simplified and improved bar configuration
[geeqie.git] / src / layout.c
1 /*
2  * Geeqie
3  * (C) 2006 John Ellis
4  * Copyright (C) 2008 - 2009 The Geeqie Team
5  *
6  * Author: John Ellis
7  *
8  * This software is released under the GNU General Public License (GNU GPL).
9  * Please read the included file COPYING for more information.
10  * This software comes with no warranty of any kind, use at your own risk!
11  */
12
13 #include "main.h"
14 #include "layout.h"
15
16 #include "color-man.h"
17 #include "filedata.h"
18 #include "histogram.h"
19 #include "image.h"
20 #include "image-overlay.h"
21 #include "layout_config.h"
22 #include "layout_image.h"
23 #include "layout_util.h"
24 #include "menu.h"
25 #include "pixbuf-renderer.h"
26 #include "pixbuf_util.h"
27 #include "utilops.h"
28 #include "view_dir.h"
29 #include "view_file.h"
30 #include "ui_fileops.h"
31 #include "ui_menu.h"
32 #include "ui_misc.h"
33 #include "ui_tabcomp.h"
34 #include "window.h"
35 #include "metadata.h"
36 #include "rcfile.h"
37 #include "bar.h"
38
39 #ifdef HAVE_LIRC
40 #include "lirc.h"
41 #endif
42
43 #define MAINWINDOW_DEF_WIDTH 700
44 #define MAINWINDOW_DEF_HEIGHT 500
45
46 #define MAIN_WINDOW_DIV_HPOS (MAINWINDOW_DEF_WIDTH / 2)
47 #define MAIN_WINDOW_DIV_VPOS (MAINWINDOW_DEF_HEIGHT / 2)
48
49 #define TOOLWINDOW_DEF_WIDTH 260
50 #define TOOLWINDOW_DEF_HEIGHT 450
51
52 #define PROGRESS_WIDTH 150
53 #define ZOOM_LABEL_WIDTH 64
54
55 #define PANE_DIVIDER_SIZE 10
56
57
58 GList *layout_window_list = NULL;
59
60
61 static void layout_list_scroll_to_subpart(LayoutWindow *lw, const gchar *needle);
62
63
64 /*
65  *-----------------------------------------------------------------------------
66  * misc
67  *-----------------------------------------------------------------------------
68  */
69
70 gint layout_valid(LayoutWindow **lw)
71 {
72         if (*lw == NULL)
73                 {
74                 if (layout_window_list) *lw = layout_window_list->data;
75                 return (*lw != NULL);
76                 }
77
78         return (g_list_find(layout_window_list, *lw) != NULL);
79 }
80
81 LayoutWindow *layout_find_by_image(ImageWindow *imd)
82 {
83         GList *work;
84
85         work = layout_window_list;
86         while (work)
87                 {
88                 LayoutWindow *lw = work->data;
89                 work = work->next;
90
91                 if (lw->image == imd) return lw;
92                 }
93
94         return NULL;
95 }
96
97 LayoutWindow *layout_find_by_image_fd(ImageWindow *imd)
98 {
99         GList *work;
100
101         work = layout_window_list;
102         while (work)
103                 {
104                 LayoutWindow *lw = work->data;
105                 work = work->next;
106                 if (lw->image->image_fd == imd->image_fd)
107                         return lw;
108
109                 }
110
111         return NULL;
112 }
113
114 /*
115  *-----------------------------------------------------------------------------
116  * menu, toolbar, and dir view
117  *-----------------------------------------------------------------------------
118  */
119
120 static void layout_path_entry_changed_cb(GtkWidget *widget, gpointer data)
121 {
122         LayoutWindow *lw = data;
123         gchar *buf;
124
125         if (gtk_combo_box_get_active(GTK_COMBO_BOX(widget)) < 0) return;
126
127         buf = g_strdup(gtk_entry_get_text(GTK_ENTRY(lw->path_entry)));
128         if (!buf || (lw->dir_fd && strcmp(buf, lw->dir_fd->path) == 0))
129                 {
130                 g_free(buf);
131                 return;
132                 }
133
134         layout_set_path(lw, buf);
135
136         g_free(buf);
137 }
138
139 static void layout_path_entry_tab_cb(const gchar *path, gpointer data)
140 {
141         LayoutWindow *lw = data;
142         gchar *buf;
143         gchar *base;
144
145         buf = g_strdup(path);
146         parse_out_relatives(buf);
147         base = remove_level_from_path(buf);
148
149         if (isdir(buf))
150                 {
151                 if ((!lw->dir_fd || strcmp(lw->dir_fd->path, buf) != 0) && layout_set_path(lw, buf))
152                         {
153                         gint pos = -1;
154                         /* put the G_DIR_SEPARATOR back, if we are in tab completion for a dir and result was path change */
155                         gtk_editable_insert_text(GTK_EDITABLE(lw->path_entry), G_DIR_SEPARATOR_S, -1, &pos);
156                         gtk_editable_set_position(GTK_EDITABLE(lw->path_entry),
157                                                   strlen(gtk_entry_get_text(GTK_ENTRY(lw->path_entry))));
158                         }
159                 }
160         else if (lw->dir_fd && strcmp(lw->dir_fd->path, base) == 0)
161                 {
162                 layout_list_scroll_to_subpart(lw, filename_from_path(buf));
163                 }
164
165         g_free(base);
166         g_free(buf);
167 }
168
169 static void layout_path_entry_cb(const gchar *path, gpointer data)
170 {
171         LayoutWindow *lw = data;
172         gchar *buf;
173
174         buf = g_strdup(path);
175         parse_out_relatives(buf);
176
177         layout_set_path(lw, buf);
178
179         g_free(buf);
180 }
181
182 static void layout_vd_select_cb(ViewDir *vd, const gchar *path, gpointer data)
183 {
184         LayoutWindow *lw = data;
185
186         layout_set_path(lw, path);
187 }
188
189 static void layout_path_entry_tab_append_cb(const gchar *path, gpointer data, gint n)
190 {
191         LayoutWindow *lw = data;
192
193         if (!lw || !lw->back_button) return;
194         if (!layout_valid(&lw)) return;
195
196         if (n >= 2)
197                 {
198                 /* Enable back button */
199                 gtk_widget_set_sensitive(lw->back_button, TRUE);
200                 }
201         else
202                 {
203                 /* Disable back button */
204                 gtk_widget_set_sensitive(lw->back_button, FALSE);
205                 }
206 }
207
208 static GtkWidget *layout_tool_setup(LayoutWindow *lw)
209 {
210         GtkWidget *box;
211         GtkWidget *menu_bar;
212         GtkWidget *tabcomp;
213
214         box = gtk_vbox_new(FALSE, 0);
215
216         menu_bar = layout_actions_menu_bar(lw);
217         gtk_box_pack_start(GTK_BOX(box), menu_bar, FALSE, FALSE, 0);
218         gtk_widget_show(menu_bar);
219
220         lw->toolbar = layout_button_bar(lw);
221         gtk_box_pack_start(GTK_BOX(box), lw->toolbar, FALSE, FALSE, 0);
222         if (!lw->options.toolbar_hidden) gtk_widget_show(lw->toolbar);
223
224         tabcomp = tab_completion_new_with_history(&lw->path_entry, NULL, "path_list", -1,
225                                                   layout_path_entry_cb, lw);
226         tab_completion_add_tab_func(lw->path_entry, layout_path_entry_tab_cb, lw);
227         tab_completion_add_append_func(lw->path_entry, layout_path_entry_tab_append_cb, lw);
228         gtk_box_pack_start(GTK_BOX(box), tabcomp, FALSE, FALSE, 0);
229         gtk_widget_show(tabcomp);
230
231         g_signal_connect(G_OBJECT(lw->path_entry->parent), "changed",
232                          G_CALLBACK(layout_path_entry_changed_cb), lw);
233
234         lw->vd = vd_new(lw->options.dir_view_type, lw->dir_fd);
235         vd_set_layout(lw->vd, lw);
236         vd_set_select_func(lw->vd, layout_vd_select_cb, lw);
237
238         lw->dir_view = lw->vd->widget;
239
240         gtk_box_pack_start(GTK_BOX(box), lw->dir_view, TRUE, TRUE, 0);
241         gtk_widget_show(lw->dir_view);
242
243         gtk_widget_show(box);
244
245         return box;
246 }
247
248 /*
249  *-----------------------------------------------------------------------------
250  * sort button (and menu)
251  *-----------------------------------------------------------------------------
252  */
253
254 static void layout_sort_menu_cb(GtkWidget *widget, gpointer data)
255 {
256         LayoutWindow *lw;
257         SortType type;
258
259         if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) return;
260
261         lw = submenu_item_get_data(widget);
262         if (!lw) return;
263
264         type = (SortType)GPOINTER_TO_INT(data);
265
266         layout_sort_set(lw, type, lw->sort_ascend);
267 }
268
269 static void layout_sort_menu_ascend_cb(GtkWidget *widget, gpointer data)
270 {
271         LayoutWindow *lw = data;
272
273         layout_sort_set(lw, lw->sort_method, !lw->sort_ascend);
274 }
275
276 static void layout_sort_menu_hide_cb(GtkWidget *widget, gpointer data)
277 {
278         /* destroy the menu */
279 #if GTK_CHECK_VERSION(2,12,0)
280         g_object_unref(widget);
281 #else
282         gtk_widget_unref(GTK_WIDGET(widget));
283 #endif
284 }
285
286 static void layout_sort_button_press_cb(GtkWidget *widget, gpointer data)
287 {
288         LayoutWindow *lw = data;
289         GtkWidget *menu;
290         GdkEvent *event;
291         guint32 etime;
292
293         menu = submenu_add_sort(NULL, G_CALLBACK(layout_sort_menu_cb), lw, FALSE, FALSE, TRUE, lw->sort_method);
294
295         /* take ownership of menu */
296 #ifdef GTK_OBJECT_FLOATING
297         /* GTK+ < 2.10 */
298         g_object_ref(G_OBJECT(menu));
299         gtk_object_sink(GTK_OBJECT(menu));
300 #else
301         /* GTK+ >= 2.10 */
302         g_object_ref_sink(G_OBJECT(menu));
303 #endif
304
305         /* ascending option */
306         menu_item_add_divider(menu);
307         menu_item_add_check(menu, _("Ascending"), lw->sort_ascend, G_CALLBACK(layout_sort_menu_ascend_cb), lw);
308
309         g_signal_connect(G_OBJECT(menu), "selection_done",
310                          G_CALLBACK(layout_sort_menu_hide_cb), NULL);
311
312         event = gtk_get_current_event();
313         if (event)
314                 {
315                 etime = gdk_event_get_time(event);
316                 gdk_event_free(event);
317                 }
318         else
319                 {
320                 etime = 0;
321                 }
322
323         gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, etime);
324 }
325
326 static GtkWidget *layout_sort_button(LayoutWindow *lw)
327 {
328         GtkWidget *button;
329
330         button = gtk_button_new_with_label(sort_type_get_text(lw->sort_method));
331         g_signal_connect(G_OBJECT(button), "clicked",
332                          G_CALLBACK(layout_sort_button_press_cb), lw);
333         gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
334
335         return button;
336 }
337
338 /*
339  *-----------------------------------------------------------------------------
340  * color profile button (and menu)
341  *-----------------------------------------------------------------------------
342  */
343
344 #ifdef HAVE_LCMS
345
346 static void layout_color_menu_enable_cb(GtkWidget *widget, gpointer data)
347 {
348         LayoutWindow *lw = data;
349
350         layout_image_color_profile_set_use(lw, (!layout_image_color_profile_get_use(lw)));
351         layout_image_refresh(lw);
352 }
353
354 static void layout_color_menu_use_image_cb(GtkWidget *widget, gpointer data)
355 {
356         LayoutWindow *lw = data;
357         gint input, screen, use_image;
358
359         if (!layout_image_color_profile_get(lw, &input, &screen, &use_image)) return;
360         layout_image_color_profile_set(lw, input, screen, !use_image);
361         layout_image_refresh(lw);
362 }
363
364 #define COLOR_MENU_KEY "color_menu_key"
365
366 static void layout_color_menu_input_cb(GtkWidget *widget, gpointer data)
367 {
368         LayoutWindow *lw = data;
369         gint type;
370         gint input, screen, use_image;
371
372         if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) return;
373
374         type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), COLOR_MENU_KEY));
375         if (type < 0 || type >= COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS) return;
376
377         if (!layout_image_color_profile_get(lw, &input, &screen, &use_image)) return;
378         if (type == input) return;
379
380         layout_image_color_profile_set(lw, type, screen, use_image);
381         layout_image_refresh(lw);
382 }
383
384 static void layout_color_menu_screen_cb(GtkWidget *widget, gpointer data)
385 {
386         LayoutWindow *lw = data;
387         gint type;
388         gint input, screen, use_image;
389
390         if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) return;
391
392         type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), COLOR_MENU_KEY));
393         if (type < 0 || type > 1) return;
394
395         if (!layout_image_color_profile_get(lw, &input, &screen, &use_image)) return;
396         if (type == screen) return;
397
398         layout_image_color_profile_set(lw, input, type, use_image);
399         layout_image_refresh(lw);
400 }
401
402 static gchar *layout_color_name_parse(const gchar *name)
403 {
404         if (!name) return g_strdup(_("Empty"));
405         return g_strdelimit(g_strdup(name), "_", '-');
406 }
407
408 #endif /* HAVE_LCMS */
409
410 static void layout_color_button_press_cb(GtkWidget *widget, gpointer data)
411 {
412 #ifndef HAVE_LCMS
413         gchar *msg = g_strdup_printf(_("This installation of %s was not built with support for color profiles."), GQ_APPNAME);
414         file_util_warning_dialog(_("Color profiles not supported"),
415                                  msg,
416                                  GTK_STOCK_DIALOG_INFO, widget);
417         g_free(msg);
418         return;
419 #else
420         LayoutWindow *lw = data;
421         GtkWidget *menu;
422         GtkWidget *item;
423         gchar *buf;
424         gint active;
425         gint input = 0;
426         gint screen = 0;
427         gint use_image = 0;
428         gint from_image = 0;
429         gint i;
430         
431         if (!layout_image_color_profile_get(lw, &input, &screen, &use_image)) return;
432
433         from_image = use_image && (layout_image_color_profile_get_from_image(lw) != COLOR_PROFILE_NONE);
434         menu = popup_menu_short_lived();
435
436         active = layout_image_color_profile_get_use(lw);
437         menu_item_add_check(menu, _("Use _color profiles"), active,
438                             G_CALLBACK(layout_color_menu_enable_cb), lw);
439
440         menu_item_add_divider(menu);
441
442         item = menu_item_add_check(menu, _("Use profile from _image"), use_image,
443                             G_CALLBACK(layout_color_menu_use_image_cb), lw);
444         gtk_widget_set_sensitive(item, active);
445
446         for (i = COLOR_PROFILE_SRGB; i < COLOR_PROFILE_FILE; i++)
447                 {
448                 const gchar *label;
449
450                 switch (i)
451                         {
452                         case COLOR_PROFILE_SRGB:        label = _("sRGB"); break;
453                         case COLOR_PROFILE_ADOBERGB:    label = _("AdobeRGB compatible"); break;
454                         default:                        label = "fixme"; break;
455                         }
456                 buf = g_strdup_printf(_("Input _%d: %s"), i, label);
457                 item = menu_item_add_radio(menu, (i == COLOR_PROFILE_SRGB) ? NULL : item,
458                                    buf, (input == i),
459                                    G_CALLBACK(layout_color_menu_input_cb), lw);
460                 g_free(buf);
461                 g_object_set_data(G_OBJECT(item), COLOR_MENU_KEY, GINT_TO_POINTER(i));
462                 gtk_widget_set_sensitive(item, active && !from_image);
463                 }
464
465         for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
466                 {
467                 const gchar *name;
468                 gchar *end;
469
470                 name = options->color_profile.input_name[i];
471                 if (!name) name = filename_from_path(options->color_profile.input_file[i]);
472
473                 end = layout_color_name_parse(name);
474                 buf = g_strdup_printf(_("Input _%d: %s"), i + COLOR_PROFILE_FILE, end);
475                 g_free(end);
476
477                 item = menu_item_add_radio(menu, item,
478                                            buf, (i + COLOR_PROFILE_FILE == input),
479                                            G_CALLBACK(layout_color_menu_input_cb), lw);
480                 g_free(buf);
481                 g_object_set_data(G_OBJECT(item), COLOR_MENU_KEY, GINT_TO_POINTER(i + COLOR_PROFILE_FILE));
482                 gtk_widget_set_sensitive(item, active && options->color_profile.input_file[i] && !from_image);
483                 }
484
485         menu_item_add_divider(menu);
486
487         item = menu_item_add_radio(menu, NULL,
488                                    _("Screen sRGB"), (screen == 0),
489                                    G_CALLBACK(layout_color_menu_screen_cb), lw);
490
491         g_object_set_data(G_OBJECT(item), COLOR_MENU_KEY, GINT_TO_POINTER(0));
492         gtk_widget_set_sensitive(item, active);
493
494         item = menu_item_add_radio(menu, item,
495                                    _("_Screen profile"), (screen == 1),
496                                    G_CALLBACK(layout_color_menu_screen_cb), lw);
497         g_object_set_data(G_OBJECT(item), COLOR_MENU_KEY, GINT_TO_POINTER(1));
498         gtk_widget_set_sensitive(item, active && options->color_profile.screen_file);
499
500         gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME);
501 #endif /* HAVE_LCMS */
502 }
503
504 static GtkWidget *layout_color_button(LayoutWindow *lw)
505 {
506         GtkWidget *button;
507         GtkWidget *image;
508         gint enable;
509
510         button = gtk_button_new();
511         image = gtk_image_new_from_stock(GTK_STOCK_SELECT_COLOR, GTK_ICON_SIZE_MENU);
512         gtk_container_add(GTK_CONTAINER(button), image);
513         gtk_widget_show(image);
514         g_signal_connect(G_OBJECT(button), "clicked",
515                          G_CALLBACK(layout_color_button_press_cb), lw);
516         gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
517
518 #ifdef HAVE_LCMS
519         enable = (lw->image) ? lw->image->color_profile_enable : FALSE;
520 #else
521         enable = FALSE;
522 #endif
523         gtk_widget_set_sensitive(image, enable);
524
525         return button;
526 }
527
528 /*
529  *-----------------------------------------------------------------------------
530  * write button
531  *-----------------------------------------------------------------------------
532  */
533
534 static void layout_write_button_press_cb(GtkWidget *widget, gpointer data)
535 {
536         metadata_write_queue_confirm(NULL, NULL);
537 }
538
539 static GtkWidget *layout_write_button(LayoutWindow *lw)
540 {
541         GtkWidget *button;
542         GtkWidget *image;
543
544         button = gtk_button_new();
545         image = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU);
546         gtk_container_add(GTK_CONTAINER(button), image);
547         gtk_widget_show(image);
548         g_signal_connect(G_OBJECT(button), "clicked",
549                          G_CALLBACK(layout_write_button_press_cb), lw);
550         gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
551         
552         gtk_widget_set_sensitive(button, metadata_queue_length() > 0);
553         
554         return button;
555 }
556
557
558 /*
559  *-----------------------------------------------------------------------------
560  * status bar
561  *-----------------------------------------------------------------------------
562  */
563
564 void layout_status_update_write(LayoutWindow *lw)
565 {
566         if (!layout_valid(&lw)) return;
567         if (!lw->info_write) return;
568
569         gtk_widget_set_sensitive(lw->info_write, metadata_queue_length() > 0);
570         /* FIXME: maybe show also the number of files */
571 }
572
573 void layout_status_update_write_all(void)
574 {
575         GList *work;
576
577         work = layout_window_list;
578         while (work)
579                 {
580                 LayoutWindow *lw = work->data;
581                 work = work->next;
582
583                 layout_status_update_write(lw);
584                 }
585 }
586
587
588 void layout_status_update_progress(LayoutWindow *lw, gdouble val, const gchar *text)
589 {
590         if (!layout_valid(&lw)) return;
591         if (!lw->info_progress_bar) return;
592
593         gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(lw->info_progress_bar), val);
594         gtk_progress_bar_set_text(GTK_PROGRESS_BAR(lw->info_progress_bar), (text) ? text : " ");
595 }
596
597 void layout_status_update_info(LayoutWindow *lw, const gchar *text)
598 {
599         gchar *buf = NULL;
600
601         if (!layout_valid(&lw)) return;
602
603         if (!text)
604                 {
605                 guint n;
606                 gint64 n_bytes = 0;
607         
608                 n = layout_list_count(lw, &n_bytes);
609                 
610                 if (n)
611                         {
612                         guint s;
613                         gint64 s_bytes = 0;
614                         const gchar *ss;
615
616                         if (layout_image_slideshow_active(lw))
617                                 {
618                                 if (!layout_image_slideshow_paused(lw))
619                                         {
620                                         ss = _(" Slideshow");
621                                         }
622                                 else
623                                         {
624                                         ss = _(" Paused");
625                                         }
626                                 }
627                         else
628                                 {
629                                 ss = "";
630                                 }
631         
632                         s = layout_selection_count(lw, &s_bytes);
633         
634                         layout_bars_new_selection(lw, s);
635         
636                         if (s > 0)
637                                 {
638                                 gchar *b = text_from_size_abrev(n_bytes);
639                                 gchar *sb = text_from_size_abrev(s_bytes);
640                                 buf = g_strdup_printf(_("%s, %d files (%s, %d)%s"), b, n, sb, s, ss);
641                                 g_free(b);
642                                 g_free(sb);
643                                 }
644                         else if (n > 0)
645                                 {
646                                 gchar *b = text_from_size_abrev(n_bytes);
647                                 buf = g_strdup_printf(_("%s, %d files%s"), b, n, ss);
648                                 g_free(b);
649                                 }
650                         else
651                                 {
652                                 buf = g_strdup_printf(_("%d files%s"), n, ss);
653                                 }
654         
655                         text = buf;
656         
657                         image_osd_update(lw->image);
658                         }
659                 else
660                         {
661                         text = "";
662                         }
663         }
664         
665         if (lw->info_status) gtk_label_set_text(GTK_LABEL(lw->info_status), text);
666         g_free(buf);
667 }
668
669 void layout_status_update_image(LayoutWindow *lw)
670 {
671         guint64 n;
672
673         if (!layout_valid(&lw) || !lw->image) return;
674
675         n = layout_list_count(lw, NULL);
676         
677         if (!n)
678                 {
679                 gtk_label_set_text(GTK_LABEL(lw->info_zoom), "");
680                 gtk_label_set_text(GTK_LABEL(lw->info_details), "");
681                 }
682         else
683                 {
684                 gchar *text;
685                 gchar *b;
686
687                 text = image_zoom_get_as_text(lw->image);
688                 gtk_label_set_text(GTK_LABEL(lw->info_zoom), text);
689                 g_free(text);
690
691                 b = image_get_fd(lw->image) ? text_from_size(image_get_fd(lw->image)->size) : g_strdup("0");
692
693                 if (lw->image->unknown)
694                         {
695                         if (image_get_path(lw->image) && !access_file(image_get_path(lw->image), R_OK))
696                                 {
697                                 text = g_strdup_printf(_("(no read permission) %s bytes"), b);
698                                 }
699                         else
700                                 {
701                                 text = g_strdup_printf(_("( ? x ? ) %s bytes"), b);
702                                 }
703                         }
704                 else
705                         {
706                         gint width, height;
707         
708                         image_get_image_size(lw->image, &width, &height);
709                         text = g_strdup_printf(_("( %d x %d ) %s bytes"),
710                                                width, height, b);
711                         }
712
713                 g_free(b);
714                 
715                 gtk_label_set_text(GTK_LABEL(lw->info_details), text);
716                 g_free(text);
717                 }
718 }
719
720 void layout_status_update_all(LayoutWindow *lw)
721 {
722         layout_status_update_progress(lw, 0.0, NULL);
723         layout_status_update_info(lw, NULL);
724         layout_status_update_image(lw);
725         layout_status_update_write(lw);
726 }
727
728 static GtkWidget *layout_status_label(gchar *text, GtkWidget *box, gint start, gint size, gint expand)
729 {
730         GtkWidget *label;
731         GtkWidget *frame;
732
733         frame = gtk_frame_new(NULL);
734         if (size) gtk_widget_set_size_request(frame, size, -1);
735         gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
736         if (start)
737                 {
738                 gtk_box_pack_start(GTK_BOX(box), frame, expand, expand, 0);
739                 }
740         else
741                 {
742                 gtk_box_pack_end(GTK_BOX(box), frame, expand, expand, 0);
743                 }
744         gtk_widget_show(frame);
745
746         label = gtk_label_new(text ? text : "");
747         gtk_container_add(GTK_CONTAINER(frame), label);
748         gtk_widget_show(label);
749
750         return label;
751 }
752
753 static void layout_status_setup(LayoutWindow *lw, GtkWidget *box, gint small_format)
754 {
755         GtkWidget *hbox;
756
757         if (lw->info_box) return;
758
759         if (small_format)
760                 {
761                 lw->info_box = gtk_vbox_new(FALSE, 0);
762                 }
763         else
764                 {
765                 lw->info_box = gtk_hbox_new(FALSE, 0);
766                 }
767         gtk_box_pack_end(GTK_BOX(box), lw->info_box, FALSE, FALSE, 0);
768         gtk_widget_show(lw->info_box);
769
770         if (small_format)
771                 {
772                 hbox = gtk_hbox_new(FALSE, 0);
773                 gtk_box_pack_start(GTK_BOX(lw->info_box), hbox, FALSE, FALSE, 0);
774                 gtk_widget_show(hbox);
775                 }
776         else
777                 {
778                 hbox = lw->info_box;
779                 }
780         lw->info_progress_bar = gtk_progress_bar_new();
781         gtk_widget_set_size_request(lw->info_progress_bar, PROGRESS_WIDTH, -1);
782         gtk_box_pack_start(GTK_BOX(hbox), lw->info_progress_bar, FALSE, FALSE, 0);
783         gtk_widget_show(lw->info_progress_bar);
784
785         lw->info_sort = layout_sort_button(lw);
786         gtk_box_pack_start(GTK_BOX(hbox), lw->info_sort, FALSE, FALSE, 0);
787         gtk_widget_show(lw->info_sort);
788
789         lw->info_color = layout_color_button(lw);
790         gtk_widget_show(lw->info_color);
791
792         lw->info_write = layout_write_button(lw);
793         gtk_widget_show(lw->info_write);
794
795         if (small_format) gtk_box_pack_end(GTK_BOX(hbox), lw->info_color, FALSE, FALSE, 0);
796         if (small_format) gtk_box_pack_end(GTK_BOX(hbox), lw->info_write, FALSE, FALSE, 0);
797
798         lw->info_status = layout_status_label(NULL, lw->info_box, TRUE, 0, (!small_format));
799
800         if (small_format)
801                 {
802                 hbox = gtk_hbox_new(FALSE, 0);
803                 gtk_box_pack_start(GTK_BOX(lw->info_box), hbox, FALSE, FALSE, 0);
804                 gtk_widget_show(hbox);
805                 }
806         else
807                 {
808                 hbox = lw->info_box;
809                 }
810         lw->info_details = layout_status_label(NULL, hbox, TRUE, 0, TRUE);
811         if (!small_format) gtk_box_pack_start(GTK_BOX(hbox), lw->info_color, FALSE, FALSE, 0);
812         if (!small_format) gtk_box_pack_start(GTK_BOX(hbox), lw->info_write, FALSE, FALSE, 0);
813         lw->info_zoom = layout_status_label(NULL, hbox, FALSE, ZOOM_LABEL_WIDTH, FALSE);
814 }
815
816 /*
817  *-----------------------------------------------------------------------------
818  * views
819  *-----------------------------------------------------------------------------
820  */
821
822 static GtkWidget *layout_tools_new(LayoutWindow *lw)
823 {
824         lw->dir_view = layout_tool_setup(lw);
825         return lw->dir_view;
826 }
827
828 static void layout_list_status_cb(ViewFile *vf, gpointer data)
829 {
830         LayoutWindow *lw = data;
831
832         layout_status_update_info(lw, NULL);
833 }
834
835 static void layout_list_thumb_cb(ViewFile *vf, gdouble val, const gchar *text, gpointer data)
836 {
837         LayoutWindow *lw = data;
838
839         layout_status_update_progress(lw, val, text);
840 }
841
842 static GtkWidget *layout_list_new(LayoutWindow *lw)
843 {
844         lw->vf = vf_new(lw->file_view_type, NULL);
845         vf_set_layout(lw->vf, lw);
846
847         vf_set_status_func(lw->vf, layout_list_status_cb, lw);
848         vf_set_thumb_status_func(lw->vf, layout_list_thumb_cb, lw);
849
850         vf_marks_set(lw->vf, lw->options.show_marks);
851
852         switch (lw->file_view_type)
853         {
854         case FILEVIEW_ICON:
855                 break;
856         case FILEVIEW_LIST:
857                 vf_thumb_set(lw->vf, lw->options.show_thumbnails);
858                 break;
859         }
860
861         return lw->vf->widget;
862 }
863
864 static void layout_list_sync_thumb(LayoutWindow *lw)
865 {
866         if (lw->vf) vf_thumb_set(lw->vf, lw->options.show_thumbnails);
867 }
868
869 static void layout_list_sync_marks(LayoutWindow *lw)
870 {
871         if (lw->vf) vf_marks_set(lw->vf, lw->options.show_marks);
872 }
873
874 static void layout_list_scroll_to_subpart(LayoutWindow *lw, const gchar *needle)
875 {
876         if (!lw) return;
877 #if 0
878         if (lw->vf) vf_scroll_to_subpart(lw->vf, needle);
879 #endif
880 }
881
882 GList *layout_list(LayoutWindow *lw)
883 {
884         if (!layout_valid(&lw)) return NULL;
885
886         if (lw->vf) return vf_get_list(lw->vf);
887
888         return NULL;
889 }
890
891 guint layout_list_count(LayoutWindow *lw, gint64 *bytes)
892 {
893         if (!layout_valid(&lw)) return 0;
894
895         if (lw->vf) return vf_count(lw->vf, bytes);
896
897         return 0;
898 }
899
900 FileData *layout_list_get_fd(LayoutWindow *lw, gint index)
901 {
902         if (!layout_valid(&lw)) return NULL;
903
904         if (lw->vf) return vf_index_get_data(lw->vf, index);
905
906         return NULL;
907 }
908
909 gint layout_list_get_index(LayoutWindow *lw, FileData *fd)
910 {
911         if (!layout_valid(&lw) || !fd) return -1;
912
913         if (lw->vf) return vf_index_by_path(lw->vf, fd->path);
914
915         return -1;
916 }
917
918 void layout_list_sync_fd(LayoutWindow *lw, FileData *fd)
919 {
920         if (!layout_valid(&lw)) return;
921
922         if (lw->vf) vf_select_by_fd(lw->vf, fd);
923 }
924
925 static void layout_list_sync_sort(LayoutWindow *lw)
926 {
927         if (!layout_valid(&lw)) return;
928
929         if (lw->vf) vf_sort_set(lw->vf, lw->sort_method, lw->sort_ascend);
930 }
931
932 GList *layout_selection_list(LayoutWindow *lw)
933 {
934         if (!layout_valid(&lw)) return NULL;
935
936         if (layout_image_get_collection(lw, NULL))
937                 {
938                 FileData *fd;
939
940                 fd = layout_image_get_fd(lw);
941                 if (fd) return g_list_append(NULL, file_data_ref(fd));
942                 return NULL;
943                 }
944
945         if (lw->vf) return vf_selection_get_list(lw->vf);
946
947         return NULL;
948 }
949
950 GList *layout_selection_list_by_index(LayoutWindow *lw)
951 {
952         if (!layout_valid(&lw)) return NULL;
953
954         if (lw->vf) return vf_selection_get_list_by_index(lw->vf);
955
956         return NULL;
957 }
958
959 guint layout_selection_count(LayoutWindow *lw, gint64 *bytes)
960 {
961         if (!layout_valid(&lw)) return 0;
962
963         if (lw->vf) return vf_selection_count(lw->vf, bytes);
964
965         return 0;
966 }
967
968 void layout_select_all(LayoutWindow *lw)
969 {
970         if (!layout_valid(&lw)) return;
971
972         if (lw->vf) vf_select_all(lw->vf);
973 }
974
975 void layout_select_none(LayoutWindow *lw)
976 {
977         if (!layout_valid(&lw)) return;
978
979         if (lw->vf) vf_select_none(lw->vf);
980 }
981
982 void layout_select_invert(LayoutWindow *lw)
983 {
984         if (!layout_valid(&lw)) return;
985
986         if (lw->vf) vf_select_invert(lw->vf);
987 }
988
989 void layout_mark_to_selection(LayoutWindow *lw, gint mark, MarkToSelectionMode mode)
990 {
991         if (!layout_valid(&lw)) return;
992
993         if (lw->vf) vf_mark_to_selection(lw->vf, mark, mode);
994 }
995
996 void layout_selection_to_mark(LayoutWindow *lw, gint mark, SelectionToMarkMode mode)
997 {
998         if (!layout_valid(&lw)) return;
999
1000         if (lw->vf) vf_selection_to_mark(lw->vf, mark, mode);
1001
1002         layout_status_update_info(lw, NULL); /* osd in fullscreen mode */
1003 }
1004
1005 /*
1006  *-----------------------------------------------------------------------------
1007  * access
1008  *-----------------------------------------------------------------------------
1009  */
1010
1011 const gchar *layout_get_path(LayoutWindow *lw)
1012 {
1013         if (!layout_valid(&lw)) return NULL;
1014         return lw->dir_fd ? lw->dir_fd->path : NULL;
1015 }
1016
1017 static void layout_sync_path(LayoutWindow *lw)
1018 {
1019         if (!lw->dir_fd) return;
1020
1021         if (lw->path_entry) gtk_entry_set_text(GTK_ENTRY(lw->path_entry), lw->dir_fd->path);
1022         if (lw->vd) vd_set_fd(lw->vd, lw->dir_fd);
1023
1024         if (lw->vf) vf_set_fd(lw->vf, lw->dir_fd);
1025 }
1026
1027 gint layout_set_path(LayoutWindow *lw, const gchar *path)
1028 {
1029         FileData *fd;
1030         if (!path) return FALSE;
1031         fd = file_data_new_simple(path);
1032         gint ret = layout_set_fd(lw, fd);
1033         file_data_unref(fd);
1034         return ret;
1035 }
1036
1037
1038 gint layout_set_fd(LayoutWindow *lw, FileData *fd)
1039 {
1040         gint have_file = FALSE;
1041
1042         if (!layout_valid(&lw)) return FALSE;
1043
1044         if (!fd || !isname(fd->path)) return FALSE;
1045         if (lw->dir_fd && fd == lw->dir_fd)
1046                 {
1047                 return TRUE;
1048                 }
1049
1050         if (isdir(fd->path))
1051                 {
1052                 if (lw->dir_fd)
1053                         {
1054                         file_data_unregister_real_time_monitor(lw->dir_fd);
1055                         file_data_unref(lw->dir_fd);
1056                         }
1057                 lw->dir_fd = file_data_ref(fd);
1058                 file_data_register_real_time_monitor(fd);
1059                 }
1060         else
1061                 {
1062                 gchar *base;
1063
1064                 base = remove_level_from_path(fd->path);
1065                 if (lw->dir_fd && strcmp(lw->dir_fd->path, base) == 0)
1066                         {
1067                         g_free(base);
1068                         }
1069                 else if (isdir(base))
1070                         {
1071                         if (lw->dir_fd)
1072                                 {
1073                                 file_data_unregister_real_time_monitor(lw->dir_fd);
1074                                 file_data_unref(lw->dir_fd);
1075                                 }
1076                         lw->dir_fd = file_data_new_simple(base);
1077                         file_data_register_real_time_monitor(lw->dir_fd);
1078                         g_free(base);
1079                         }
1080                 else
1081                         {
1082                         g_free(base);
1083                         return FALSE;
1084                         }
1085                 if (isfile(fd->path)) have_file = TRUE;
1086                 }
1087
1088         if (lw->path_entry) tab_completion_append_to_history(lw->path_entry, lw->dir_fd->path);
1089         layout_sync_path(lw);
1090         layout_list_sync_sort(lw);
1091         
1092         if (have_file)
1093                 {
1094                 gint row;
1095
1096                 row = layout_list_get_index(lw, fd);
1097                 if (row >= 0)
1098                         {
1099                         layout_image_set_index(lw, row);
1100                         }
1101                 else
1102                         {
1103                         layout_image_set_fd(lw, fd);
1104                         }
1105                 }
1106         else if (!options->lazy_image_sync)
1107                 {
1108                 layout_image_set_index(lw, 0);
1109                 }
1110
1111         if (options->metadata.confirm_on_dir_change)
1112                 metadata_write_queue_confirm(NULL, NULL);
1113
1114         return TRUE;
1115 }
1116
1117 static void layout_refresh_lists(LayoutWindow *lw)
1118 {
1119         if (lw->vd) vd_refresh(lw->vd);
1120
1121         if (lw->vf) vf_refresh(lw->vf);
1122 }
1123
1124 void layout_refresh(LayoutWindow *lw)
1125 {
1126         if (!layout_valid(&lw)) return;
1127
1128         DEBUG_1("layout refresh");
1129
1130         layout_refresh_lists(lw);
1131
1132         if (lw->image) layout_image_refresh(lw);
1133 }
1134
1135 void layout_thumb_set(LayoutWindow *lw, gint enable)
1136 {
1137         if (!layout_valid(&lw)) return;
1138
1139         if (lw->options.show_thumbnails == enable) return;
1140
1141         lw->options.show_thumbnails = enable;
1142
1143         layout_util_sync_thumb(lw);
1144         layout_list_sync_thumb(lw);
1145 }
1146
1147 void layout_marks_set(LayoutWindow *lw, gint enable)
1148 {
1149         if (!layout_valid(&lw)) return;
1150
1151         if (lw->options.show_marks == enable) return;
1152
1153         lw->options.show_marks = enable;
1154
1155 //      layout_util_sync_marks(lw);
1156         layout_list_sync_marks(lw);
1157 }
1158
1159 gint layout_thumb_get(LayoutWindow *lw)
1160 {
1161         if (!layout_valid(&lw)) return FALSE;
1162
1163         return lw->options.show_thumbnails;
1164 }
1165
1166 gint layout_marks_get(LayoutWindow *lw)
1167 {
1168         if (!layout_valid(&lw)) return FALSE;
1169
1170         return lw->options.show_marks;
1171 }
1172
1173 void layout_sort_set(LayoutWindow *lw, SortType type, gint ascend)
1174 {
1175         if (!layout_valid(&lw)) return;
1176         if (lw->sort_method == type && lw->sort_ascend == ascend) return;
1177
1178         lw->sort_method = type;
1179         lw->sort_ascend = ascend;
1180
1181         if (lw->info_sort) gtk_label_set_text(GTK_LABEL(GTK_BIN(lw->info_sort)->child),
1182                                               sort_type_get_text(type));
1183         layout_list_sync_sort(lw);
1184 }
1185
1186 gint layout_sort_get(LayoutWindow *lw, SortType *type, gint *ascend)
1187 {
1188         if (!layout_valid(&lw)) return FALSE;
1189
1190         if (type) *type = lw->sort_method;
1191         if (ascend) *ascend = lw->sort_ascend;
1192
1193         return TRUE;
1194 }
1195
1196 gint layout_geometry_get(LayoutWindow *lw, gint *x, gint *y, gint *w, gint *h)
1197 {
1198         if (!layout_valid(&lw)) return FALSE;
1199
1200         gdk_window_get_root_origin(lw->window->window, x, y);
1201         gdk_drawable_get_size(lw->window->window, w, h);
1202
1203         return TRUE;
1204 }
1205
1206 gint layout_geometry_get_dividers(LayoutWindow *lw, gint *h, gint *v)
1207 {
1208         if (!layout_valid(&lw)) return FALSE;
1209
1210         if (lw->h_pane && GTK_PANED(lw->h_pane)->child1->allocation.x >= 0)
1211                 {
1212                 *h = GTK_PANED(lw->h_pane)->child1->allocation.width;
1213                 }
1214         else if (h != &lw->options.main_window.hdivider_pos)
1215                 {
1216                 *h = lw->options.main_window.hdivider_pos;
1217                 }
1218
1219         if (lw->v_pane && GTK_PANED(lw->v_pane)->child1->allocation.x >= 0)
1220                 {
1221                 *v = GTK_PANED(lw->v_pane)->child1->allocation.height;
1222                 }
1223         else if (v != &lw->options.main_window.vdivider_pos)
1224                 {
1225                 *v = lw->options.main_window.vdivider_pos;
1226                 }
1227
1228         return TRUE;
1229 }
1230
1231 void layout_views_set(LayoutWindow *lw, DirViewType dir_view_type, FileViewType file_view_type)
1232 {
1233         if (!layout_valid(&lw)) return;
1234
1235         if (lw->options.dir_view_type == dir_view_type && lw->file_view_type == file_view_type) return;
1236
1237         lw->options.dir_view_type = dir_view_type;
1238         lw->file_view_type = file_view_type;
1239
1240         layout_style_set(lw, -1, NULL);
1241 }
1242
1243 gint layout_views_get(LayoutWindow *lw, DirViewType *dir_view_type, FileViewType *file_view_type)
1244 {
1245         if (!layout_valid(&lw)) return FALSE;
1246
1247         *dir_view_type = lw->options.dir_view_type;
1248         *file_view_type = lw->file_view_type;
1249
1250         return TRUE;
1251 }
1252
1253 /*
1254  *-----------------------------------------------------------------------------
1255  * location utils
1256  *-----------------------------------------------------------------------------
1257  */
1258
1259 static gint layout_location_single(LayoutLocation l)
1260 {
1261         return (l == LAYOUT_LEFT ||
1262                 l == LAYOUT_RIGHT ||
1263                 l == LAYOUT_TOP ||
1264                 l == LAYOUT_BOTTOM);
1265 }
1266
1267 static gint layout_location_vertical(LayoutLocation l)
1268 {
1269         return (l & LAYOUT_TOP ||
1270                 l & LAYOUT_BOTTOM);
1271 }
1272
1273 static gint layout_location_first(LayoutLocation l)
1274 {
1275         return (l & LAYOUT_TOP ||
1276                 l & LAYOUT_LEFT);
1277 }
1278
1279 static LayoutLocation layout_grid_compass(LayoutWindow *lw)
1280 {
1281         if (layout_location_single(lw->dir_location)) return lw->dir_location;
1282         if (layout_location_single(lw->file_location)) return lw->file_location;
1283         return lw->image_location;
1284 }
1285
1286 static void layout_location_compute(LayoutLocation l1, LayoutLocation l2,
1287                                     GtkWidget *s1, GtkWidget *s2,
1288                                     GtkWidget **d1, GtkWidget **d2)
1289 {
1290         LayoutLocation l;
1291
1292         l = l1 & l2;    /* get common compass direction */
1293         l = l1 - l;     /* remove it */
1294
1295         if (layout_location_first(l))
1296                 {
1297                 *d1 = s1;
1298                 *d2 = s2;
1299                 }
1300         else
1301                 {
1302                 *d1 = s2;
1303                 *d2 = s1;
1304                 }
1305 }
1306
1307 /*
1308  *-----------------------------------------------------------------------------
1309  * tools window (for floating/hidden)
1310  *-----------------------------------------------------------------------------
1311  */
1312
1313 gint layout_geometry_get_tools(LayoutWindow *lw, gint *x, gint *y, gint *w, gint *h, gint *divider_pos)
1314 {
1315         if (!layout_valid(&lw)) return FALSE;
1316
1317         if (!lw->tools || !GTK_WIDGET_VISIBLE(lw->tools))
1318                 {
1319                 /* use the stored values (sort of breaks success return value) */
1320
1321                 *divider_pos = lw->options.float_window.vdivider_pos;
1322
1323                 return FALSE;
1324                 }
1325
1326         gdk_window_get_root_origin(lw->tools->window, x, y);
1327         gdk_drawable_get_size(lw->tools->window, w, h);
1328
1329         if (GTK_IS_VPANED(lw->tools_pane))
1330                 {
1331                 *divider_pos = GTK_PANED(lw->tools_pane)->child1->allocation.height;
1332                 }
1333         else
1334                 {
1335                 *divider_pos = GTK_PANED(lw->tools_pane)->child1->allocation.width;
1336                 }
1337
1338         return TRUE;
1339 }
1340
1341 static void layout_tools_geometry_sync(LayoutWindow *lw)
1342 {
1343         layout_geometry_get_tools(lw, &options->layout.float_window.x, &options->layout.float_window.x,
1344                                   &options->layout.float_window.w, &options->layout.float_window.h, &lw->options.float_window.vdivider_pos);
1345 }
1346
1347 static void layout_tools_hide(LayoutWindow *lw, gint hide)
1348 {
1349         if (!lw->tools) return;
1350
1351         if (hide)
1352                 {
1353                 if (GTK_WIDGET_VISIBLE(lw->tools))
1354                         {
1355                         layout_tools_geometry_sync(lw);
1356                         gtk_widget_hide(lw->tools);
1357                         }
1358                 }
1359         else
1360                 {
1361                 if (!GTK_WIDGET_VISIBLE(lw->tools))
1362                         {
1363                         gtk_widget_show(lw->tools);
1364                         if (lw->vf) vf_refresh(lw->vf);
1365                         }
1366                 }
1367
1368         lw->options.tools_hidden = hide;
1369 }
1370
1371 static gint layout_tools_delete_cb(GtkWidget *widget, GdkEventAny *event, gpointer data)
1372 {
1373         LayoutWindow *lw = data;
1374
1375         layout_tools_float_toggle(lw);
1376
1377         return TRUE;
1378 }
1379
1380 static void layout_tools_setup(LayoutWindow *lw, GtkWidget *tools, GtkWidget *files)
1381 {
1382         GtkWidget *vbox;
1383         GtkWidget *w1, *w2;
1384         gint vertical;
1385         gint new_window = FALSE;
1386
1387         vertical = (layout_location_single(lw->image_location) && !layout_location_vertical(lw->image_location)) ||
1388                    (!layout_location_single(lw->image_location) && layout_location_vertical(layout_grid_compass(lw)));
1389 #if 0
1390         layout_location_compute(lw->dir_location, lw->file_location,
1391                                 tools, files, &w1, &w2);
1392 #endif
1393         /* for now, tools/dir are always first in order */
1394         w1 = tools;
1395         w2 = files;
1396
1397         if (!lw->tools)
1398                 {
1399                 GdkGeometry geometry;
1400                 GdkWindowHints hints;
1401
1402                 lw->tools = window_new(GTK_WINDOW_TOPLEVEL, "tools", PIXBUF_INLINE_ICON_TOOLS, NULL, _("Tools"));
1403                 g_signal_connect(G_OBJECT(lw->tools), "delete_event",
1404                                  G_CALLBACK(layout_tools_delete_cb), lw);
1405                 layout_keyboard_init(lw, lw->tools);
1406
1407                 if (options->layout.save_window_positions)
1408                         {
1409                         hints = GDK_HINT_USER_POS;
1410                         }
1411                 else
1412                         {
1413                         hints = 0;
1414                         }
1415
1416                 geometry.min_width = DEFAULT_MINIMAL_WINDOW_SIZE;
1417                 geometry.min_height = DEFAULT_MINIMAL_WINDOW_SIZE;
1418                 geometry.base_width = TOOLWINDOW_DEF_WIDTH;
1419                 geometry.base_height = TOOLWINDOW_DEF_HEIGHT;
1420                 gtk_window_set_geometry_hints(GTK_WINDOW(lw->tools), NULL, &geometry,
1421                                               GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | hints);
1422
1423
1424                 gtk_window_set_resizable(GTK_WINDOW(lw->tools), TRUE);
1425                 gtk_container_set_border_width(GTK_CONTAINER(lw->tools), 0);
1426
1427                 new_window = TRUE;
1428                 }
1429         else
1430                 {
1431                 layout_tools_geometry_sync(lw);
1432                 /* dump the contents */
1433                 gtk_widget_destroy(GTK_BIN(lw->tools)->child);
1434                 }
1435
1436         layout_actions_add_window(lw, lw->tools);
1437
1438         vbox = gtk_vbox_new(FALSE, 0);
1439         gtk_container_add(GTK_CONTAINER(lw->tools), vbox);
1440         gtk_widget_show(vbox);
1441
1442         layout_status_setup(lw, vbox, TRUE);
1443
1444         if (vertical)
1445                 {
1446                 lw->tools_pane = gtk_vpaned_new();
1447                 }
1448         else
1449                 {
1450                 lw->tools_pane = gtk_hpaned_new();
1451                 }
1452         gtk_box_pack_start(GTK_BOX(vbox), lw->tools_pane, TRUE, TRUE, 0);
1453         gtk_widget_show(lw->tools_pane);
1454
1455         gtk_paned_pack1(GTK_PANED(lw->tools_pane), w1, FALSE, TRUE);
1456         gtk_paned_pack2(GTK_PANED(lw->tools_pane), w2, TRUE, TRUE);
1457
1458         gtk_widget_show(tools);
1459         gtk_widget_show(files);
1460
1461         if (new_window)
1462                 {
1463                 if (options->layout.save_window_positions)
1464                         {
1465                         gtk_window_set_default_size(GTK_WINDOW(lw->tools), options->layout.float_window.w, options->layout.float_window.h);
1466                         gtk_window_move(GTK_WINDOW(lw->tools), options->layout.float_window.x, options->layout.float_window.y);
1467                         }
1468                 else
1469                         {
1470                         if (vertical)
1471                                 {
1472                                 gtk_window_set_default_size(GTK_WINDOW(lw->tools),
1473                                                             TOOLWINDOW_DEF_WIDTH, TOOLWINDOW_DEF_HEIGHT);
1474                                 }
1475                         else
1476                                 {
1477                                 gtk_window_set_default_size(GTK_WINDOW(lw->tools),
1478                                                             TOOLWINDOW_DEF_HEIGHT, TOOLWINDOW_DEF_WIDTH);
1479                                 }
1480                         }
1481                 }
1482
1483         if (!options->layout.save_window_positions)
1484                 {
1485                 if (vertical)
1486                         {
1487                         lw->options.float_window.vdivider_pos = MAIN_WINDOW_DIV_VPOS;
1488                         }
1489                 else
1490                         {
1491                         lw->options.float_window.vdivider_pos = MAIN_WINDOW_DIV_HPOS;
1492                         }
1493                 }
1494
1495         gtk_paned_set_position(GTK_PANED(lw->tools_pane), lw->options.float_window.vdivider_pos);
1496 }
1497
1498 /*
1499  *-----------------------------------------------------------------------------
1500  * glue (layout arrangement)
1501  *-----------------------------------------------------------------------------
1502  */
1503
1504 static void layout_grid_compute(LayoutWindow *lw,
1505                                 GtkWidget *image, GtkWidget *tools, GtkWidget *files,
1506                                 GtkWidget **w1, GtkWidget **w2, GtkWidget **w3)
1507 {
1508         /* heh, this was fun */
1509
1510         if (layout_location_single(lw->dir_location))
1511                 {
1512                 if (layout_location_first(lw->dir_location))
1513                         {
1514                         *w1 = tools;
1515                         layout_location_compute(lw->file_location, lw->image_location, files, image, w2, w3);
1516                         }
1517                 else
1518                         {
1519                         *w3 = tools;
1520                         layout_location_compute(lw->file_location, lw->image_location, files, image, w1, w2);
1521                         }
1522                 }
1523         else if (layout_location_single(lw->file_location))
1524                 {
1525                 if (layout_location_first(lw->file_location))
1526                         {
1527                         *w1 = files;
1528                         layout_location_compute(lw->dir_location, lw->image_location, tools, image, w2, w3);
1529                         }
1530                 else
1531                         {
1532                         *w3 = files;
1533                         layout_location_compute(lw->dir_location, lw->image_location, tools, image, w1, w2);
1534                         }
1535                 }
1536         else
1537                 {
1538                 /* image */
1539                 if (layout_location_first(lw->image_location))
1540                         {
1541                         *w1 = image;
1542                         layout_location_compute(lw->file_location, lw->dir_location, files, tools, w2, w3);
1543                         }
1544                 else
1545                         {
1546                         *w3 = image;
1547                         layout_location_compute(lw->file_location, lw->dir_location, files, tools, w1, w2);
1548                         }
1549                 }
1550 }
1551
1552 void layout_split_change(LayoutWindow *lw, ImageSplitMode mode)
1553 {
1554         GtkWidget *image;
1555         gint i;
1556
1557         for (i = 0; i < MAX_SPLIT_IMAGES; i++)
1558                 {
1559                 if (lw->split_images[i])
1560                         {
1561                         gtk_widget_hide(lw->split_images[i]->widget);
1562                         if (lw->split_images[i]->widget->parent != lw->utility_box)
1563                                 gtk_container_remove(GTK_CONTAINER(lw->split_images[i]->widget->parent), lw->split_images[i]->widget);
1564                         }
1565                 }
1566         gtk_container_remove(GTK_CONTAINER(lw->utility_box), lw->split_image_widget);
1567
1568         image = layout_image_setup_split(lw, mode);
1569
1570         gtk_box_pack_start(GTK_BOX(lw->utility_box), image, TRUE, TRUE, 0);
1571         gtk_box_reorder_child(GTK_BOX(lw->utility_box), image, 0);
1572         gtk_widget_show(image);
1573 }
1574
1575 static void layout_grid_setup(LayoutWindow *lw)
1576 {
1577         gint priority_location;
1578         GtkWidget *h;
1579         GtkWidget *v;
1580         GtkWidget *w1, *w2, *w3;
1581
1582         GtkWidget *image;
1583         GtkWidget *tools;
1584         GtkWidget *files;
1585
1586         layout_actions_setup(lw);
1587         layout_actions_add_window(lw, lw->window);
1588
1589         lw->group_box = gtk_vbox_new(FALSE, 0);
1590         gtk_box_pack_start(GTK_BOX(lw->main_box), lw->group_box, TRUE, TRUE, 0);
1591         gtk_widget_show(lw->group_box);
1592
1593         priority_location = layout_grid_compass(lw);
1594
1595         image = layout_image_setup_split(lw, lw->split_mode);
1596
1597         tools = layout_tools_new(lw);
1598         files = layout_list_new(lw);
1599
1600         image = layout_bars_prepare(lw, image);
1601
1602         if (lw->options.tools_float || lw->options.tools_hidden)
1603                 {
1604                 gtk_box_pack_start(GTK_BOX(lw->group_box), image, TRUE, TRUE, 0);
1605                 gtk_widget_show(image);
1606
1607                 layout_tools_setup(lw, tools, files);
1608
1609                 gtk_widget_grab_focus(lw->image->widget);
1610
1611                 return;
1612                 }
1613         else if (lw->tools)
1614                 {
1615                 layout_tools_geometry_sync(lw);
1616                 gtk_widget_destroy(lw->tools);
1617                 lw->tools = NULL;
1618                 lw->tools_pane = NULL;
1619                 }
1620
1621         layout_status_setup(lw, lw->group_box, FALSE);
1622
1623         layout_grid_compute(lw, image, tools, files, &w1, &w2, &w3);
1624
1625         v = lw->v_pane = gtk_vpaned_new();
1626
1627         h = lw->h_pane = gtk_hpaned_new();
1628
1629         if (!layout_location_vertical(priority_location))
1630                 {
1631                 GtkWidget *tmp;
1632
1633                 tmp = v;
1634                 v = h;
1635                 h = tmp;
1636                 }
1637
1638         gtk_box_pack_start(GTK_BOX(lw->group_box), v, TRUE, TRUE, 0);
1639
1640         if (!layout_location_first(priority_location))
1641                 {
1642                 gtk_paned_pack1(GTK_PANED(v), h, FALSE, TRUE);
1643                 gtk_paned_pack2(GTK_PANED(v), w3, TRUE, TRUE);
1644
1645                 gtk_paned_pack1(GTK_PANED(h), w1, FALSE, TRUE);
1646                 gtk_paned_pack2(GTK_PANED(h), w2, TRUE, TRUE);
1647                 }
1648         else
1649                 {
1650                 gtk_paned_pack1(GTK_PANED(v), w1, FALSE, TRUE);
1651                 gtk_paned_pack2(GTK_PANED(v), h, TRUE, TRUE);
1652
1653                 gtk_paned_pack1(GTK_PANED(h), w2, FALSE, TRUE);
1654                 gtk_paned_pack2(GTK_PANED(h), w3, TRUE, TRUE);
1655                 }
1656
1657         gtk_widget_show(image);
1658         gtk_widget_show(tools);
1659         gtk_widget_show(files);
1660
1661         gtk_widget_show(v);
1662         gtk_widget_show(h);
1663
1664         /* fix to have image pane visible when it is left and priority widget */
1665         if (lw->options.main_window.hdivider_pos == -1 &&
1666             w1 == image &&
1667             !layout_location_vertical(priority_location) &&
1668             layout_location_first(priority_location))
1669                 {
1670                 gtk_widget_set_size_request(image, 200, -1);
1671                 }
1672
1673         gtk_paned_set_position(GTK_PANED(lw->h_pane), lw->options.main_window.hdivider_pos);
1674         gtk_paned_set_position(GTK_PANED(lw->v_pane), lw->options.main_window.vdivider_pos);
1675
1676         gtk_widget_grab_focus(lw->image->widget);
1677 }
1678
1679 void layout_style_set(LayoutWindow *lw, gint style, const gchar *order)
1680 {
1681         FileData *dir_fd;
1682         gint i;
1683
1684         if (!layout_valid(&lw)) return;
1685
1686         if (style != -1)
1687                 {
1688                 LayoutLocation d, f, i;
1689
1690                 layout_config_parse(style, order, &d,  &f, &i);
1691
1692                 if (lw->dir_location == d &&
1693                     lw->file_location == f &&
1694                     lw->image_location == i) return;
1695
1696                 lw->dir_location = d;
1697                 lw->file_location = f;
1698                 lw->image_location = i;
1699                 }
1700
1701         /* remember state */
1702
1703         layout_image_slideshow_stop(lw);
1704         layout_image_full_screen_stop(lw);
1705
1706         dir_fd = lw->dir_fd;
1707         if (dir_fd) file_data_unregister_real_time_monitor(dir_fd);
1708         lw->dir_fd = NULL;
1709         lw->image = NULL;
1710         lw->utility_box = NULL;
1711
1712         layout_geometry_get_dividers(lw, &lw->options.main_window.hdivider_pos, &lw->options.main_window.vdivider_pos);
1713
1714         /* clear it all */
1715
1716         for (i = 0; i < MAX_SPLIT_IMAGES; i++)
1717                 {
1718                 if (lw->split_images[i])
1719                         {
1720                         gtk_widget_hide(lw->split_images[i]->widget);
1721                         gtk_container_remove(GTK_CONTAINER(lw->split_images[i]->widget->parent), lw->split_images[i]->widget);
1722                         }
1723                 }
1724
1725         lw->h_pane = NULL;
1726         lw->v_pane = NULL;
1727
1728         lw->toolbar = NULL;
1729         lw->thumb_button = NULL;
1730         lw->path_entry = NULL;
1731         lw->dir_view = NULL;
1732         lw->vd = NULL;
1733
1734         lw->file_view = NULL;
1735         lw->vf = NULL;
1736
1737         lw->info_box = NULL;
1738         lw->info_progress_bar = NULL;
1739         lw->info_sort = NULL;
1740         lw->info_color = NULL;
1741         lw->info_status = NULL;
1742         lw->info_details = NULL;
1743         lw->info_zoom = NULL;
1744
1745         if (lw->ui_manager) g_object_unref(lw->ui_manager);
1746         lw->ui_manager = NULL;
1747         lw->action_group = NULL;
1748         lw->action_group_external = NULL;
1749
1750         gtk_container_remove(GTK_CONTAINER(lw->main_box), lw->group_box);
1751         lw->group_box = NULL;
1752
1753         /* re-fill */
1754
1755         layout_grid_setup(lw);
1756         layout_tools_hide(lw, lw->options.tools_hidden);
1757
1758         layout_util_sync(lw);
1759         layout_status_update_all(lw);
1760
1761         /* sync */
1762
1763         if (image_get_fd(lw->image))
1764                 {
1765                 layout_set_fd(lw, image_get_fd(lw->image));
1766                 }
1767         else
1768                 {
1769                 layout_set_fd(lw, dir_fd);
1770                 }
1771         image_top_window_set_sync(lw->image, (lw->options.tools_float || lw->options.tools_hidden));
1772
1773         /* clean up */
1774
1775         file_data_unref(dir_fd);
1776 }
1777
1778 void layout_styles_update(void)
1779 {
1780         GList *work;
1781
1782         work = layout_window_list;
1783         while (work)
1784                 {
1785                 LayoutWindow *lw = work->data;
1786                 work = work->next;
1787
1788                 layout_style_set(lw, options->layout.style, options->layout.order);
1789                 }
1790 }
1791
1792 void layout_colors_update(void)
1793 {
1794         GList *work;
1795
1796         work = layout_window_list;
1797         while (work)
1798                 {
1799                 LayoutWindow *lw = work->data;
1800                 work = work->next;
1801
1802                 if (!lw->image) continue;
1803                 image_background_set_color(lw->image, options->image.use_custom_border_color ? &options->image.border_color : NULL);
1804                 }
1805 }
1806
1807 void layout_tools_float_toggle(LayoutWindow *lw)
1808 {
1809         gint popped;
1810
1811         if (!lw) return;
1812
1813         if (!lw->options.tools_hidden)
1814                 {
1815                 popped = !lw->options.tools_float;
1816                 }
1817         else
1818                 {
1819                 popped = TRUE;
1820                 }
1821
1822         if (lw->options.tools_float == popped)
1823                 {
1824                 if (popped && lw->options.tools_hidden)
1825                         {
1826                         layout_tools_float_set(lw, popped, FALSE);
1827                         }
1828                 }
1829         else
1830                 {
1831                 if (lw->options.tools_float)
1832                         {
1833                         layout_tools_float_set(lw, FALSE, FALSE);
1834                         }
1835                 else
1836                         {
1837                         layout_tools_float_set(lw, TRUE, FALSE);
1838                         }
1839                 }
1840 }
1841
1842 void layout_tools_hide_toggle(LayoutWindow *lw)
1843 {
1844         if (!lw) return;
1845
1846         layout_tools_float_set(lw, lw->options.tools_float, !lw->options.tools_hidden);
1847 }
1848
1849 void layout_tools_float_set(LayoutWindow *lw, gint popped, gint hidden)
1850 {
1851         if (!layout_valid(&lw)) return;
1852
1853         if (lw->options.tools_float == popped && lw->options.tools_hidden == hidden) return;
1854
1855         if (lw->options.tools_float == popped && lw->options.tools_float && lw->tools)
1856                 {
1857                 layout_tools_hide(lw, hidden);
1858                 return;
1859                 }
1860
1861         lw->options.tools_float = popped;
1862         lw->options.tools_hidden = hidden;
1863
1864         layout_style_set(lw, -1, NULL);
1865 }
1866
1867 gint layout_tools_float_get(LayoutWindow *lw, gint *popped, gint *hidden)
1868 {
1869         if (!layout_valid(&lw)) return FALSE;
1870
1871         *popped = lw->options.tools_float;
1872         *hidden = lw->options.tools_hidden;
1873
1874         return TRUE;
1875 }
1876
1877 void layout_toolbar_toggle(LayoutWindow *lw)
1878 {
1879         if (!layout_valid(&lw)) return;
1880         if (!lw->toolbar) return;
1881
1882         lw->options.toolbar_hidden = !lw->options.toolbar_hidden;
1883
1884         if (lw->options.toolbar_hidden)
1885                 {
1886                 if (GTK_WIDGET_VISIBLE(lw->toolbar)) gtk_widget_hide(lw->toolbar);
1887                 }
1888         else
1889                 {
1890                 if (!GTK_WIDGET_VISIBLE(lw->toolbar)) gtk_widget_show(lw->toolbar);
1891                 }
1892 }
1893
1894 gint layout_toolbar_hidden(LayoutWindow *lw)
1895 {
1896         if (!layout_valid(&lw)) return TRUE;
1897
1898         return lw->options.toolbar_hidden;
1899 }
1900
1901 /*
1902  *-----------------------------------------------------------------------------
1903  * base
1904  *-----------------------------------------------------------------------------
1905  */
1906
1907 void layout_sync_options_with_current_state(LayoutWindow *lw)
1908 {
1909         if (!layout_valid(&lw)) return;
1910
1911         lw->options.main_window.maximized =  window_maximized(lw->window);
1912         if (!lw->options.main_window.maximized)
1913                 {
1914                 layout_geometry_get(lw, &lw->options.main_window.x, &lw->options.main_window.y,
1915                                     &lw->options.main_window.w, &lw->options.main_window.h);
1916                 }
1917
1918         layout_geometry_get_dividers(lw, &lw->options.main_window.hdivider_pos, &lw->options.main_window.vdivider_pos);
1919
1920 //      layout_sort_get(NULL, &options->file_sort.method, &options->file_sort.ascending);
1921
1922         layout_geometry_get_tools(lw, &lw->options.float_window.x, &lw->options.float_window.y,
1923                                   &lw->options.float_window.w, &lw->options.float_window.h, &lw->options.float_window.vdivider_pos);
1924
1925 //      if (options->startup.restore_path && options->startup.use_last_path)
1926 //              {
1927 //              g_free(options->startup.path);
1928 //              options->startup.path = g_strdup(layout_get_path(NULL));
1929 //              }
1930 }
1931
1932
1933 void layout_close(LayoutWindow *lw)
1934 {
1935         if (layout_window_list && layout_window_list->next)
1936                 {
1937                 layout_free(lw);
1938                 }
1939         else
1940                 {
1941                 exit_program();
1942                 }
1943 }
1944
1945 void layout_free(LayoutWindow *lw)
1946 {
1947         if (!lw) return;
1948
1949         layout_window_list = g_list_remove(layout_window_list, lw);
1950
1951         if (lw->exif_window) g_signal_handlers_disconnect_matched(G_OBJECT(lw->exif_window), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, lw);
1952                 
1953         layout_bars_close(lw);
1954
1955         gtk_widget_destroy(lw->window);
1956         
1957         if (lw->split_image_sizegroup) g_object_unref(lw->split_image_sizegroup);
1958
1959         file_data_unregister_notify_func(layout_image_notify_cb, lw);
1960
1961         if (lw->dir_fd)
1962                 {
1963                 file_data_unregister_real_time_monitor(lw->dir_fd);
1964                 file_data_unref(lw->dir_fd);
1965                 }
1966
1967         free_layout_options_content(&lw->options);
1968         g_free(lw);
1969 }
1970
1971 static gint layout_delete_cb(GtkWidget *widget, GdkEventAny *event, gpointer data)
1972 {
1973         LayoutWindow *lw = data;
1974
1975         layout_close(lw);
1976         return TRUE;
1977 }
1978
1979 LayoutWindow *layout_new(FileData *dir_fd, LayoutOptions *lop)
1980 {
1981         return layout_new_with_geometry(dir_fd, lop, NULL);
1982 }
1983
1984 LayoutWindow *layout_new_with_geometry(FileData *dir_fd, LayoutOptions *lop,
1985                                        const gchar *geometry)
1986 {
1987         LayoutWindow *lw;
1988         GdkGeometry hint;
1989         GdkWindowHints hint_mask;
1990
1991         lw = g_new0(LayoutWindow, 1);
1992
1993         if (lop)
1994                 copy_layout_options(&lw->options, lop);
1995         else
1996                 copy_layout_options(&lw->options, &options->layout);
1997
1998         lw->sort_method = SORT_NAME;
1999         lw->sort_ascend = TRUE;
2000
2001 //      lw->options.tools_float = popped;
2002 //      lw->options.tools_hidden = hidden;
2003
2004         lw->utility_box = NULL;
2005         lw->bar_sort = NULL;
2006 //      lw->bar_sort_enabled = options->panels.sort.enabled;
2007
2008         lw->bar = NULL;
2009 //      lw->bar_enabled = options->panels.info.enabled;
2010
2011         lw->exif_window = NULL;
2012         /* default layout */
2013
2014         layout_config_parse(lw->options.style, lw->options.order,
2015                             &lw->dir_location,  &lw->file_location, &lw->image_location);
2016         if (lw->options.dir_view_type >= VIEW_DIR_TYPES_COUNT) lw->options.dir_view_type = 0;
2017         if (lw->options.file_view_type >= VIEW_FILE_TYPES_COUNT) lw->options.file_view_type = 0;
2018
2019         /* divider positions */
2020
2021         if (!lw->options.save_window_positions)
2022                 {
2023                 lw->options.main_window.hdivider_pos = MAIN_WINDOW_DIV_HPOS;
2024                 lw->options.main_window.vdivider_pos = MAIN_WINDOW_DIV_VPOS;
2025                 lw->options.float_window.vdivider_pos = MAIN_WINDOW_DIV_VPOS;
2026                 }
2027
2028         /* window */
2029
2030         lw->window = window_new(GTK_WINDOW_TOPLEVEL, GQ_APPNAME_LC, NULL, NULL, NULL);
2031         gtk_window_set_resizable(GTK_WINDOW(lw->window), TRUE);
2032         gtk_container_set_border_width(GTK_CONTAINER(lw->window), 0);
2033
2034         if (lw->options.save_window_positions)
2035                 {
2036                 hint_mask = GDK_HINT_USER_POS;
2037                 }
2038         else
2039                 {
2040                 hint_mask = 0;
2041                 }
2042
2043         hint.min_width = 32;
2044         hint.min_height = 32;
2045         hint.base_width = 0;
2046         hint.base_height = 0;
2047         gtk_window_set_geometry_hints(GTK_WINDOW(lw->window), NULL, &hint,
2048                                       GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | hint_mask);
2049
2050         if (lw->options.save_window_positions)
2051                 {
2052                 gtk_window_set_default_size(GTK_WINDOW(lw->window), lw->options.main_window.w, lw->options.main_window.h);
2053 //              if (!layout_window_list)
2054 //                      {
2055                 gtk_window_move(GTK_WINDOW(lw->window), lw->options.main_window.x, lw->options.main_window.y);
2056                 if (lw->options.main_window.maximized) gtk_window_maximize(GTK_WINDOW(lw->window));
2057 //                      }
2058                 }
2059         else
2060                 {
2061                 gtk_window_set_default_size(GTK_WINDOW(lw->window), MAINWINDOW_DEF_WIDTH, MAINWINDOW_DEF_HEIGHT);
2062                 }
2063
2064         g_signal_connect(G_OBJECT(lw->window), "delete_event",
2065                          G_CALLBACK(layout_delete_cb), lw);
2066
2067         layout_keyboard_init(lw, lw->window);
2068
2069 #ifdef HAVE_LIRC
2070         layout_image_lirc_init(lw);
2071 #endif
2072
2073         lw->main_box = gtk_vbox_new(FALSE, 0);
2074         gtk_container_add(GTK_CONTAINER(lw->window), lw->main_box);
2075         gtk_widget_show(lw->main_box);
2076
2077         layout_grid_setup(lw);
2078         image_top_window_set_sync(lw->image, (lw->options.tools_float || lw->options.tools_hidden));
2079
2080         layout_util_sync(lw);
2081         layout_status_update_all(lw);
2082
2083         if (dir_fd)
2084                 {
2085                 layout_set_fd(lw, dir_fd);
2086                 }
2087         else
2088                 {
2089                 GdkPixbuf *pixbuf;
2090
2091                 pixbuf = pixbuf_inline(PIXBUF_INLINE_LOGO);
2092                 
2093                 /* FIXME: the zoom value set here is the value, which is then copied again and again
2094                    in "Leave Zoom at previous setting" mode. This is not ideal.  */
2095                 image_change_pixbuf(lw->image, pixbuf, 0.0, FALSE);
2096                 g_object_unref(pixbuf);
2097                 }
2098
2099         if (geometry)
2100                 {
2101                 if (!gtk_window_parse_geometry(GTK_WINDOW(lw->window), geometry))
2102                         {
2103                         log_printf("%s", _("Invalid geometry\n"));
2104                         }
2105                 }
2106
2107         gtk_widget_show(lw->window);
2108         layout_tools_hide(lw, lw->options.tools_hidden);
2109
2110         image_osd_set(lw->image, options->image_overlay.common.state | (options->image_overlay.common.show_at_startup ? OSD_SHOW_INFO : OSD_SHOW_NOTHING));
2111
2112         layout_window_list = g_list_append(layout_window_list, lw);
2113
2114         file_data_register_notify_func(layout_image_notify_cb, lw, NOTIFY_PRIORITY_LOW);
2115
2116         return lw;
2117 }
2118
2119 void layout_write_attributes(LayoutOptions *layout, GString *outstr, gint indent)
2120 {
2121         WRITE_INT(*layout, style);
2122         WRITE_CHAR(*layout, order);
2123         WRITE_UINT(*layout, dir_view_type);
2124         WRITE_UINT(*layout, file_view_type);
2125         WRITE_BOOL(*layout, show_marks);
2126         WRITE_BOOL(*layout, show_thumbnails);
2127         WRITE_BOOL(*layout, show_directory_date);
2128         WRITE_CHAR(*layout, home_path);
2129         WRITE_SEPARATOR();
2130
2131         WRITE_BOOL(*layout, save_window_positions);
2132         WRITE_SEPARATOR();
2133
2134         WRITE_INT(*layout, main_window.x);
2135         WRITE_INT(*layout, main_window.y);
2136         WRITE_INT(*layout, main_window.w);
2137         WRITE_INT(*layout, main_window.h);
2138         WRITE_BOOL(*layout, main_window.maximized);
2139         WRITE_INT(*layout, main_window.hdivider_pos);
2140         WRITE_INT(*layout, main_window.vdivider_pos);
2141         WRITE_SEPARATOR();
2142
2143         WRITE_INT(*layout, float_window.x);
2144         WRITE_INT(*layout, float_window.y);
2145         WRITE_INT(*layout, float_window.w);
2146         WRITE_INT(*layout, float_window.h);
2147         WRITE_INT(*layout, float_window.vdivider_pos);
2148         WRITE_SEPARATOR();
2149
2150         WRITE_INT(*layout, properties_window.w);
2151         WRITE_INT(*layout, properties_window.h);
2152         WRITE_SEPARATOR();
2153
2154         WRITE_BOOL(*layout, tools_float);
2155         WRITE_BOOL(*layout, tools_hidden);
2156         WRITE_BOOL(*layout, tools_restore_state);
2157         WRITE_SEPARATOR();
2158
2159         WRITE_BOOL(*layout, toolbar_hidden);
2160
2161         WRITE_BOOL(*layout, panels.sort.enabled);
2162         WRITE_INT(*layout, panels.sort.action_state);
2163         WRITE_INT(*layout, panels.sort.mode_state);
2164         WRITE_INT(*layout, panels.sort.selection_state);
2165         WRITE_CHAR(*layout, panels.sort.action_filter);
2166 }
2167
2168
2169 void layout_write_config(LayoutWindow *lw, GString *outstr, gint indent)
2170 {
2171         layout_sync_options_with_current_state(lw);
2172         WRITE_STRING("<layout\n");
2173         layout_write_attributes(&lw->options, outstr, indent + 1);
2174         WRITE_STRING(">\n");
2175
2176         bar_write_config(lw->bar, outstr, indent + 1);
2177         
2178         WRITE_STRING("</layout>\n");
2179 }
2180
2181 void layout_load_attributes(LayoutOptions *layout, const gchar **attribute_names, const gchar **attribute_values)
2182 {
2183         
2184         while (*attribute_names)
2185                 {
2186                 const gchar *option = *attribute_names++;
2187                 const gchar *value = *attribute_values++;
2188
2189                 /* layout options */
2190
2191                 if (READ_INT(*layout, style)) continue;
2192                 if (READ_CHAR(*layout, order)) continue;
2193                 
2194                 if (READ_UINT(*layout, dir_view_type)) continue;
2195                 if (READ_UINT(*layout, file_view_type)) continue;
2196                 if (READ_BOOL(*layout, show_marks)) continue;
2197                 if (READ_BOOL(*layout, show_thumbnails)) continue;
2198                 if (READ_BOOL(*layout, show_directory_date)) continue;
2199                 if (READ_CHAR(*layout, home_path)) continue;
2200
2201                 /* window positions */
2202
2203                 if (READ_BOOL(*layout, save_window_positions)) continue;
2204
2205                 if (READ_INT(*layout, main_window.x)) continue;
2206                 if (READ_INT(*layout, main_window.y)) continue;
2207                 if (READ_INT(*layout, main_window.w)) continue;
2208                 if (READ_INT(*layout, main_window.h)) continue;
2209                 if (READ_BOOL(*layout, main_window.maximized)) continue;
2210                 if (READ_INT(*layout, main_window.hdivider_pos)) continue;
2211                 if (READ_INT(*layout, main_window.vdivider_pos)) continue;
2212
2213                 if (READ_INT(*layout, float_window.x)) continue;
2214                 if (READ_INT(*layout, float_window.y)) continue;
2215                 if (READ_INT(*layout, float_window.w)) continue;
2216                 if (READ_INT(*layout, float_window.h)) continue;
2217                 if (READ_INT(*layout, float_window.vdivider_pos)) continue;
2218         
2219                 if (READ_INT(*layout, properties_window.w)) continue;
2220                 if (READ_INT(*layout, properties_window.h)) continue;
2221
2222                 if (READ_BOOL(*layout, tools_float)) continue;
2223                 if (READ_BOOL(*layout, tools_hidden)) continue;
2224                 if (READ_BOOL(*layout, tools_restore_state)) continue;
2225                 if (READ_BOOL(*layout, toolbar_hidden)) continue;
2226
2227                 /* panels */
2228                 if (READ_BOOL(*layout, panels.sort.enabled)) continue;
2229                 if (READ_INT(*layout, panels.sort.action_state)) continue;
2230                 if (READ_INT(*layout, panels.sort.mode_state)) continue;
2231                 if (READ_INT(*layout, panels.sort.selection_state)) continue;
2232                 if (READ_CHAR(*layout, panels.sort.action_filter)) continue;
2233
2234
2235                 DEBUG_1("unknown attribute %s = %s", option, value);
2236                 }
2237
2238 }
2239
2240 static void layout_config_commandline(LayoutOptions *lop, gchar **path)
2241 {
2242         if (command_line->startup_blank)
2243                 {
2244                 *path = NULL;
2245                 }
2246         else if (command_line->file)
2247                 {
2248                 *path = g_strdup(command_line->file);
2249                 }
2250         else if (command_line->path)
2251                 {
2252                 *path = g_strdup(command_line->path);
2253                 }
2254         else if (options->startup.restore_path && options->startup.path && isdir(options->startup.path))
2255                 {
2256                 *path = g_strdup(options->startup.path);
2257                 }
2258         else
2259                 {
2260                 *path = get_current_dir();
2261                 }
2262         
2263         if (command_line->tools_show)
2264                 {
2265                 lop->tools_float = FALSE;
2266                 lop->tools_hidden = FALSE;
2267                 }
2268         else if (command_line->tools_hide)
2269                 {
2270                 lop->tools_hidden = TRUE;
2271                 }
2272 }
2273
2274 LayoutWindow *layout_new_from_config(const gchar **attribute_names, const gchar **attribute_values, gboolean use_commandline)
2275 {
2276         LayoutOptions lop;
2277         LayoutWindow *lw;
2278         gchar *path = NULL;
2279         
2280         memset(&lop, 0, sizeof(LayoutOptions));
2281         copy_layout_options(&lop, &options->layout);
2282
2283         if (attribute_names) layout_load_attributes(&lop, attribute_names, attribute_values);
2284         
2285         if (use_commandline)
2286                 {
2287                 layout_config_commandline(&lop, &path);
2288                 }
2289         else if (options->startup.restore_path && options->startup.path && isdir(options->startup.path))
2290                 {
2291                 path = g_strdup(options->startup.path);
2292                 }
2293         else
2294                 {
2295                 path = get_current_dir();
2296                 }
2297
2298         lw = layout_new_with_geometry(NULL, &lop, use_commandline ? command_line->geometry : NULL);
2299         layout_sort_set(lw, options->file_sort.method, options->file_sort.ascending);
2300         layout_set_path(lw, path);
2301
2302         if (use_commandline && command_line->startup_full_screen) layout_image_full_screen_start(lw);
2303         if (use_commandline && command_line->startup_in_slideshow) layout_image_slideshow_start(lw);
2304
2305
2306         g_free(path);
2307         free_layout_options_content(&lop);
2308         return lw;
2309 }
2310
2311
2312 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */