be more verbose on parse errors
[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 #include "bar_sort.h"
39 #include "preferences.h"
40
41 #ifdef HAVE_LIRC
42 #include "lirc.h"
43 #endif
44
45 #define MAINWINDOW_DEF_WIDTH 700
46 #define MAINWINDOW_DEF_HEIGHT 500
47
48 #define MAIN_WINDOW_DIV_HPOS (MAINWINDOW_DEF_WIDTH / 2)
49 #define MAIN_WINDOW_DIV_VPOS (MAINWINDOW_DEF_HEIGHT / 2)
50
51 #define TOOLWINDOW_DEF_WIDTH 260
52 #define TOOLWINDOW_DEF_HEIGHT 450
53
54 #define PROGRESS_WIDTH 150
55 #define PIXEL_LABEL_WIDTH 130
56 #define ZOOM_LABEL_WIDTH 64
57
58 #define PANE_DIVIDER_SIZE 10
59
60
61 GList *layout_window_list = NULL;
62
63
64 static void layout_list_scroll_to_subpart(LayoutWindow *lw, const gchar *needle);
65
66
67 /*
68  *-----------------------------------------------------------------------------
69  * misc
70  *-----------------------------------------------------------------------------
71  */
72
73 gboolean layout_valid(LayoutWindow **lw)
74 {
75         if (*lw == NULL)
76                 {
77                 if (layout_window_list) *lw = layout_window_list->data;
78                 return (*lw != NULL);
79                 }
80
81         return (g_list_find(layout_window_list, *lw) != NULL);
82 }
83
84 LayoutWindow *layout_find_by_image(ImageWindow *imd)
85 {
86         GList *work;
87
88         work = layout_window_list;
89         while (work)
90                 {
91                 LayoutWindow *lw = work->data;
92                 work = work->next;
93
94                 if (lw->image == imd) return lw;
95                 }
96
97         return NULL;
98 }
99
100 LayoutWindow *layout_find_by_image_fd(ImageWindow *imd)
101 {
102         GList *work;
103
104         work = layout_window_list;
105         while (work)
106                 {
107                 LayoutWindow *lw = work->data;
108                 work = work->next;
109
110                 if (lw->image->image_fd == imd->image_fd)
111                         return lw;
112                 }
113
114         return NULL;
115 }
116
117 /*
118  *-----------------------------------------------------------------------------
119  * menu, toolbar, and dir view
120  *-----------------------------------------------------------------------------
121  */
122
123 static void layout_path_entry_changed_cb(GtkWidget *widget, gpointer data)
124 {
125         LayoutWindow *lw = data;
126         gchar *buf;
127
128         if (gtk_combo_box_get_active(GTK_COMBO_BOX(widget)) < 0) return;
129
130         buf = g_strdup(gtk_entry_get_text(GTK_ENTRY(lw->path_entry)));
131         if (!lw->dir_fd || strcmp(buf, lw->dir_fd->path) != 0)
132                 {
133                 layout_set_path(lw, buf);
134                 }
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
144         buf = g_strdup(path);
145         parse_out_relatives(buf);
146         
147         if (isdir(buf))
148                 {
149                 if ((!lw->dir_fd || strcmp(lw->dir_fd->path, buf) != 0) && layout_set_path(lw, buf))
150                         {
151                         gint pos = -1;
152                         /* put the G_DIR_SEPARATOR back, if we are in tab completion for a dir and result was path change */
153                         gtk_editable_insert_text(GTK_EDITABLE(lw->path_entry), G_DIR_SEPARATOR_S, -1, &pos);
154                         gtk_editable_set_position(GTK_EDITABLE(lw->path_entry),
155                                                   strlen(gtk_entry_get_text(GTK_ENTRY(lw->path_entry))));
156                         }
157                 }
158         else if (lw->dir_fd)
159                 {
160                 gchar *base = remove_level_from_path(buf);
161
162                 if (strcmp(lw->dir_fd->path, base) == 0)
163                         {
164                         layout_list_scroll_to_subpart(lw, filename_from_path(buf));
165                         }
166                 g_free(base);
167                 }
168                 
169         g_free(buf);
170 }
171
172 static void layout_path_entry_cb(const gchar *path, gpointer data)
173 {
174         LayoutWindow *lw = data;
175         gchar *buf;
176
177         buf = g_strdup(path);
178         parse_out_relatives(buf);
179
180         layout_set_path(lw, buf);
181
182         g_free(buf);
183 }
184
185 static void layout_vd_select_cb(ViewDir *vd, const gchar *path, gpointer data)
186 {
187         LayoutWindow *lw = data;
188
189         layout_set_path(lw, path);
190 }
191
192 static void layout_path_entry_tab_append_cb(const gchar *path, gpointer data, gint n)
193 {
194         LayoutWindow *lw = data;
195
196         if (!lw || !lw->back_button) return;
197         if (!layout_valid(&lw)) return;
198
199         /* Enable back button if it makes sense */
200         gtk_widget_set_sensitive(lw->back_button, (n > 1));
201 }
202
203 static GtkWidget *layout_tool_setup(LayoutWindow *lw)
204 {
205         GtkWidget *box;
206         GtkWidget *menu_bar;
207         GtkWidget *tabcomp;
208
209         box = gtk_vbox_new(FALSE, 0);
210
211         menu_bar = layout_actions_menu_bar(lw);
212         gtk_box_pack_start(GTK_BOX(box), menu_bar, FALSE, FALSE, 0);
213         gtk_widget_show(menu_bar);
214
215         lw->toolbar = layout_actions_toolbar(lw);
216         gtk_box_pack_start(GTK_BOX(box), lw->toolbar, FALSE, FALSE, 0);
217         if (!lw->options.toolbar_hidden) gtk_widget_show(lw->toolbar);
218
219         tabcomp = tab_completion_new_with_history(&lw->path_entry, NULL, "path_list", -1,
220                                                   layout_path_entry_cb, lw);
221         tab_completion_add_tab_func(lw->path_entry, layout_path_entry_tab_cb, lw);
222         tab_completion_add_append_func(lw->path_entry, layout_path_entry_tab_append_cb, lw);
223         gtk_box_pack_start(GTK_BOX(box), tabcomp, FALSE, FALSE, 0);
224         gtk_widget_show(tabcomp);
225
226         g_signal_connect(G_OBJECT(lw->path_entry->parent), "changed",
227                          G_CALLBACK(layout_path_entry_changed_cb), lw);
228
229         lw->vd = vd_new(lw->options.dir_view_type, lw->dir_fd);
230         vd_set_layout(lw->vd, lw);
231         vd_set_select_func(lw->vd, layout_vd_select_cb, lw);
232
233         lw->dir_view = lw->vd->widget;
234
235         gtk_box_pack_start(GTK_BOX(box), lw->dir_view, TRUE, TRUE, 0);
236         gtk_widget_show(lw->dir_view);
237
238         gtk_widget_show(box);
239
240         return box;
241 }
242
243 /*
244  *-----------------------------------------------------------------------------
245  * sort button (and menu)
246  *-----------------------------------------------------------------------------
247  */
248
249 static void layout_sort_menu_cb(GtkWidget *widget, gpointer data)
250 {
251         LayoutWindow *lw;
252         SortType type;
253
254         if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) return;
255
256         lw = submenu_item_get_data(widget);
257         if (!lw) return;
258
259         type = (SortType)GPOINTER_TO_INT(data);
260
261         layout_sort_set(lw, type, lw->sort_ascend);
262 }
263
264 static void layout_sort_menu_ascend_cb(GtkWidget *widget, gpointer data)
265 {
266         LayoutWindow *lw = data;
267
268         layout_sort_set(lw, lw->sort_method, !lw->sort_ascend);
269 }
270
271 static void layout_sort_menu_hide_cb(GtkWidget *widget, gpointer data)
272 {
273         /* destroy the menu */
274 #if GTK_CHECK_VERSION(2,12,0)
275         g_object_unref(widget);
276 #else
277         gtk_widget_unref(GTK_WIDGET(widget));
278 #endif
279 }
280
281 static void layout_sort_button_press_cb(GtkWidget *widget, gpointer data)
282 {
283         LayoutWindow *lw = data;
284         GtkWidget *menu;
285         GdkEvent *event;
286         guint32 etime;
287
288         menu = submenu_add_sort(NULL, G_CALLBACK(layout_sort_menu_cb), lw, FALSE, FALSE, TRUE, lw->sort_method);
289
290         /* take ownership of menu */
291 #ifdef GTK_OBJECT_FLOATING
292         /* GTK+ < 2.10 */
293         g_object_ref(G_OBJECT(menu));
294         gtk_object_sink(GTK_OBJECT(menu));
295 #else
296         /* GTK+ >= 2.10 */
297         g_object_ref_sink(G_OBJECT(menu));
298 #endif
299
300         /* ascending option */
301         menu_item_add_divider(menu);
302         menu_item_add_check(menu, _("Ascending"), lw->sort_ascend, G_CALLBACK(layout_sort_menu_ascend_cb), lw);
303
304         g_signal_connect(G_OBJECT(menu), "selection_done",
305                          G_CALLBACK(layout_sort_menu_hide_cb), NULL);
306
307         event = gtk_get_current_event();
308         if (event)
309                 {
310                 etime = gdk_event_get_time(event);
311                 gdk_event_free(event);
312                 }
313         else
314                 {
315                 etime = 0;
316                 }
317
318         gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, etime);
319 }
320
321 static GtkWidget *layout_sort_button(LayoutWindow *lw)
322 {
323         GtkWidget *button;
324
325         button = gtk_button_new_with_label(sort_type_get_text(lw->sort_method));
326         g_signal_connect(G_OBJECT(button), "clicked",
327                          G_CALLBACK(layout_sort_button_press_cb), lw);
328         gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
329
330         return button;
331 }
332
333 /*
334  *-----------------------------------------------------------------------------
335  * color profile button (and menu)
336  *-----------------------------------------------------------------------------
337  */
338
339 #ifdef HAVE_LCMS
340
341 static void layout_color_menu_enable_cb(GtkWidget *widget, gpointer data)
342 {
343         LayoutWindow *lw = data;
344
345         layout_image_color_profile_set_use(lw, (!layout_image_color_profile_get_use(lw)));
346         layout_image_refresh(lw);
347 }
348
349 static void layout_color_menu_use_image_cb(GtkWidget *widget, gpointer data)
350 {
351         LayoutWindow *lw = data;
352         gint input, screen;
353         gboolean use_image;
354
355         if (!layout_image_color_profile_get(lw, &input, &screen, &use_image)) return;
356         layout_image_color_profile_set(lw, input, screen, !use_image);
357         layout_image_refresh(lw);
358 }
359
360 #define COLOR_MENU_KEY "color_menu_key"
361
362 static void layout_color_menu_input_cb(GtkWidget *widget, gpointer data)
363 {
364         LayoutWindow *lw = data;
365         gint type;
366         gint input, screen;
367         gboolean use_image;
368
369         if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) return;
370
371         type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), COLOR_MENU_KEY));
372         if (type < 0 || type >= COLOR_PROFILE_FILE + COLOR_PROFILE_INPUTS) return;
373
374         if (!layout_image_color_profile_get(lw, &input, &screen, &use_image)) return;
375         if (type == input) return;
376
377         layout_image_color_profile_set(lw, type, screen, use_image);
378         layout_image_refresh(lw);
379 }
380
381 static void layout_color_menu_screen_cb(GtkWidget *widget, gpointer data)
382 {
383         LayoutWindow *lw = data;
384         gint type;
385         gint input, screen;
386         gboolean use_image;
387
388         if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) return;
389
390         type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), COLOR_MENU_KEY));
391         if (type < 0 || type > 1) return;
392
393         if (!layout_image_color_profile_get(lw, &input, &screen, &use_image)) return;
394         if (type == screen) return;
395
396         layout_image_color_profile_set(lw, input, type, use_image);
397         layout_image_refresh(lw);
398 }
399
400 static gchar *layout_color_name_parse(const gchar *name)
401 {
402         if (!name || !*name) return g_strdup(_("Empty"));
403         return g_strdelimit(g_strdup(name), "_", '-');
404 }
405
406 #endif /* HAVE_LCMS */
407
408 static void layout_color_button_press_cb(GtkWidget *widget, gpointer data)
409 {
410 #ifndef HAVE_LCMS
411         gchar *msg = g_strdup_printf(_("This installation of %s was not built with support for color profiles."), GQ_APPNAME);
412         file_util_warning_dialog(_("Color profiles not supported"),
413                                  msg,
414                                  GTK_STOCK_DIALOG_INFO, widget);
415         g_free(msg);
416         return;
417 #else
418         LayoutWindow *lw = data;
419         GtkWidget *menu;
420         GtkWidget *item;
421         gchar *buf;
422         gboolean active;
423         gint input = 0;
424         gint screen = 0;
425         gboolean use_image = FALSE;
426         gboolean from_image;
427         gint image_profile;
428         gint i;
429         
430         if (!layout_image_color_profile_get(lw, &input, &screen, &use_image)) return;
431
432         image_profile = layout_image_color_profile_get_from_image(lw);
433         from_image = use_image && (image_profile != 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, image_profile == COLOR_PROFILE_MEM || (image_profile > COLOR_PROFILE_NONE && image_profile < COLOR_PROFILE_FILE));
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%s"), i, label, (i == image_profile) ? " *" : "");
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 = options->color_profile.input_name[i];
468                 const gchar *file = options->color_profile.input_file[i];
469                 gchar *end;
470
471                 if (!name || !name[0]) name = filename_from_path(file);
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 && !from_image && is_readable_file(file));
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 && is_readable_file(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         gboolean 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_signal_emit_by_name (lw->image->pr, "update-pixel");
714                 
715                 g_free(b);
716                 
717                 gtk_label_set_text(GTK_LABEL(lw->info_details), text);
718                 g_free(text);
719                 }
720 }
721
722 void layout_status_update_all(LayoutWindow *lw)
723 {
724         layout_status_update_progress(lw, 0.0, NULL);
725         layout_status_update_info(lw, NULL);
726         layout_status_update_image(lw);
727         layout_status_update_write(lw);
728 }
729
730 static GtkWidget *layout_status_label(gchar *text, GtkWidget *box, gboolean start, gint size, gboolean expand)
731 {
732         GtkWidget *label;
733         GtkWidget *frame;
734
735         frame = gtk_frame_new(NULL);
736         if (size) gtk_widget_set_size_request(frame, size, -1);
737         gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
738         if (start)
739                 {
740                 gtk_box_pack_start(GTK_BOX(box), frame, expand, expand, 0);
741                 }
742         else
743                 {
744                 gtk_box_pack_end(GTK_BOX(box), frame, expand, expand, 0);
745                 }
746         gtk_widget_show(frame);
747
748         label = gtk_label_new(text ? text : "");
749         gtk_container_add(GTK_CONTAINER(frame), label);
750         gtk_widget_show(label);
751
752         return label;
753 }
754
755 static void layout_status_setup(LayoutWindow *lw, GtkWidget *box, gboolean small_format)
756 {
757         GtkWidget *hbox;
758
759         if (lw->info_box) return;
760
761         if (small_format)
762                 {
763                 lw->info_box = gtk_vbox_new(FALSE, 0);
764                 }
765         else
766                 {
767                 lw->info_box = gtk_hbox_new(FALSE, 0);
768                 }
769         gtk_box_pack_end(GTK_BOX(box), lw->info_box, FALSE, FALSE, 0);
770         gtk_widget_show(lw->info_box);
771
772         if (small_format)
773                 {
774                 hbox = gtk_hbox_new(FALSE, 0);
775                 gtk_box_pack_start(GTK_BOX(lw->info_box), hbox, FALSE, FALSE, 0);
776                 gtk_widget_show(hbox);
777                 }
778         else
779                 {
780                 hbox = lw->info_box;
781                 }
782         lw->info_progress_bar = gtk_progress_bar_new();
783         gtk_widget_set_size_request(lw->info_progress_bar, PROGRESS_WIDTH, -1);
784         gtk_box_pack_start(GTK_BOX(hbox), lw->info_progress_bar, FALSE, FALSE, 0);
785         gtk_widget_show(lw->info_progress_bar);
786
787         lw->info_sort = layout_sort_button(lw);
788         gtk_box_pack_start(GTK_BOX(hbox), lw->info_sort, FALSE, FALSE, 0);
789         gtk_widget_show(lw->info_sort);
790
791         lw->info_color = layout_color_button(lw);
792         gtk_widget_show(lw->info_color);
793
794         lw->info_write = layout_write_button(lw);
795         gtk_widget_show(lw->info_write);
796
797         if (small_format) gtk_box_pack_end(GTK_BOX(hbox), lw->info_color, FALSE, FALSE, 0);
798         if (small_format) gtk_box_pack_end(GTK_BOX(hbox), lw->info_write, FALSE, FALSE, 0);
799
800         lw->info_status = layout_status_label(NULL, lw->info_box, TRUE, 0, (!small_format));
801
802         if (small_format)
803                 {
804                 hbox = gtk_hbox_new(FALSE, 0);
805                 gtk_box_pack_start(GTK_BOX(lw->info_box), hbox, FALSE, FALSE, 0);
806                 gtk_widget_show(hbox);
807                 }
808         else
809                 {
810                 hbox = lw->info_box;
811                 }
812         lw->info_details = layout_status_label(NULL, hbox, TRUE, 0, TRUE);
813         if (!small_format) gtk_box_pack_start(GTK_BOX(hbox), lw->info_color, FALSE, FALSE, 0);
814         if (!small_format) gtk_box_pack_start(GTK_BOX(hbox), lw->info_write, FALSE, FALSE, 0);
815         lw->info_pixel = layout_status_label(NULL, hbox, FALSE, PIXEL_LABEL_WIDTH, TRUE);
816         if (lw->options.info_pixel_hidden) gtk_widget_hide(gtk_widget_get_parent(lw->info_pixel));
817         lw->info_zoom = layout_status_label(NULL, hbox, FALSE, ZOOM_LABEL_WIDTH, FALSE);
818 }
819
820 /*
821  *-----------------------------------------------------------------------------
822  * views
823  *-----------------------------------------------------------------------------
824  */
825
826 static GtkWidget *layout_tools_new(LayoutWindow *lw)
827 {
828         lw->dir_view = layout_tool_setup(lw);
829         return lw->dir_view;
830 }
831
832 static void layout_list_status_cb(ViewFile *vf, gpointer data)
833 {
834         LayoutWindow *lw = data;
835
836         layout_status_update_info(lw, NULL);
837 }
838
839 static void layout_list_thumb_cb(ViewFile *vf, gdouble val, const gchar *text, gpointer data)
840 {
841         LayoutWindow *lw = data;
842
843         layout_status_update_progress(lw, val, text);
844 }
845
846 static GtkWidget *layout_list_new(LayoutWindow *lw)
847 {
848         lw->vf = vf_new(lw->options.file_view_type, NULL);
849         vf_set_layout(lw->vf, lw);
850
851         vf_set_status_func(lw->vf, layout_list_status_cb, lw);
852         vf_set_thumb_status_func(lw->vf, layout_list_thumb_cb, lw);
853
854         vf_marks_set(lw->vf, lw->options.show_marks);
855
856         switch (lw->options.file_view_type)
857         {
858         case FILEVIEW_ICON:
859                 break;
860         case FILEVIEW_LIST:
861                 vf_thumb_set(lw->vf, lw->options.show_thumbnails);
862                 break;
863         }
864
865         return lw->vf->widget;
866 }
867
868 static void layout_list_sync_thumb(LayoutWindow *lw)
869 {
870         if (lw->vf) vf_thumb_set(lw->vf, lw->options.show_thumbnails);
871 }
872
873 static void layout_list_sync_marks(LayoutWindow *lw)
874 {
875         if (lw->vf) vf_marks_set(lw->vf, lw->options.show_marks);
876 }
877
878 static void layout_list_scroll_to_subpart(LayoutWindow *lw, const gchar *needle)
879 {
880         if (!lw) return;
881 #if 0
882         if (lw->vf) vf_scroll_to_subpart(lw->vf, needle);
883 #endif
884 }
885
886 GList *layout_list(LayoutWindow *lw)
887 {
888         if (!layout_valid(&lw)) return NULL;
889
890         if (lw->vf) return vf_get_list(lw->vf);
891
892         return NULL;
893 }
894
895 guint layout_list_count(LayoutWindow *lw, gint64 *bytes)
896 {
897         if (!layout_valid(&lw)) return 0;
898
899         if (lw->vf) return vf_count(lw->vf, bytes);
900
901         return 0;
902 }
903
904 FileData *layout_list_get_fd(LayoutWindow *lw, gint index)
905 {
906         if (!layout_valid(&lw)) return NULL;
907
908         if (lw->vf) return vf_index_get_data(lw->vf, index);
909
910         return NULL;
911 }
912
913 gint layout_list_get_index(LayoutWindow *lw, FileData *fd)
914 {
915         if (!layout_valid(&lw) || !fd) return -1;
916
917         if (lw->vf) return vf_index_by_path(lw->vf, fd->path);
918
919         return -1;
920 }
921
922 void layout_list_sync_fd(LayoutWindow *lw, FileData *fd)
923 {
924         if (!layout_valid(&lw)) return;
925
926         if (lw->vf) vf_select_by_fd(lw->vf, fd);
927 }
928
929 static void layout_list_sync_sort(LayoutWindow *lw)
930 {
931         if (!layout_valid(&lw)) return;
932
933         if (lw->vf) vf_sort_set(lw->vf, lw->sort_method, lw->sort_ascend);
934 }
935
936 GList *layout_selection_list(LayoutWindow *lw)
937 {
938         if (!layout_valid(&lw)) return NULL;
939
940         if (layout_image_get_collection(lw, NULL))
941                 {
942                 FileData *fd;
943
944                 fd = layout_image_get_fd(lw);
945                 if (fd) return g_list_append(NULL, file_data_ref(fd));
946                 return NULL;
947                 }
948
949         if (lw->vf) return vf_selection_get_list(lw->vf);
950
951         return NULL;
952 }
953
954 GList *layout_selection_list_by_index(LayoutWindow *lw)
955 {
956         if (!layout_valid(&lw)) return NULL;
957
958         if (lw->vf) return vf_selection_get_list_by_index(lw->vf);
959
960         return NULL;
961 }
962
963 guint layout_selection_count(LayoutWindow *lw, gint64 *bytes)
964 {
965         if (!layout_valid(&lw)) return 0;
966
967         if (lw->vf) return vf_selection_count(lw->vf, bytes);
968
969         return 0;
970 }
971
972 void layout_select_all(LayoutWindow *lw)
973 {
974         if (!layout_valid(&lw)) return;
975
976         if (lw->vf) vf_select_all(lw->vf);
977 }
978
979 void layout_select_none(LayoutWindow *lw)
980 {
981         if (!layout_valid(&lw)) return;
982
983         if (lw->vf) vf_select_none(lw->vf);
984 }
985
986 void layout_select_invert(LayoutWindow *lw)
987 {
988         if (!layout_valid(&lw)) return;
989
990         if (lw->vf) vf_select_invert(lw->vf);
991 }
992
993 void layout_mark_to_selection(LayoutWindow *lw, gint mark, MarkToSelectionMode mode)
994 {
995         if (!layout_valid(&lw)) return;
996
997         if (lw->vf) vf_mark_to_selection(lw->vf, mark, mode);
998 }
999
1000 void layout_selection_to_mark(LayoutWindow *lw, gint mark, SelectionToMarkMode mode)
1001 {
1002         if (!layout_valid(&lw)) return;
1003
1004         if (lw->vf) vf_selection_to_mark(lw->vf, mark, mode);
1005
1006         layout_status_update_info(lw, NULL); /* osd in fullscreen mode */
1007 }
1008
1009 /*
1010  *-----------------------------------------------------------------------------
1011  * access
1012  *-----------------------------------------------------------------------------
1013  */
1014
1015 const gchar *layout_get_path(LayoutWindow *lw)
1016 {
1017         if (!layout_valid(&lw)) return NULL;
1018         return lw->dir_fd ? lw->dir_fd->path : NULL;
1019 }
1020
1021 static void layout_sync_path(LayoutWindow *lw)
1022 {
1023         if (!lw->dir_fd) return;
1024
1025         if (lw->path_entry) gtk_entry_set_text(GTK_ENTRY(lw->path_entry), lw->dir_fd->path);
1026
1027         if (lw->vd) vd_set_fd(lw->vd, lw->dir_fd);
1028         if (lw->vf) vf_set_fd(lw->vf, lw->dir_fd);
1029 }
1030
1031 gboolean layout_set_path(LayoutWindow *lw, const gchar *path)
1032 {
1033         FileData *fd;
1034         gboolean ret;
1035
1036         if (!path) return FALSE;
1037         
1038         fd = file_data_new_simple(path);
1039         ret = layout_set_fd(lw, fd);
1040         file_data_unref(fd);
1041         return ret;
1042 }
1043
1044
1045 gboolean layout_set_fd(LayoutWindow *lw, FileData *fd)
1046 {
1047         gboolean have_file = FALSE;
1048
1049         if (!layout_valid(&lw)) return FALSE;
1050
1051         if (!fd || !isname(fd->path)) return FALSE;
1052         if (lw->dir_fd && fd == lw->dir_fd)
1053                 {
1054                 return TRUE;
1055                 }
1056
1057         if (isdir(fd->path))
1058                 {
1059                 if (lw->dir_fd)
1060                         {
1061                         file_data_unregister_real_time_monitor(lw->dir_fd);
1062                         file_data_unref(lw->dir_fd);
1063                         }
1064                 lw->dir_fd = file_data_ref(fd);
1065                 file_data_register_real_time_monitor(fd);
1066                 }
1067         else
1068                 {
1069                 gchar *base;
1070
1071                 base = remove_level_from_path(fd->path);
1072                 if (lw->dir_fd && strcmp(lw->dir_fd->path, base) == 0)
1073                         {
1074                         g_free(base);
1075                         }
1076                 else if (isdir(base))
1077                         {
1078                         if (lw->dir_fd)
1079                                 {
1080                                 file_data_unregister_real_time_monitor(lw->dir_fd);
1081                                 file_data_unref(lw->dir_fd);
1082                                 }
1083                         lw->dir_fd = file_data_new_simple(base);
1084                         file_data_register_real_time_monitor(lw->dir_fd);
1085                         g_free(base);
1086                         }
1087                 else
1088                         {
1089                         g_free(base);
1090                         return FALSE;
1091                         }
1092                 if (isfile(fd->path)) have_file = TRUE;
1093                 }
1094
1095         if (lw->path_entry) tab_completion_append_to_history(lw->path_entry, lw->dir_fd->path);
1096         layout_sync_path(lw);
1097         layout_list_sync_sort(lw);
1098         
1099         if (have_file)
1100                 {
1101                 gint row;
1102
1103                 row = layout_list_get_index(lw, fd);
1104                 if (row >= 0)
1105                         {
1106                         layout_image_set_index(lw, row);
1107                         }
1108                 else
1109                         {
1110                         layout_image_set_fd(lw, fd);
1111                         }
1112                 }
1113         else if (!options->lazy_image_sync)
1114                 {
1115                 layout_image_set_index(lw, 0);
1116                 }
1117
1118         if (options->metadata.confirm_on_dir_change)
1119                 metadata_write_queue_confirm(NULL, NULL);
1120
1121         return TRUE;
1122 }
1123
1124 static void layout_refresh_lists(LayoutWindow *lw)
1125 {
1126         if (lw->vd) vd_refresh(lw->vd);
1127
1128         if (lw->vf) vf_refresh(lw->vf);
1129 }
1130
1131 void layout_refresh(LayoutWindow *lw)
1132 {
1133         if (!layout_valid(&lw)) return;
1134
1135         DEBUG_1("layout refresh");
1136
1137         layout_refresh_lists(lw);
1138
1139         if (lw->image) layout_image_refresh(lw);
1140 }
1141
1142 void layout_thumb_set(LayoutWindow *lw, gboolean enable)
1143 {
1144         if (!layout_valid(&lw)) return;
1145
1146         if (lw->options.show_thumbnails == enable) return;
1147
1148         lw->options.show_thumbnails = enable;
1149
1150         layout_util_sync_thumb(lw);
1151         layout_list_sync_thumb(lw);
1152 }
1153
1154 void layout_marks_set(LayoutWindow *lw, gboolean enable)
1155 {
1156         if (!layout_valid(&lw)) return;
1157
1158         if (lw->options.show_marks == enable) return;
1159
1160         lw->options.show_marks = enable;
1161
1162 //      layout_util_sync_marks(lw);
1163         layout_list_sync_marks(lw);
1164 }
1165
1166 gboolean layout_thumb_get(LayoutWindow *lw)
1167 {
1168         if (!layout_valid(&lw)) return FALSE;
1169
1170         return lw->options.show_thumbnails;
1171 }
1172
1173 gboolean layout_marks_get(LayoutWindow *lw)
1174 {
1175         if (!layout_valid(&lw)) return FALSE;
1176
1177         return lw->options.show_marks;
1178 }
1179
1180 void layout_sort_set(LayoutWindow *lw, SortType type, gboolean ascend)
1181 {
1182         if (!layout_valid(&lw)) return;
1183         if (lw->sort_method == type && lw->sort_ascend == ascend) return;
1184
1185         lw->sort_method = type;
1186         lw->sort_ascend = ascend;
1187
1188         if (lw->info_sort) gtk_label_set_text(GTK_LABEL(GTK_BIN(lw->info_sort)->child),
1189                                               sort_type_get_text(type));
1190         layout_list_sync_sort(lw);
1191 }
1192
1193 gboolean layout_sort_get(LayoutWindow *lw, SortType *type, gboolean *ascend)
1194 {
1195         if (!layout_valid(&lw)) return FALSE;
1196
1197         if (type) *type = lw->sort_method;
1198         if (ascend) *ascend = lw->sort_ascend;
1199
1200         return TRUE;
1201 }
1202
1203 gboolean layout_geometry_get(LayoutWindow *lw, gint *x, gint *y, gint *w, gint *h)
1204 {
1205         if (!layout_valid(&lw)) return FALSE;
1206
1207         gdk_window_get_root_origin(lw->window->window, x, y);
1208         gdk_drawable_get_size(lw->window->window, w, h);
1209
1210         return TRUE;
1211 }
1212
1213 gboolean layout_geometry_get_dividers(LayoutWindow *lw, gint *h, gint *v)
1214 {
1215         if (!layout_valid(&lw)) return FALSE;
1216
1217         if (lw->h_pane && GTK_PANED(lw->h_pane)->child1->allocation.x >= 0)
1218                 {
1219                 *h = GTK_PANED(lw->h_pane)->child1->allocation.width;
1220                 }
1221         else if (h != &lw->options.main_window.hdivider_pos)
1222                 {
1223                 *h = lw->options.main_window.hdivider_pos;
1224                 }
1225
1226         if (lw->v_pane && GTK_PANED(lw->v_pane)->child1->allocation.x >= 0)
1227                 {
1228                 *v = GTK_PANED(lw->v_pane)->child1->allocation.height;
1229                 }
1230         else if (v != &lw->options.main_window.vdivider_pos)
1231                 {
1232                 *v = lw->options.main_window.vdivider_pos;
1233                 }
1234
1235         return TRUE;
1236 }
1237
1238 void layout_views_set(LayoutWindow *lw, DirViewType dir_view_type, FileViewType file_view_type)
1239 {
1240         if (!layout_valid(&lw)) return;
1241
1242         if (lw->options.dir_view_type == dir_view_type && lw->options.file_view_type == file_view_type) return;
1243
1244         lw->options.dir_view_type = dir_view_type;
1245         lw->options.file_view_type = file_view_type;
1246
1247         layout_style_set(lw, -1, NULL);
1248 }
1249
1250 gboolean layout_views_get(LayoutWindow *lw, DirViewType *dir_view_type, FileViewType *file_view_type)
1251 {
1252         if (!layout_valid(&lw)) return FALSE;
1253
1254         *dir_view_type = lw->options.dir_view_type;
1255         *file_view_type = lw->options.file_view_type;
1256
1257         return TRUE;
1258 }
1259
1260 /*
1261  *-----------------------------------------------------------------------------
1262  * location utils
1263  *-----------------------------------------------------------------------------
1264  */
1265
1266 static gboolean layout_location_single(LayoutLocation l)
1267 {
1268         return (l == LAYOUT_LEFT ||
1269                 l == LAYOUT_RIGHT ||
1270                 l == LAYOUT_TOP ||
1271                 l == LAYOUT_BOTTOM);
1272 }
1273
1274 static gboolean layout_location_vertical(LayoutLocation l)
1275 {
1276         return (l & LAYOUT_TOP ||
1277                 l & LAYOUT_BOTTOM);
1278 }
1279
1280 static gboolean layout_location_first(LayoutLocation l)
1281 {
1282         return (l & LAYOUT_TOP ||
1283                 l & LAYOUT_LEFT);
1284 }
1285
1286 static LayoutLocation layout_grid_compass(LayoutWindow *lw)
1287 {
1288         if (layout_location_single(lw->dir_location)) return lw->dir_location;
1289         if (layout_location_single(lw->file_location)) return lw->file_location;
1290         return lw->image_location;
1291 }
1292
1293 static void layout_location_compute(LayoutLocation l1, LayoutLocation l2,
1294                                     GtkWidget *s1, GtkWidget *s2,
1295                                     GtkWidget **d1, GtkWidget **d2)
1296 {
1297         LayoutLocation l;
1298
1299         l = l1 & l2;    /* get common compass direction */
1300         l = l1 - l;     /* remove it */
1301
1302         if (layout_location_first(l))
1303                 {
1304                 *d1 = s1;
1305                 *d2 = s2;
1306                 }
1307         else
1308                 {
1309                 *d1 = s2;
1310                 *d2 = s1;
1311                 }
1312 }
1313
1314 /*
1315  *-----------------------------------------------------------------------------
1316  * tools window (for floating/hidden)
1317  *-----------------------------------------------------------------------------
1318  */
1319
1320 gboolean layout_geometry_get_tools(LayoutWindow *lw, gint *x, gint *y, gint *w, gint *h, gint *divider_pos)
1321 {
1322         if (!layout_valid(&lw)) return FALSE;
1323
1324         if (!lw->tools || !GTK_WIDGET_VISIBLE(lw->tools))
1325                 {
1326                 /* use the stored values (sort of breaks success return value) */
1327
1328                 *divider_pos = lw->options.float_window.vdivider_pos;
1329
1330                 return FALSE;
1331                 }
1332
1333         gdk_window_get_root_origin(lw->tools->window, x, y);
1334         gdk_drawable_get_size(lw->tools->window, w, h);
1335
1336         if (GTK_IS_VPANED(lw->tools_pane))
1337                 {
1338                 *divider_pos = GTK_PANED(lw->tools_pane)->child1->allocation.height;
1339                 }
1340         else
1341                 {
1342                 *divider_pos = GTK_PANED(lw->tools_pane)->child1->allocation.width;
1343                 }
1344
1345         return TRUE;
1346 }
1347
1348 static void layout_tools_geometry_sync(LayoutWindow *lw)
1349 {
1350         layout_geometry_get_tools(lw, &lw->options.float_window.x, &lw->options.float_window.x,
1351                                   &lw->options.float_window.w, &lw->options.float_window.h, &lw->options.float_window.vdivider_pos);
1352 }
1353
1354 static void layout_tools_hide(LayoutWindow *lw, gboolean hide)
1355 {
1356         if (!lw->tools) return;
1357
1358         if (hide)
1359                 {
1360                 if (GTK_WIDGET_VISIBLE(lw->tools))
1361                         {
1362                         layout_tools_geometry_sync(lw);
1363                         gtk_widget_hide(lw->tools);
1364                         }
1365                 }
1366         else
1367                 {
1368                 if (!GTK_WIDGET_VISIBLE(lw->tools))
1369                         {
1370                         gtk_widget_show(lw->tools);
1371                         if (lw->vf) vf_refresh(lw->vf);
1372                         }
1373                 }
1374
1375         lw->options.tools_hidden = hide;
1376 }
1377
1378 static gboolean layout_tools_delete_cb(GtkWidget *widget, GdkEventAny *event, gpointer data)
1379 {
1380         LayoutWindow *lw = data;
1381
1382         layout_tools_float_toggle(lw);
1383
1384         return TRUE;
1385 }
1386
1387 static void layout_tools_setup(LayoutWindow *lw, GtkWidget *tools, GtkWidget *files)
1388 {
1389         GtkWidget *vbox;
1390         GtkWidget *w1, *w2;
1391         gboolean vertical;
1392         gboolean new_window = FALSE;
1393
1394         vertical = (layout_location_single(lw->image_location) && !layout_location_vertical(lw->image_location)) ||
1395                    (!layout_location_single(lw->image_location) && layout_location_vertical(layout_grid_compass(lw)));
1396 #if 0
1397         layout_location_compute(lw->dir_location, lw->file_location,
1398                                 tools, files, &w1, &w2);
1399 #endif
1400         /* for now, tools/dir are always first in order */
1401         w1 = tools;
1402         w2 = files;
1403
1404         if (!lw->tools)
1405                 {
1406                 GdkGeometry geometry;
1407                 GdkWindowHints hints;
1408
1409                 lw->tools = window_new(GTK_WINDOW_TOPLEVEL, "tools", PIXBUF_INLINE_ICON_TOOLS, NULL, _("Tools"));
1410                 g_signal_connect(G_OBJECT(lw->tools), "delete_event",
1411                                  G_CALLBACK(layout_tools_delete_cb), lw);
1412                 layout_keyboard_init(lw, lw->tools);
1413
1414                 if (options->save_window_positions)
1415                         {
1416                         hints = GDK_HINT_USER_POS;
1417                         }
1418                 else
1419                         {
1420                         hints = 0;
1421                         }
1422
1423                 geometry.min_width = DEFAULT_MINIMAL_WINDOW_SIZE;
1424                 geometry.min_height = DEFAULT_MINIMAL_WINDOW_SIZE;
1425                 geometry.base_width = TOOLWINDOW_DEF_WIDTH;
1426                 geometry.base_height = TOOLWINDOW_DEF_HEIGHT;
1427                 gtk_window_set_geometry_hints(GTK_WINDOW(lw->tools), NULL, &geometry,
1428                                               GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | hints);
1429
1430
1431                 gtk_window_set_resizable(GTK_WINDOW(lw->tools), TRUE);
1432                 gtk_container_set_border_width(GTK_CONTAINER(lw->tools), 0);
1433
1434                 new_window = TRUE;
1435                 }
1436         else
1437                 {
1438                 layout_tools_geometry_sync(lw);
1439                 /* dump the contents */
1440                 gtk_widget_destroy(GTK_BIN(lw->tools)->child);
1441                 }
1442
1443         layout_actions_add_window(lw, lw->tools);
1444
1445         vbox = gtk_vbox_new(FALSE, 0);
1446         gtk_container_add(GTK_CONTAINER(lw->tools), vbox);
1447         gtk_widget_show(vbox);
1448
1449         layout_status_setup(lw, vbox, TRUE);
1450
1451         if (vertical)
1452                 {
1453                 lw->tools_pane = gtk_vpaned_new();
1454                 }
1455         else
1456                 {
1457                 lw->tools_pane = gtk_hpaned_new();
1458                 }
1459         gtk_box_pack_start(GTK_BOX(vbox), lw->tools_pane, TRUE, TRUE, 0);
1460         gtk_widget_show(lw->tools_pane);
1461
1462         gtk_paned_pack1(GTK_PANED(lw->tools_pane), w1, FALSE, TRUE);
1463         gtk_paned_pack2(GTK_PANED(lw->tools_pane), w2, TRUE, TRUE);
1464
1465         gtk_widget_show(tools);
1466         gtk_widget_show(files);
1467
1468         if (new_window)
1469                 {
1470                 if (options->save_window_positions)
1471                         {
1472                         gtk_window_set_default_size(GTK_WINDOW(lw->tools), lw->options.float_window.w, lw->options.float_window.h);
1473                         gtk_window_move(GTK_WINDOW(lw->tools), lw->options.float_window.x, lw->options.float_window.y);
1474                         }
1475                 else
1476                         {
1477                         if (vertical)
1478                                 {
1479                                 gtk_window_set_default_size(GTK_WINDOW(lw->tools),
1480                                                             TOOLWINDOW_DEF_WIDTH, TOOLWINDOW_DEF_HEIGHT);
1481                                 }
1482                         else
1483                                 {
1484                                 gtk_window_set_default_size(GTK_WINDOW(lw->tools),
1485                                                             TOOLWINDOW_DEF_HEIGHT, TOOLWINDOW_DEF_WIDTH);
1486                                 }
1487                         }
1488                 }
1489
1490         if (!options->save_window_positions)
1491                 {
1492                 if (vertical)
1493                         {
1494                         lw->options.float_window.vdivider_pos = MAIN_WINDOW_DIV_VPOS;
1495                         }
1496                 else
1497                         {
1498                         lw->options.float_window.vdivider_pos = MAIN_WINDOW_DIV_HPOS;
1499                         }
1500                 }
1501
1502         gtk_paned_set_position(GTK_PANED(lw->tools_pane), lw->options.float_window.vdivider_pos);
1503 }
1504
1505 /*
1506  *-----------------------------------------------------------------------------
1507  * glue (layout arrangement)
1508  *-----------------------------------------------------------------------------
1509  */
1510
1511 static void layout_grid_compute(LayoutWindow *lw,
1512                                 GtkWidget *image, GtkWidget *tools, GtkWidget *files,
1513                                 GtkWidget **w1, GtkWidget **w2, GtkWidget **w3)
1514 {
1515         /* heh, this was fun */
1516
1517         if (layout_location_single(lw->dir_location))
1518                 {
1519                 if (layout_location_first(lw->dir_location))
1520                         {
1521                         *w1 = tools;
1522                         layout_location_compute(lw->file_location, lw->image_location, files, image, w2, w3);
1523                         }
1524                 else
1525                         {
1526                         *w3 = tools;
1527                         layout_location_compute(lw->file_location, lw->image_location, files, image, w1, w2);
1528                         }
1529                 }
1530         else if (layout_location_single(lw->file_location))
1531                 {
1532                 if (layout_location_first(lw->file_location))
1533                         {
1534                         *w1 = files;
1535                         layout_location_compute(lw->dir_location, lw->image_location, tools, image, w2, w3);
1536                         }
1537                 else
1538                         {
1539                         *w3 = files;
1540                         layout_location_compute(lw->dir_location, lw->image_location, tools, image, w1, w2);
1541                         }
1542                 }
1543         else
1544                 {
1545                 /* image */
1546                 if (layout_location_first(lw->image_location))
1547                         {
1548                         *w1 = image;
1549                         layout_location_compute(lw->file_location, lw->dir_location, files, tools, w2, w3);
1550                         }
1551                 else
1552                         {
1553                         *w3 = image;
1554                         layout_location_compute(lw->file_location, lw->dir_location, files, tools, w1, w2);
1555                         }
1556                 }
1557 }
1558
1559 void layout_split_change(LayoutWindow *lw, ImageSplitMode mode)
1560 {
1561         GtkWidget *image;
1562         gint i;
1563
1564         for (i = 0; i < MAX_SPLIT_IMAGES; i++)
1565                 {
1566                 if (lw->split_images[i])
1567                         {
1568                         gtk_widget_hide(lw->split_images[i]->widget);
1569                         if (lw->split_images[i]->widget->parent != lw->utility_paned)
1570                                 gtk_container_remove(GTK_CONTAINER(lw->split_images[i]->widget->parent), lw->split_images[i]->widget);
1571                         }
1572                 }
1573         gtk_container_remove(GTK_CONTAINER(lw->utility_paned), lw->split_image_widget);
1574
1575         image = layout_image_setup_split(lw, mode);
1576
1577 //      gtk_box_pack_start(GTK_BOX(lw->utility_box), image, TRUE, TRUE, 0);
1578 //      gtk_box_reorder_child(GTK_BOX(lw->utility_box), image, 0);
1579         gtk_paned_pack1(GTK_PANED(lw->utility_paned), image, TRUE, FALSE);
1580         gtk_widget_show(image);
1581 }
1582
1583 static void layout_grid_setup(LayoutWindow *lw)
1584 {
1585         gint priority_location;
1586         GtkWidget *h;
1587         GtkWidget *v;
1588         GtkWidget *w1, *w2, *w3;
1589
1590         GtkWidget *image_sb; /* image together with sidebars in utility box */
1591         GtkWidget *tools;
1592         GtkWidget *files;
1593
1594         layout_actions_setup(lw);
1595         layout_actions_add_window(lw, lw->window);
1596
1597         lw->group_box = gtk_vbox_new(FALSE, 0);
1598         gtk_box_pack_start(GTK_BOX(lw->main_box), lw->group_box, TRUE, TRUE, 0);
1599         gtk_widget_show(lw->group_box);
1600
1601         priority_location = layout_grid_compass(lw);
1602
1603         if (lw->utility_box)
1604                 {
1605                 image_sb = lw->utility_box;
1606                 }
1607         else
1608                 {
1609                 GtkWidget *image; /* image or split images together */
1610                 image = layout_image_setup_split(lw, lw->split_mode);
1611                 image_sb = layout_bars_prepare(lw, image);
1612                 }
1613         
1614         tools = layout_tools_new(lw);
1615         files = layout_list_new(lw);
1616
1617
1618         if (lw->options.tools_float || lw->options.tools_hidden)
1619                 {
1620                 gtk_box_pack_start(GTK_BOX(lw->group_box), image_sb, TRUE, TRUE, 0);
1621                 gtk_widget_show(image_sb);
1622
1623                 layout_tools_setup(lw, tools, files);
1624
1625                 gtk_widget_grab_focus(lw->image->widget);
1626
1627                 return;
1628                 }
1629         else if (lw->tools)
1630                 {
1631                 layout_tools_geometry_sync(lw);
1632                 gtk_widget_destroy(lw->tools);
1633                 lw->tools = NULL;
1634                 lw->tools_pane = NULL;
1635                 }
1636
1637         layout_status_setup(lw, lw->group_box, FALSE);
1638
1639         layout_grid_compute(lw, image_sb, tools, files, &w1, &w2, &w3);
1640
1641         v = lw->v_pane = gtk_vpaned_new();
1642
1643         h = lw->h_pane = gtk_hpaned_new();
1644
1645         if (!layout_location_vertical(priority_location))
1646                 {
1647                 GtkWidget *tmp;
1648
1649                 tmp = v;
1650                 v = h;
1651                 h = tmp;
1652                 }
1653
1654         gtk_box_pack_start(GTK_BOX(lw->group_box), v, TRUE, TRUE, 0);
1655
1656         if (!layout_location_first(priority_location))
1657                 {
1658                 gtk_paned_pack1(GTK_PANED(v), h, FALSE, TRUE);
1659                 gtk_paned_pack2(GTK_PANED(v), w3, TRUE, TRUE);
1660
1661                 gtk_paned_pack1(GTK_PANED(h), w1, FALSE, TRUE);
1662                 gtk_paned_pack2(GTK_PANED(h), w2, TRUE, TRUE);
1663                 }
1664         else
1665                 {
1666                 gtk_paned_pack1(GTK_PANED(v), w1, FALSE, TRUE);
1667                 gtk_paned_pack2(GTK_PANED(v), h, TRUE, TRUE);
1668
1669                 gtk_paned_pack1(GTK_PANED(h), w2, FALSE, TRUE);
1670                 gtk_paned_pack2(GTK_PANED(h), w3, TRUE, TRUE);
1671                 }
1672
1673         gtk_widget_show(image_sb);
1674         gtk_widget_show(tools);
1675         gtk_widget_show(files);
1676
1677         gtk_widget_show(v);
1678         gtk_widget_show(h);
1679
1680         /* fix to have image pane visible when it is left and priority widget */
1681         if (lw->options.main_window.hdivider_pos == -1 &&
1682             w1 == image_sb &&
1683             !layout_location_vertical(priority_location) &&
1684             layout_location_first(priority_location))
1685                 {
1686                 gtk_widget_set_size_request(image_sb, 200, -1);
1687                 }
1688
1689         gtk_paned_set_position(GTK_PANED(lw->h_pane), lw->options.main_window.hdivider_pos);
1690         gtk_paned_set_position(GTK_PANED(lw->v_pane), lw->options.main_window.vdivider_pos);
1691
1692         gtk_widget_grab_focus(lw->image->widget);
1693 }
1694
1695 void layout_style_set(LayoutWindow *lw, gint style, const gchar *order)
1696 {
1697         FileData *dir_fd;
1698
1699         if (!layout_valid(&lw)) return;
1700
1701         if (style != -1)
1702                 {
1703                 LayoutLocation d, f, i;
1704
1705                 layout_config_parse(style, order, &d,  &f, &i);
1706
1707                 if (lw->dir_location == d &&
1708                     lw->file_location == f &&
1709                     lw->image_location == i) return;
1710
1711                 lw->dir_location = d;
1712                 lw->file_location = f;
1713                 lw->image_location = i;
1714                 }
1715
1716         /* remember state */
1717
1718         layout_image_slideshow_stop(lw);
1719         layout_image_full_screen_stop(lw);
1720
1721         dir_fd = lw->dir_fd;
1722         if (dir_fd) file_data_unregister_real_time_monitor(dir_fd);
1723         lw->dir_fd = NULL;
1724
1725         layout_geometry_get_dividers(lw, &lw->options.main_window.hdivider_pos, &lw->options.main_window.vdivider_pos);
1726
1727         /* lw->image is preserved together with lw->utility_box */
1728         if (lw->utility_box)
1729                 {
1730                 /* preserve utility_box (image + sidebars) to be reused later in layout_grid_setup */
1731                 gtk_widget_hide(lw->utility_box);
1732                 g_object_ref(lw->utility_box);
1733                 gtk_container_remove(GTK_CONTAINER(lw->utility_box->parent), lw->utility_box);
1734                 }
1735
1736         /* clear it all */
1737
1738         lw->h_pane = NULL;
1739         lw->v_pane = NULL;
1740
1741         lw->toolbar = NULL;
1742         lw->path_entry = NULL;
1743         lw->dir_view = NULL;
1744         lw->vd = NULL;
1745
1746         lw->file_view = NULL;
1747         lw->vf = NULL;
1748
1749         lw->info_box = NULL;
1750         lw->info_progress_bar = NULL;
1751         lw->info_sort = NULL;
1752         lw->info_color = NULL;
1753         lw->info_status = NULL;
1754         lw->info_details = NULL;
1755         lw->info_pixel = NULL;
1756         lw->info_zoom = NULL;
1757
1758         if (lw->ui_manager) g_object_unref(lw->ui_manager);
1759         lw->ui_manager = NULL;
1760         lw->action_group = NULL;
1761         lw->action_group_editors = NULL;
1762
1763         gtk_container_remove(GTK_CONTAINER(lw->main_box), lw->group_box);
1764         lw->group_box = NULL;
1765
1766         /* re-fill */
1767
1768         layout_grid_setup(lw);
1769         layout_tools_hide(lw, lw->options.tools_hidden);
1770
1771         layout_util_sync(lw);
1772         layout_status_update_all(lw);
1773
1774         /* sync */
1775
1776         if (image_get_fd(lw->image))
1777                 {
1778                 layout_set_fd(lw, image_get_fd(lw->image));
1779                 }
1780         else
1781                 {
1782                 layout_set_fd(lw, dir_fd);
1783                 }
1784         image_top_window_set_sync(lw->image, (lw->options.tools_float || lw->options.tools_hidden));
1785
1786         /* clean up */
1787
1788         file_data_unref(dir_fd);
1789 }
1790
1791 void layout_colors_update(void)
1792 {
1793         GList *work;
1794
1795         work = layout_window_list;
1796         while (work)
1797                 {
1798                 LayoutWindow *lw = work->data;
1799                 work = work->next;
1800
1801                 if (!lw->image) continue;
1802                 image_background_set_color(lw->image, options->image.use_custom_border_color ? &options->image.border_color : NULL);
1803                 }
1804 }
1805
1806 void layout_tools_float_toggle(LayoutWindow *lw)
1807 {
1808         gboolean popped;
1809
1810         if (!lw) return;
1811
1812         if (!lw->options.tools_hidden)
1813                 {
1814                 popped = !lw->options.tools_float;
1815                 }
1816         else
1817                 {
1818                 popped = TRUE;
1819                 }
1820
1821         if (lw->options.tools_float == popped)
1822                 {
1823                 if (popped && lw->options.tools_hidden)
1824                         {
1825                         layout_tools_float_set(lw, popped, FALSE);
1826                         }
1827                 }
1828         else
1829                 {
1830                 if (lw->options.tools_float)
1831                         {
1832                         layout_tools_float_set(lw, FALSE, FALSE);
1833                         }
1834                 else
1835                         {
1836                         layout_tools_float_set(lw, TRUE, FALSE);
1837                         }
1838                 }
1839 }
1840
1841 void layout_tools_hide_toggle(LayoutWindow *lw)
1842 {
1843         if (!lw) return;
1844
1845         layout_tools_float_set(lw, lw->options.tools_float, !lw->options.tools_hidden);
1846 }
1847
1848 void layout_tools_float_set(LayoutWindow *lw, gboolean popped, gboolean hidden)
1849 {
1850         if (!layout_valid(&lw)) return;
1851
1852         if (lw->options.tools_float == popped && lw->options.tools_hidden == hidden) return;
1853
1854         if (lw->options.tools_float == popped && lw->options.tools_float && lw->tools)
1855                 {
1856                 layout_tools_hide(lw, hidden);
1857                 return;
1858                 }
1859
1860         lw->options.tools_float = popped;
1861         lw->options.tools_hidden = hidden;
1862
1863         layout_style_set(lw, -1, NULL);
1864 }
1865
1866 gboolean layout_tools_float_get(LayoutWindow *lw, gboolean *popped, gboolean *hidden)
1867 {
1868         if (!layout_valid(&lw)) return FALSE;
1869
1870         *popped = lw->options.tools_float;
1871         *hidden = lw->options.tools_hidden;
1872
1873         return TRUE;
1874 }
1875
1876 void layout_toolbar_toggle(LayoutWindow *lw)
1877 {
1878         if (!layout_valid(&lw)) return;
1879         if (!lw->toolbar) return;
1880
1881         lw->options.toolbar_hidden = !lw->options.toolbar_hidden;
1882
1883         if (lw->options.toolbar_hidden)
1884                 {
1885                 if (GTK_WIDGET_VISIBLE(lw->toolbar)) gtk_widget_hide(lw->toolbar);
1886                 }
1887         else
1888                 {
1889                 if (!GTK_WIDGET_VISIBLE(lw->toolbar)) gtk_widget_show(lw->toolbar);
1890                 }
1891 }
1892
1893 void layout_info_pixel_toggle(LayoutWindow *lw)
1894 {
1895         GtkWidget *frame;
1896         
1897         if (!layout_valid(&lw)) return;
1898         if (!lw->info_pixel) return;
1899
1900         lw->options.info_pixel_hidden = !lw->options.info_pixel_hidden;
1901
1902         frame = gtk_widget_get_parent(lw->info_pixel);
1903         if (lw->options.info_pixel_hidden)
1904                 {
1905                 if (GTK_WIDGET_VISIBLE(frame)) gtk_widget_hide(frame);
1906                 }
1907         else
1908                 {
1909                 if (!GTK_WIDGET_VISIBLE(frame)) gtk_widget_show(frame);
1910                 }
1911 }
1912
1913 /*
1914  *-----------------------------------------------------------------------------
1915  * configuration
1916  *-----------------------------------------------------------------------------
1917  */
1918
1919 #define CONFIG_WINDOW_DEF_WIDTH         600
1920 #define CONFIG_WINDOW_DEF_HEIGHT        400
1921
1922 typedef struct _LayoutConfig LayoutConfig;
1923 struct _LayoutConfig
1924 {
1925         LayoutWindow *lw;
1926
1927         GtkWidget *configwindow;
1928         GtkWidget *home_path_entry;
1929         GtkWidget *layout_widget;
1930         
1931         LayoutOptions options;
1932 };
1933
1934 static gint layout_config_delete_cb(GtkWidget *w, GdkEventAny *event, gpointer data);
1935
1936 static void layout_config_close_cb(GtkWidget *widget, gpointer data)
1937 {
1938         LayoutConfig *lc = data;
1939         
1940         gtk_widget_destroy(lc->configwindow);
1941         free_layout_options_content(&lc->options);
1942         g_free(lc);
1943 }
1944
1945 static gint layout_config_delete_cb(GtkWidget *w, GdkEventAny *event, gpointer data)
1946 {
1947         layout_config_close_cb(w, data);
1948         return TRUE;
1949 }
1950
1951 static void layout_config_apply_cb(GtkWidget *widget, gpointer data)
1952 {
1953         LayoutConfig *lc = data;
1954         
1955         g_free(lc->options.order);
1956         lc->options.order = layout_config_get(lc->layout_widget, &lc->options.style);
1957
1958         config_entry_to_option(lc->home_path_entry, &lc->options.home_path, remove_trailing_slash);
1959
1960         layout_apply_options(lc->lw, &lc->options);
1961 }
1962
1963 static void layout_config_ok_cb(GtkWidget *widget, gpointer data)
1964 {
1965         LayoutConfig *lc = data;
1966         layout_config_apply_cb(widget, lc);
1967         layout_config_close_cb(widget, lc);
1968 }
1969
1970 static void home_path_set_current_cb(GtkWidget *widget, gpointer data)
1971 {
1972         LayoutConfig *lc = data;
1973         gtk_entry_set_text(GTK_ENTRY(lc->home_path_entry), layout_get_path(lc->lw));
1974 }
1975
1976 /*
1977 static void layout_config_save_cb(GtkWidget *widget, gpointer data)
1978 {
1979         layout_config_apply();
1980         save_options(options);
1981 }
1982 */
1983
1984 void layout_show_config_window(LayoutWindow *lw)
1985 {
1986         LayoutConfig *lc;
1987         GtkWidget *win_vbox;
1988         GtkWidget *hbox;
1989         GtkWidget *vbox;
1990         GtkWidget *button;
1991         GtkWidget *ct_button;
1992         GtkWidget *group;
1993         GtkWidget *frame;
1994         GtkWidget *tabcomp;
1995
1996         lc = g_new0(LayoutConfig, 1);
1997         lc->lw = lw;
1998         layout_sync_options_with_current_state(lw);
1999         copy_layout_options(&lc->options, &lw->options);
2000
2001         lc->configwindow = window_new(GTK_WINDOW_TOPLEVEL, "Layout", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Window options and layout"));
2002         gtk_window_set_type_hint(GTK_WINDOW(lc->configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
2003
2004         g_signal_connect(G_OBJECT(lc->configwindow), "delete_event",
2005                          G_CALLBACK(layout_config_delete_cb), lc);
2006
2007         gtk_window_set_default_size(GTK_WINDOW(lc->configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
2008         gtk_window_set_resizable(GTK_WINDOW(lc->configwindow), TRUE);
2009         gtk_container_set_border_width(GTK_CONTAINER(lc->configwindow), PREF_PAD_BORDER);
2010
2011         win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
2012         gtk_container_add(GTK_CONTAINER(lc->configwindow), win_vbox);
2013         gtk_widget_show(win_vbox);
2014
2015         hbox = gtk_hbutton_box_new();
2016         gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
2017         gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
2018         gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
2019         gtk_widget_show(hbox);
2020
2021         button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
2022                                  G_CALLBACK(layout_config_ok_cb), lc);
2023         gtk_container_add(GTK_CONTAINER(hbox), button);
2024         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
2025         gtk_widget_grab_default(button);
2026         gtk_widget_show(button);
2027
2028         ct_button = button;
2029 /*
2030         button = pref_button_new(NULL, GTK_STOCK_SAVE, NULL, FALSE,
2031                                  G_CALLBACK(layout_config_save_cb), NULL);
2032         gtk_container_add(GTK_CONTAINER(hbox), button);
2033         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
2034         gtk_widget_show(button);
2035 */      
2036         button = pref_button_new(NULL, GTK_STOCK_APPLY, NULL, FALSE,
2037                                  G_CALLBACK(layout_config_apply_cb), lc);
2038         gtk_container_add(GTK_CONTAINER(hbox), button);
2039         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
2040         gtk_widget_show(button);
2041
2042         button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
2043                                  G_CALLBACK(layout_config_close_cb), lc);
2044         gtk_container_add(GTK_CONTAINER(hbox), button);
2045         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
2046         gtk_widget_show(button);
2047
2048         if (!generic_dialog_get_alternative_button_order(lc->configwindow))
2049                 {
2050                 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
2051                 }
2052
2053         frame = pref_frame_new(win_vbox, TRUE, NULL, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2054         
2055         vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
2056         gtk_container_add(GTK_CONTAINER(frame), vbox);
2057         gtk_widget_show(vbox);
2058
2059         group = pref_group_new(vbox, FALSE, _("General options"), GTK_ORIENTATION_VERTICAL);
2060
2061         pref_label_new(group, _("Home button path (empty to use your home directory)"));
2062         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2063
2064         tabcomp = tab_completion_new(&lc->home_path_entry, lc->options.home_path, NULL, NULL);
2065         tab_completion_add_select_button(lc->home_path_entry, NULL, TRUE);
2066         gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
2067         gtk_widget_show(tabcomp);
2068
2069         button = pref_button_new(hbox, NULL, _("Use current"), FALSE,
2070                                  G_CALLBACK(home_path_set_current_cb), lc);
2071
2072         group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
2073
2074         pref_checkbox_new_int(group, _("Show date in directories list view"),
2075                               lc->options.show_directory_date, &lc->options.show_directory_date);
2076
2077         group = pref_group_new(vbox, FALSE, _("Layout"), GTK_ORIENTATION_VERTICAL);
2078
2079         lc->layout_widget = layout_config_new();
2080         layout_config_set(lc->layout_widget, lw->options.style, lw->options.order);
2081         gtk_box_pack_start(GTK_BOX(group), lc->layout_widget, TRUE, TRUE, 0);
2082
2083         gtk_widget_show(lc->layout_widget);
2084         gtk_widget_show(lc->configwindow);
2085 }
2086
2087 /*
2088  *-----------------------------------------------------------------------------
2089  * base
2090  *-----------------------------------------------------------------------------
2091  */
2092
2093 void layout_sync_options_with_current_state(LayoutWindow *lw)
2094 {
2095         Histogram *histogram;
2096         if (!layout_valid(&lw)) return;
2097
2098         lw->options.main_window.maximized =  window_maximized(lw->window);
2099         if (!lw->options.main_window.maximized)
2100                 {
2101                 layout_geometry_get(lw, &lw->options.main_window.x, &lw->options.main_window.y,
2102                                     &lw->options.main_window.w, &lw->options.main_window.h);
2103                 }
2104
2105         layout_geometry_get_dividers(lw, &lw->options.main_window.hdivider_pos, &lw->options.main_window.vdivider_pos);
2106
2107 //      layout_sort_get(NULL, &options->file_sort.method, &options->file_sort.ascending);
2108
2109         layout_geometry_get_tools(lw, &lw->options.float_window.x, &lw->options.float_window.y,
2110                                   &lw->options.float_window.w, &lw->options.float_window.h, &lw->options.float_window.vdivider_pos);
2111
2112         lw->options.image_overlay.state = image_osd_get(lw->image);
2113         histogram = image_osd_get_histogram(lw->image);
2114         
2115         lw->options.image_overlay.histogram_channel = histogram->histogram_channel;
2116         lw->options.image_overlay.histogram_mode = histogram->histogram_mode;
2117
2118 //      if (options->startup.restore_path && options->startup.use_last_path)
2119 //              {
2120 //              g_free(options->startup.path);
2121 //              options->startup.path = g_strdup(layout_get_path(NULL));
2122 //              }
2123 }
2124
2125 void layout_apply_options(LayoutWindow *lw, LayoutOptions *lop)
2126 {
2127         gboolean refresh_style;
2128         gboolean refresh_lists;
2129
2130         if (!layout_valid(&lw)) return;
2131 /* FIXME: add other options too */
2132
2133         refresh_style = (lop->style != lw->options.style || strcmp(lop->order, lw->options.order) != 0);
2134         refresh_lists = (lop->show_directory_date != lw->options.show_directory_date);
2135
2136         copy_layout_options(&lw->options, lop);
2137
2138         if (refresh_style) layout_style_set(lw, lw->options.style, lw->options.order);
2139         if (refresh_lists) layout_refresh(lw);
2140 }
2141
2142
2143 void layout_close(LayoutWindow *lw)
2144 {
2145         if (layout_window_list && layout_window_list->next)
2146                 {
2147                 layout_free(lw);
2148                 }
2149         else
2150                 {
2151                 exit_program();
2152                 }
2153 }
2154
2155 void layout_free(LayoutWindow *lw)
2156 {
2157         if (!lw) return;
2158
2159         layout_window_list = g_list_remove(layout_window_list, lw);
2160
2161         if (lw->exif_window) g_signal_handlers_disconnect_matched(G_OBJECT(lw->exif_window), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, lw);
2162                 
2163         layout_bars_close(lw);
2164
2165         gtk_widget_destroy(lw->window);
2166         
2167         if (lw->split_image_sizegroup) g_object_unref(lw->split_image_sizegroup);
2168
2169         file_data_unregister_notify_func(layout_image_notify_cb, lw);
2170
2171         if (lw->dir_fd)
2172                 {
2173                 file_data_unregister_real_time_monitor(lw->dir_fd);
2174                 file_data_unref(lw->dir_fd);
2175                 }
2176
2177         string_list_free(lw->toolbar_actions);
2178         free_layout_options_content(&lw->options);
2179         g_free(lw);
2180 }
2181
2182 static gboolean layout_delete_cb(GtkWidget *widget, GdkEventAny *event, gpointer data)
2183 {
2184         LayoutWindow *lw = data;
2185
2186         layout_close(lw);
2187         return TRUE;
2188 }
2189
2190 LayoutWindow *layout_new(FileData *dir_fd, LayoutOptions *lop)
2191 {
2192         return layout_new_with_geometry(dir_fd, lop, NULL);
2193 }
2194
2195 LayoutWindow *layout_new_with_geometry(FileData *dir_fd, LayoutOptions *lop,
2196                                        const gchar *geometry)
2197 {
2198         LayoutWindow *lw;
2199         GdkGeometry hint;
2200         GdkWindowHints hint_mask;
2201         Histogram *histogram;
2202
2203         lw = g_new0(LayoutWindow, 1);
2204
2205         if (lop)
2206                 copy_layout_options(&lw->options, lop);
2207         else
2208                 init_layout_options(&lw->options);
2209
2210         lw->sort_method = SORT_NAME;
2211         lw->sort_ascend = TRUE;
2212
2213 //      lw->options.tools_float = popped;
2214 //      lw->options.tools_hidden = hidden;
2215 //      lw->bar_sort_enabled = options->panels.sort.enabled;
2216 //      lw->bar_enabled = options->panels.info.enabled;
2217
2218         /* default layout */
2219
2220         layout_config_parse(lw->options.style, lw->options.order,
2221                             &lw->dir_location,  &lw->file_location, &lw->image_location);
2222         if (lw->options.dir_view_type >= VIEW_DIR_TYPES_COUNT) lw->options.dir_view_type = 0;
2223         if (lw->options.file_view_type >= VIEW_FILE_TYPES_COUNT) lw->options.file_view_type = 0;
2224
2225         /* divider positions */
2226
2227         if (!options->save_window_positions)
2228                 {
2229                 lw->options.main_window.hdivider_pos = MAIN_WINDOW_DIV_HPOS;
2230                 lw->options.main_window.vdivider_pos = MAIN_WINDOW_DIV_VPOS;
2231                 lw->options.float_window.vdivider_pos = MAIN_WINDOW_DIV_VPOS;
2232                 }
2233
2234         /* window */
2235
2236         lw->window = window_new(GTK_WINDOW_TOPLEVEL, GQ_APPNAME_LC, NULL, NULL, NULL);
2237         gtk_window_set_resizable(GTK_WINDOW(lw->window), TRUE);
2238         gtk_container_set_border_width(GTK_CONTAINER(lw->window), 0);
2239
2240         if (options->save_window_positions)
2241                 {
2242                 hint_mask = GDK_HINT_USER_POS;
2243                 }
2244         else
2245                 {
2246                 hint_mask = 0;
2247                 }
2248
2249         hint.min_width = 32;
2250         hint.min_height = 32;
2251         hint.base_width = 0;
2252         hint.base_height = 0;
2253         gtk_window_set_geometry_hints(GTK_WINDOW(lw->window), NULL, &hint,
2254                                       GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | hint_mask);
2255
2256         if (options->save_window_positions)
2257                 {
2258                 gtk_window_set_default_size(GTK_WINDOW(lw->window), lw->options.main_window.w, lw->options.main_window.h);
2259 //              if (!layout_window_list)
2260 //                      {
2261                 gtk_window_move(GTK_WINDOW(lw->window), lw->options.main_window.x, lw->options.main_window.y);
2262                 if (lw->options.main_window.maximized) gtk_window_maximize(GTK_WINDOW(lw->window));
2263 //                      }
2264                 }
2265         else
2266                 {
2267                 gtk_window_set_default_size(GTK_WINDOW(lw->window), MAINWINDOW_DEF_WIDTH, MAINWINDOW_DEF_HEIGHT);
2268                 }
2269
2270         g_signal_connect(G_OBJECT(lw->window), "delete_event",
2271                          G_CALLBACK(layout_delete_cb), lw);
2272
2273         layout_keyboard_init(lw, lw->window);
2274
2275 #ifdef HAVE_LIRC
2276         layout_image_lirc_init(lw);
2277 #endif
2278
2279         lw->main_box = gtk_vbox_new(FALSE, 0);
2280         gtk_container_add(GTK_CONTAINER(lw->window), lw->main_box);
2281         gtk_widget_show(lw->main_box);
2282
2283         layout_grid_setup(lw);
2284         image_top_window_set_sync(lw->image, (lw->options.tools_float || lw->options.tools_hidden));
2285
2286         layout_util_sync(lw);
2287         layout_status_update_all(lw);
2288
2289         if (dir_fd)
2290                 {
2291                 layout_set_fd(lw, dir_fd);
2292                 }
2293         else
2294                 {
2295                 GdkPixbuf *pixbuf;
2296
2297                 pixbuf = pixbuf_inline(PIXBUF_INLINE_LOGO);
2298                 
2299                 /* FIXME: the zoom value set here is the value, which is then copied again and again
2300                    in "Leave Zoom at previous setting" mode. This is not ideal.  */
2301                 image_change_pixbuf(lw->image, pixbuf, 0.0, FALSE);
2302                 g_object_unref(pixbuf);
2303                 }
2304
2305         if (geometry)
2306                 {
2307                 if (!gtk_window_parse_geometry(GTK_WINDOW(lw->window), geometry))
2308                         {
2309                         log_printf("%s", _("Invalid geometry\n"));
2310                         }
2311                 }
2312
2313         gtk_widget_show(lw->window);
2314         layout_tools_hide(lw, lw->options.tools_hidden);
2315
2316         image_osd_set(lw->image, lw->options.image_overlay.state);
2317         histogram = image_osd_get_histogram(lw->image);
2318         
2319         histogram->histogram_channel = lw->options.image_overlay.histogram_channel;
2320         histogram->histogram_mode = lw->options.image_overlay.histogram_mode;
2321
2322         layout_window_list = g_list_append(layout_window_list, lw);
2323
2324         file_data_register_notify_func(layout_image_notify_cb, lw, NOTIFY_PRIORITY_LOW);
2325
2326         return lw;
2327 }
2328
2329 void layout_write_attributes(LayoutOptions *layout, GString *outstr, gint indent)
2330 {
2331         WRITE_NL(); WRITE_INT(*layout, style);
2332         WRITE_NL(); WRITE_CHAR(*layout, order);
2333         WRITE_NL(); WRITE_UINT(*layout, dir_view_type);
2334         WRITE_NL(); WRITE_UINT(*layout, file_view_type);
2335         WRITE_NL(); WRITE_BOOL(*layout, show_marks);
2336         WRITE_NL(); WRITE_BOOL(*layout, show_thumbnails);
2337         WRITE_NL(); WRITE_BOOL(*layout, show_directory_date);
2338         WRITE_NL(); WRITE_CHAR(*layout, home_path);
2339         WRITE_SEPARATOR();
2340
2341         WRITE_NL(); WRITE_INT(*layout, main_window.x);
2342         WRITE_NL(); WRITE_INT(*layout, main_window.y);
2343         WRITE_NL(); WRITE_INT(*layout, main_window.w);
2344         WRITE_NL(); WRITE_INT(*layout, main_window.h);
2345         WRITE_NL(); WRITE_BOOL(*layout, main_window.maximized);
2346         WRITE_NL(); WRITE_INT(*layout, main_window.hdivider_pos);
2347         WRITE_NL(); WRITE_INT(*layout, main_window.vdivider_pos);
2348         WRITE_SEPARATOR();
2349
2350         WRITE_NL(); WRITE_INT(*layout, float_window.x);
2351         WRITE_NL(); WRITE_INT(*layout, float_window.y);
2352         WRITE_NL(); WRITE_INT(*layout, float_window.w);
2353         WRITE_NL(); WRITE_INT(*layout, float_window.h);
2354         WRITE_NL(); WRITE_INT(*layout, float_window.vdivider_pos);
2355         WRITE_SEPARATOR();
2356
2357         WRITE_NL(); WRITE_INT(*layout, properties_window.w);
2358         WRITE_NL(); WRITE_INT(*layout, properties_window.h);
2359         WRITE_SEPARATOR();
2360
2361         WRITE_NL(); WRITE_BOOL(*layout, tools_float);
2362         WRITE_NL(); WRITE_BOOL(*layout, tools_hidden);
2363         WRITE_SEPARATOR();
2364
2365         WRITE_NL(); WRITE_BOOL(*layout, toolbar_hidden);
2366         WRITE_NL(); WRITE_BOOL(*layout, info_pixel_hidden);
2367
2368         WRITE_NL(); WRITE_UINT(*layout, image_overlay.state);
2369         WRITE_NL(); WRITE_INT(*layout, image_overlay.histogram_channel);
2370         WRITE_NL(); WRITE_INT(*layout, image_overlay.histogram_mode);
2371 }
2372
2373
2374 void layout_write_config(LayoutWindow *lw, GString *outstr, gint indent)
2375 {
2376         layout_sync_options_with_current_state(lw);
2377         WRITE_NL(); WRITE_STRING("<layout");
2378         layout_write_attributes(&lw->options, outstr, indent + 1);
2379         WRITE_STRING(">");
2380
2381         bar_sort_write_config(lw->bar_sort, outstr, indent + 1);
2382         bar_write_config(lw->bar, outstr, indent + 1);
2383         
2384         layout_toolbar_write_config(lw, outstr, indent + 1);
2385
2386         WRITE_NL(); WRITE_STRING("</layout>");
2387 }
2388
2389 void layout_load_attributes(LayoutOptions *layout, const gchar **attribute_names, const gchar **attribute_values)
2390 {
2391         
2392         while (*attribute_names)
2393                 {
2394                 const gchar *option = *attribute_names++;
2395                 const gchar *value = *attribute_values++;
2396
2397                 /* layout options */
2398
2399                 if (READ_INT(*layout, style)) continue;
2400                 if (READ_CHAR(*layout, order)) continue;
2401                 
2402                 if (READ_UINT(*layout, dir_view_type)) continue;
2403                 if (READ_UINT(*layout, file_view_type)) continue;
2404                 if (READ_BOOL(*layout, show_marks)) continue;
2405                 if (READ_BOOL(*layout, show_thumbnails)) continue;
2406                 if (READ_BOOL(*layout, show_directory_date)) continue;
2407                 if (READ_CHAR(*layout, home_path)) continue;
2408
2409                 /* window positions */
2410
2411                 if (READ_INT(*layout, main_window.x)) continue;
2412                 if (READ_INT(*layout, main_window.y)) continue;
2413                 if (READ_INT(*layout, main_window.w)) continue;
2414                 if (READ_INT(*layout, main_window.h)) continue;
2415                 if (READ_BOOL(*layout, main_window.maximized)) continue;
2416                 if (READ_INT(*layout, main_window.hdivider_pos)) continue;
2417                 if (READ_INT(*layout, main_window.vdivider_pos)) continue;
2418
2419                 if (READ_INT(*layout, float_window.x)) continue;
2420                 if (READ_INT(*layout, float_window.y)) continue;
2421                 if (READ_INT(*layout, float_window.w)) continue;
2422                 if (READ_INT(*layout, float_window.h)) continue;
2423                 if (READ_INT(*layout, float_window.vdivider_pos)) continue;
2424         
2425                 if (READ_INT(*layout, properties_window.w)) continue;
2426                 if (READ_INT(*layout, properties_window.h)) continue;
2427
2428                 if (READ_BOOL(*layout, tools_float)) continue;
2429                 if (READ_BOOL(*layout, tools_hidden)) continue;
2430                 if (READ_BOOL(*layout, toolbar_hidden)) continue;
2431                 if (READ_BOOL(*layout, info_pixel_hidden)) continue;
2432
2433                 if (READ_UINT(*layout, image_overlay.state)) continue;
2434                 if (READ_INT(*layout, image_overlay.histogram_channel)) continue;
2435                 if (READ_INT(*layout, image_overlay.histogram_mode)) continue;
2436
2437                 log_printf("unknown attribute %s = %s\n", option, value);
2438                 }
2439
2440 }
2441
2442 static void layout_config_commandline(LayoutOptions *lop, gchar **path)
2443 {
2444         if (command_line->startup_blank)
2445                 {
2446                 *path = NULL;
2447                 }
2448         else if (command_line->file)
2449                 {
2450                 *path = g_strdup(command_line->file);
2451                 }
2452         else if (command_line->path)
2453                 {
2454                 *path = g_strdup(command_line->path);
2455                 }
2456         else if (options->startup.restore_path && options->startup.path && isdir(options->startup.path))
2457                 {
2458                 *path = g_strdup(options->startup.path);
2459                 }
2460         else
2461                 {
2462                 *path = get_current_dir();
2463                 }
2464         
2465         if (command_line->tools_show)
2466                 {
2467                 lop->tools_float = FALSE;
2468                 lop->tools_hidden = FALSE;
2469                 }
2470         else if (command_line->tools_hide)
2471                 {
2472                 lop->tools_hidden = TRUE;
2473                 }
2474 }
2475
2476 LayoutWindow *layout_new_from_config(const gchar **attribute_names, const gchar **attribute_values, gboolean use_commandline)
2477 {
2478         LayoutOptions lop;
2479         LayoutWindow *lw;
2480         gchar *path = NULL;
2481         
2482         init_layout_options(&lop);
2483
2484         if (attribute_names) layout_load_attributes(&lop, attribute_names, attribute_values);
2485         
2486         if (use_commandline)
2487                 {
2488                 layout_config_commandline(&lop, &path);
2489                 }
2490         else if (options->startup.restore_path && options->startup.path && isdir(options->startup.path))
2491                 {
2492                 path = g_strdup(options->startup.path);
2493                 }
2494         else
2495                 {
2496                 path = get_current_dir();
2497                 }
2498
2499         lw = layout_new_with_geometry(NULL, &lop, use_commandline ? command_line->geometry : NULL);
2500         layout_sort_set(lw, options->file_sort.method, options->file_sort.ascending);
2501         layout_set_path(lw, path);
2502
2503         if (use_commandline && command_line->startup_full_screen) layout_image_full_screen_start(lw);
2504         if (use_commandline && command_line->startup_in_slideshow) layout_image_slideshow_start(lw);
2505
2506
2507         g_free(path);
2508         free_layout_options_content(&lop);
2509         return lw;
2510 }
2511
2512
2513 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */