5027cb8400b8d1e6f40015471ca77897ec2a54d8
[geeqie.git] / src / layout.c
1 /*
2  * GQview
3  * (C) 2004 John Ellis
4  *
5  * Author: John Ellis
6  *
7  * This software is released under the GNU General Public License (GNU GPL).
8  * Please read the included file COPYING for more information.
9  * This software comes with no warranty of any kind, use at your own risk!
10  */
11
12 #include "gqview.h"
13 #include "layout.h"
14
15 #include "image.h"
16 #include "layout_config.h"
17 #include "layout_image.h"
18 #include "layout_util.h"
19 #include "menu.h"
20 #include "pixbuf_util.h"
21 #include "view_dir_list.h"
22 #include "view_dir_tree.h"
23 #include "view_file_list.h"
24 #include "view_file_icon.h"
25 #include "ui_bookmark.h"
26 #include "ui_fileops.h"
27 #include "ui_menu.h"
28 #include "ui_misc.h"
29 #include "ui_tabcomp.h"
30
31 #include "icons/tools.xpm"
32
33 #define MAINWINDOW_DEF_WIDTH 620
34 #define MAINWINDOW_DEF_HEIGHT 400
35
36 #define MAIN_WINDOW_DIV_HPOS -1
37 #define MAIN_WINDOW_DIV_VPOS 200
38
39 #define TOOLWINDOW_DEF_WIDTH 260
40 #define TOOLWINDOW_DEF_HEIGHT 450
41 #define PROGRESS_WIDTH 150
42 #define ZOOM_LABEL_WIDTH 64
43
44 #define PANE_DIVIDER_SIZE 10
45
46
47 GList *layout_window_list = NULL;
48
49
50 static void layout_list_scroll_to_subpart(LayoutWindow *lw, const gchar *needle);
51
52
53 /*
54  *-----------------------------------------------------------------------------
55  * misc
56  *-----------------------------------------------------------------------------
57  */
58
59 gint layout_valid(LayoutWindow **lw)
60 {
61         if (*lw == NULL)
62                 {
63                 if (layout_window_list) *lw = layout_window_list->data;
64                 return (*lw != NULL);
65                 }
66
67         return (g_list_find(layout_window_list, *lw) != NULL);
68 }
69
70 LayoutWindow *layout_find_by_image(ImageWindow *imd)
71 {
72         GList *work;
73
74         work = layout_window_list;
75         while (work)
76                 {
77                 LayoutWindow *lw = work->data;
78                 work = work->next;
79
80                 if (lw->image == imd) return lw;
81                 }
82
83         return NULL;
84 }
85
86 /*
87  *-----------------------------------------------------------------------------
88  * menu, toolbar, and dir view
89  *-----------------------------------------------------------------------------
90  */
91
92 static void layout_path_entry_changed_cb(GtkWidget *widget, gpointer data)
93 {
94         LayoutWindow *lw = data;
95         gchar *buf;
96
97         if (gtk_combo_box_get_active(GTK_COMBO_BOX(widget)) < 0) return;
98
99         buf = g_strdup(gtk_entry_get_text(GTK_ENTRY(lw->path_entry)));
100         if (!buf || (lw->path && strcmp(buf, lw->path) == 0))
101                 {
102                 g_free(buf);
103                 return;
104                 }
105
106         layout_set_path(lw, buf);
107
108         g_free(buf);
109 }
110
111 static void layout_path_entry_tab_cb(const gchar *path, gpointer data)
112 {
113         LayoutWindow *lw = data;
114         gchar *buf;
115         gchar *base;
116
117         buf = g_strdup(path);
118         parse_out_relatives(buf);
119         base = remove_level_from_path(buf);
120
121         if (isdir(buf))
122                 {
123                 if ((!lw->path || strcmp(lw->path, buf) != 0) && layout_set_path(lw, buf))
124                         {
125                         gint pos = -1;
126                         /* put the '/' back, if we are in tab completion for a dir and result was path change */
127                         gtk_editable_insert_text(GTK_EDITABLE(lw->path_entry), "/", -1, &pos);
128                         gtk_editable_set_position(GTK_EDITABLE(lw->path_entry),
129                                                   strlen(gtk_entry_get_text(GTK_ENTRY(lw->path_entry))));
130                         }
131                 }
132         else if (lw->path && strcmp(lw->path, base) == 0)
133                 {
134                 layout_list_scroll_to_subpart(lw, filename_from_path(buf));
135                 }
136
137         g_free(base);
138         g_free(buf);
139 }
140
141 static void layout_path_entry_cb(const gchar *path, gpointer data)
142 {
143         LayoutWindow *lw = data;
144         gchar *buf;
145
146         buf = g_strdup(path);
147         parse_out_relatives(buf);
148
149         layout_set_path(lw, buf);
150
151         g_free(buf);
152 }
153
154 static void layout_vdlist_select_cb(ViewDirList *vdl, const gchar *path, gpointer data)
155 {
156         LayoutWindow *lw = data;
157
158         layout_set_path(lw, path);
159 }
160
161 static void layout_vdtree_select_cb(ViewDirTree *vdt, const gchar *path, gpointer data)
162 {
163         LayoutWindow *lw = data;
164
165         layout_set_path(lw, path);
166 }
167
168 static GtkWidget *layout_tool_setup(LayoutWindow *lw)
169 {
170         GtkWidget *box;
171         GtkWidget *menu_bar;
172         GtkWidget *tabcomp;
173 #if 0
174         GtkWidget *popwin;
175 #endif
176
177         box = gtk_vbox_new(FALSE, 0);
178
179         menu_bar = layout_actions_menu_bar(lw);
180         gtk_box_pack_start(GTK_BOX(box), menu_bar, FALSE, FALSE, 0);
181         gtk_widget_show(menu_bar);
182
183         lw->toolbar = layout_button_bar(lw);
184         gtk_box_pack_start(GTK_BOX(box), lw->toolbar, FALSE, FALSE, 0);
185         if (!lw->toolbar_hidden) gtk_widget_show(lw->toolbar);
186
187         tabcomp = tab_completion_new_with_history(&lw->path_entry, NULL, "path_list", -1,
188                                                   layout_path_entry_cb, lw);
189         tab_completion_add_tab_func(lw->path_entry, layout_path_entry_tab_cb, lw);
190         gtk_box_pack_start(GTK_BOX(box), tabcomp, FALSE, FALSE, 0);
191         gtk_widget_show(tabcomp);
192
193 #if 0
194         popwin = gtk_widget_get_toplevel(GTK_COMBO(tabcomp)->list);
195 #endif
196         g_signal_connect(G_OBJECT(lw->path_entry->parent), "changed",
197                          G_CALLBACK(layout_path_entry_changed_cb), lw);
198
199         if (lw->tree_view)
200                 {
201                 lw->vdt = vdtree_new(lw->path, TRUE);
202                 vdtree_set_layout(lw->vdt, lw);
203                 vdtree_set_select_func(lw->vdt, layout_vdtree_select_cb, lw);
204
205                 lw->dir_view = lw->vdt->widget;
206                 }
207         else
208                 {
209                 lw->vdl = vdlist_new(lw->path);
210                 vdlist_set_layout(lw->vdl, lw);
211                 vdlist_set_select_func(lw->vdl, layout_vdlist_select_cb, lw);
212
213                 lw->dir_view = lw->vdl->widget;
214                 }
215
216         gtk_box_pack_start(GTK_BOX(box), lw->dir_view, TRUE, TRUE, 0);
217         gtk_widget_show(lw->dir_view);
218
219         gtk_widget_show(box);
220
221         return box;
222 }
223
224 /*
225  *-----------------------------------------------------------------------------
226  * sort button (and menu)
227  *-----------------------------------------------------------------------------
228  */
229
230 static void layout_sort_menu_cb(GtkWidget *widget, gpointer data)
231 {
232         LayoutWindow *lw;
233         SortType type;
234
235         lw = submenu_item_get_data(widget);
236         if (!lw) return;
237
238         type = (SortType)GPOINTER_TO_INT(data);
239
240         layout_sort_set(lw, type, lw->sort_ascend);
241 }
242
243 static void layout_sort_menu_ascend_cb(GtkWidget *widget, gpointer data)
244 {
245         LayoutWindow *lw = data;
246
247         layout_sort_set(lw, lw->sort_method, !lw->sort_ascend);
248 }
249
250 static void layout_sort_menu_hide_cb(GtkWidget *widget, gpointer data)
251 {
252         /* destroy the menu */
253         gtk_widget_unref(GTK_WIDGET(widget));
254 }
255
256 static void layout_sort_button_press_cb(GtkWidget *widget, gpointer data)
257 {
258         LayoutWindow *lw = data;
259         GtkWidget *menu;
260         GdkEvent *event;
261         guint32 etime;
262
263         menu = submenu_add_sort(NULL, G_CALLBACK(layout_sort_menu_cb), lw, FALSE, FALSE, TRUE, lw->sort_method);
264
265         /* apparently the menu is never sunk, even on a popup */
266         g_object_ref(G_OBJECT(menu));
267         gtk_object_sink(GTK_OBJECT(menu));
268
269         /* ascending option */
270         menu_item_add_divider(menu);
271         menu_item_add_check(menu, _("Ascending"), lw->sort_ascend, G_CALLBACK(layout_sort_menu_ascend_cb), lw);
272
273         g_signal_connect(G_OBJECT(menu), "selection_done",
274                          G_CALLBACK(layout_sort_menu_hide_cb), NULL);
275
276         event = gtk_get_current_event();
277         if (event)
278                 {
279                 etime = gdk_event_get_time(event);
280                 gdk_event_free(event);
281                 }
282         else
283                 {
284                 etime = 0;
285                 }
286
287         gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, etime);
288 }
289
290 static GtkWidget *layout_sort_button(LayoutWindow *lw)
291 {
292         GtkWidget *button;
293
294         button = gtk_button_new_with_label(sort_type_get_text(lw->sort_method));
295         g_signal_connect(G_OBJECT(button), "clicked",
296                          G_CALLBACK(layout_sort_button_press_cb), lw);
297         gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
298
299         return button;
300 }
301
302 /*
303  *-----------------------------------------------------------------------------
304  * status bar
305  *-----------------------------------------------------------------------------
306  */
307
308 void layout_status_update_progress(LayoutWindow *lw, gdouble val, const gchar *text)
309 {
310         if (!layout_valid(&lw)) return;
311         if (!lw->info_progress_bar) return;
312
313         gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(lw->info_progress_bar), val);
314         gtk_progress_bar_set_text(GTK_PROGRESS_BAR(lw->info_progress_bar), (text) ? text : " ");
315 }
316
317 void layout_status_update_info(LayoutWindow *lw, const gchar *text)
318 {
319         gchar *buf = NULL;
320
321         if (!layout_valid(&lw)) return;
322
323         if (!text)
324                 {
325                 gint n;
326                 gint64 n_bytes = 0;
327                 gint s;
328                 gint64 s_bytes = 0;
329                 const gchar *ss;
330                 gchar *b;
331                 gchar *sb;
332
333                 if (layout_image_slideshow_active(lw))
334                         {
335                         if (!layout_image_slideshow_paused(lw))
336                                 {
337                                 ss = _(" Slideshow");
338                                 }
339                         else
340                                 {
341                                 ss = _(" Paused");
342                                 }
343                         }
344                 else
345                         {
346                         ss = "";
347                         }
348
349                 n = layout_list_count(lw, &n_bytes);
350                 s = layout_selection_count(lw, &s_bytes);
351
352                 layout_bars_new_selection(lw, s);
353
354                 if (s > 0)
355                         {
356                         b = text_from_size_abrev(n_bytes);
357                         sb = text_from_size_abrev(s_bytes);
358                         buf = g_strdup_printf(_("%s, %d files (%s, %d)%s"), b, n, sb, s, ss);
359                         g_free(b);
360                         g_free(sb);
361                         }
362                 else if (n > 0)
363                         {
364                         b = text_from_size_abrev(n_bytes);
365                         buf = g_strdup_printf(_("%s, %d files%s"), b, n, ss);
366                         g_free(b);
367                         }
368                 else
369                         {
370                         buf = g_strdup_printf(_("%d files%s"), n, ss);
371                         }
372
373                 text = buf;
374
375                 layout_image_overlay_update(lw);
376                 }
377
378         gtk_label_set_text(GTK_LABEL(lw->info_status), text);
379         g_free(buf);
380 }
381
382 void layout_status_update_image(LayoutWindow *lw)
383 {
384         gchar *text;
385         gchar *b;
386
387         if (!layout_valid(&lw) || !lw->image) return;
388
389         text = image_zoom_get_as_text(lw->image);
390         gtk_label_set_text(GTK_LABEL(lw->info_zoom), text);
391         g_free(text);
392
393         b = text_from_size(lw->image->size);
394
395         if (lw->image->unknown)
396                 {
397                 if (image_get_path(lw->image) && !access_file(image_get_path(lw->image), R_OK))
398                         {
399                         text = g_strdup_printf(_("(no read permission) %s bytes"), b);
400                         }
401                 else
402                         {
403                         text = g_strdup_printf(_("( ? x ? ) %s bytes"), b);
404                         }
405                 }
406         else
407                 {
408                 text = g_strdup_printf(_("( %d x %d ) %s bytes"),
409                                        lw->image->image_width, lw->image->image_height, b);
410                 }
411
412         gtk_label_set_text(GTK_LABEL(lw->info_details), text);
413
414         g_free(b);
415         g_free(text);
416 }
417
418 void layout_status_update_all(LayoutWindow *lw)
419 {
420         layout_status_update_progress(lw, 0.0, NULL);
421         layout_status_update_info(lw, NULL);
422         layout_status_update_image(lw);
423 }
424
425 static GtkWidget *layout_status_label(gchar *text, GtkWidget *box, gint start, gint size, gint expand)
426 {
427         GtkWidget *label;
428         GtkWidget *frame;
429
430         frame = gtk_frame_new(NULL);
431         if (size) gtk_widget_set_size_request(frame, size, -1);
432         gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
433         if (start)
434                 {
435                 gtk_box_pack_start(GTK_BOX(box), frame, expand, expand, 0);
436                 }
437         else
438                 {
439                 gtk_box_pack_end(GTK_BOX(box), frame, expand, expand, 0);
440                 }
441         gtk_widget_show(frame);
442
443         label = gtk_label_new(text ? text : "");
444         gtk_container_add(GTK_CONTAINER(frame), label);
445         gtk_widget_show(label);
446
447         return label;
448 }
449
450 static void layout_status_setup(LayoutWindow *lw, GtkWidget *box, gint small_format)
451 {
452         GtkWidget *hbox;
453
454         if (lw->info_box) return;
455
456         if (small_format)
457                 {
458                 lw->info_box = gtk_vbox_new(FALSE, 0);
459                 }
460         else
461                 {
462                 lw->info_box = gtk_hbox_new(FALSE, 0);
463                 }
464         gtk_box_pack_end(GTK_BOX(box), lw->info_box, FALSE, FALSE, 0);
465         gtk_widget_show(lw->info_box);
466
467         if (small_format)
468                 {
469                 hbox = gtk_hbox_new(FALSE, 0);
470                 gtk_box_pack_start(GTK_BOX(lw->info_box), hbox, FALSE, FALSE, 0);
471                 gtk_widget_show(hbox);
472                 }
473         else
474                 {
475                 hbox = lw->info_box;
476                 }
477         lw->info_progress_bar = gtk_progress_bar_new();
478         gtk_widget_set_size_request(lw->info_progress_bar, PROGRESS_WIDTH, -1);
479         gtk_box_pack_start(GTK_BOX(hbox), lw->info_progress_bar, FALSE, FALSE, 0);
480         gtk_widget_show(lw->info_progress_bar);
481
482         lw->info_sort = layout_sort_button(lw);
483         gtk_box_pack_start(GTK_BOX(hbox), lw->info_sort, FALSE, FALSE, 0);
484         gtk_widget_show(lw->info_sort);
485
486         lw->info_status = layout_status_label(NULL, lw->info_box, TRUE, 0, (!small_format));
487
488         if (small_format)
489                 {
490                 hbox = gtk_hbox_new(FALSE, 0);
491                 gtk_box_pack_start(GTK_BOX(lw->info_box), hbox, FALSE, FALSE, 0);
492                 gtk_widget_show(hbox);
493                 }
494         else
495                 {
496                 hbox = lw->info_box;
497                 }
498         lw->info_details = layout_status_label(NULL, hbox, TRUE, 0, TRUE);
499         lw->info_zoom = layout_status_label(NULL, hbox, FALSE, ZOOM_LABEL_WIDTH, FALSE);
500 }
501
502 /*
503  *-----------------------------------------------------------------------------
504  * views
505  *-----------------------------------------------------------------------------
506  */
507
508 static GtkWidget *layout_tools_new(LayoutWindow *lw)
509 {
510         lw->dir_view = layout_tool_setup(lw);
511         return lw->dir_view;
512 }
513
514 static void layout_list_status_cb(ViewFileList *vfl, gpointer data)
515 {
516         LayoutWindow *lw = data;
517
518         layout_status_update_info(lw, NULL);
519 }
520
521 static void layout_list_thumb_cb(ViewFileList *vfl, gdouble val, const gchar *text, gpointer data)
522 {
523         LayoutWindow *lw = data;
524
525         layout_status_update_progress(lw, val, text);
526 }
527
528 static void layout_icon_status_cb(ViewFileIcon *vfi, gpointer data)
529 {
530         LayoutWindow *lw = data;
531
532         layout_status_update_info(lw, NULL);
533 }
534
535 static void layout_icon_thumb_cb(ViewFileIcon *vfi, gdouble val, const gchar *text, gpointer data)
536 {
537         LayoutWindow *lw = data;
538
539         layout_status_update_progress(lw, val, text);
540 }
541
542 static GtkWidget *layout_list_new(LayoutWindow *lw)
543 {
544         if (lw->icon_view)
545                 {
546                 lw->vfi = vficon_new(NULL);
547                 vficon_set_layout(lw->vfi, lw);
548
549                 vficon_set_status_func(lw->vfi, layout_icon_status_cb, lw);
550                 vficon_set_thumb_status_func(lw->vfi, layout_icon_thumb_cb, lw);
551
552                 return lw->vfi->widget;
553                 }
554
555         lw->vfl = vflist_new(NULL, lw->thumbs_enabled);
556         vflist_set_layout(lw->vfl, lw);
557
558         vflist_set_status_func(lw->vfl, layout_list_status_cb, lw);
559         vflist_set_thumb_status_func(lw->vfl, layout_list_thumb_cb, lw);
560
561         return lw->vfl->widget;
562 }
563
564 static void layout_list_sync_thumb(LayoutWindow *lw)
565 {
566         if (lw->vfl) vflist_thumb_set(lw->vfl, lw->thumbs_enabled);
567 }
568
569 static void layout_list_scroll_to_subpart(LayoutWindow *lw, const gchar *needle)
570 {
571         if (!lw) return;
572 #if 0
573         if (lw->vfl) vflist_scroll_to_subpart(lw->vfl, needle);
574         if (lw->vfi) vficon_scroll_to_subpart(lw->vfi, needle);
575 #endif
576 }
577
578 GList *layout_list(LayoutWindow *lw)
579 {
580         if (!layout_valid(&lw)) return NULL;
581
582         if (lw->vfl) return vflist_get_list(lw->vfl);
583         if (lw->vfi) return vficon_get_list(lw->vfi);
584
585         return NULL;
586 }
587
588 gint layout_list_count(LayoutWindow *lw, gint64 *bytes)
589 {
590         if (!layout_valid(&lw)) return 0;
591
592         if (lw->vfl) return vflist_count(lw->vfl, bytes);
593         if (lw->vfi) return vficon_count(lw->vfi, bytes);
594
595         return 0;
596 }
597
598 const gchar *layout_list_get_path(LayoutWindow *lw, gint index)
599 {
600         if (!layout_valid(&lw)) return NULL;
601
602         if (lw->vfl) return vflist_index_get_path(lw->vfl, index);
603         if (lw->vfi) return vficon_index_get_path(lw->vfi, index);
604
605         return NULL;
606 }
607
608 gint layout_list_get_index(LayoutWindow *lw, const gchar *path)
609 {
610         if (!layout_valid(&lw)) return -1;
611
612         if (lw->vfl) return vflist_index_by_path(lw->vfl, path);
613         if (lw->vfi) return vficon_index_by_path(lw->vfi, path);
614
615         return -1;
616 }
617
618 void layout_list_sync_path(LayoutWindow *lw, const gchar *path)
619 {
620         if (!layout_valid(&lw)) return;
621
622         if (lw->vfl) vflist_select_by_path(lw->vfl, path);
623         if (lw->vfi) vficon_select_by_path(lw->vfi, path);
624 }
625
626 static void layout_list_sync_sort(LayoutWindow *lw)
627 {
628         if (!layout_valid(&lw)) return;
629
630         if (lw->vfl) vflist_sort_set(lw->vfl, lw->sort_method, lw->sort_ascend);
631         if (lw->vfi) vficon_sort_set(lw->vfi, lw->sort_method, lw->sort_ascend);
632 }
633
634 GList *layout_selection_list(LayoutWindow *lw)
635 {
636         if (!layout_valid(&lw)) return NULL;
637
638         if (layout_image_get_collection(lw, NULL))
639                 {
640                 const gchar *path;
641
642                 path = layout_image_get_path(lw);
643                 if (path) return g_list_append(NULL, g_strdup(path));
644                 return NULL;
645                 }
646
647         if (lw->vfl) return vflist_selection_get_list(lw->vfl);
648         if (lw->vfi) return vficon_selection_get_list(lw->vfi);
649
650         return NULL;
651 }
652
653 GList *layout_selection_list_by_index(LayoutWindow *lw)
654 {
655         if (!layout_valid(&lw)) return NULL;
656
657         if (lw->vfl) return vflist_selection_get_list_by_index(lw->vfl);
658         if (lw->vfi) return vficon_selection_get_list_by_index(lw->vfi);
659
660         return NULL;
661 }
662
663 gint layout_selection_count(LayoutWindow *lw, gint64 *bytes)
664 {
665         if (!layout_valid(&lw)) return 0;
666
667         if (lw->vfl) return vflist_selection_count(lw->vfl, bytes);
668         if (lw->vfi) return vficon_selection_count(lw->vfi, bytes);
669
670         return 0;
671 }
672
673 void layout_select_all(LayoutWindow *lw)
674 {
675         if (!layout_valid(&lw)) return;
676
677         if (lw->vfl) vflist_select_all(lw->vfl);
678         if (lw->vfi) vficon_select_all(lw->vfi);
679 }
680
681 void layout_select_none(LayoutWindow *lw)
682 {
683         if (!layout_valid(&lw)) return;
684
685         if (lw->vfl) vflist_select_none(lw->vfl);
686         if (lw->vfi) vficon_select_none(lw->vfi);
687 }
688
689 /*
690  *-----------------------------------------------------------------------------
691  * access
692  *-----------------------------------------------------------------------------
693  */
694
695 const gchar *layout_get_path(LayoutWindow *lw)
696 {
697         if (!layout_valid(&lw)) return NULL;
698         return lw->path;
699 }
700
701 static void layout_sync_path(LayoutWindow *lw)
702 {
703         if (!lw->path) return;
704
705         lw->last_time = filetime(lw->path);
706
707         gtk_entry_set_text(GTK_ENTRY(lw->path_entry), lw->path);
708         if (lw->vdl) vdlist_set_path(lw->vdl, lw->path);
709         if (lw->vdt) vdtree_set_path(lw->vdt, lw->path);
710
711         if (lw->vfl) vflist_set_path(lw->vfl, lw->path);
712         if (lw->vfi) vficon_set_path(lw->vfi, lw->path);
713 }
714
715 gint layout_set_path(LayoutWindow *lw, const gchar *path)
716 {
717         gint have_file = FALSE;
718
719         if (!layout_valid(&lw)) return FALSE;
720
721         if (!path || !isname(path)) return FALSE;
722         if (lw->path && path && strcmp(path, lw->path) == 0)
723                 {
724                 return TRUE;
725                 }
726
727         if (isdir(path))
728                 {
729                 g_free(lw->path);
730                 lw->path = g_strdup(path);
731                 }
732         else
733                 {
734                 gchar *base;
735
736                 base = remove_level_from_path(path);
737                 if (lw->path && strcmp(lw->path, base) == 0)
738                         {
739                         g_free(base);
740                         }
741                 else if (isdir(base))
742                         {
743                         g_free(lw->path);
744                         lw->path = base;
745                         }
746                 else
747                         {
748                         g_free(base);
749                         return FALSE;
750                         }
751                 if (isfile(path)) have_file = TRUE;
752                 }
753
754         if (lw->path_entry) tab_completion_append_to_history(lw->path_entry, lw->path);
755         layout_sync_path(lw);
756
757         if (have_file)
758                 {
759                 gint row;
760
761                 row = layout_list_get_index(lw, path);
762                 if (row >= 0)
763                         {
764                         layout_image_set_index(lw, row);
765                         }
766                 else
767                         {
768                         layout_image_set_path(lw, path);
769                         }
770                 }
771         else if (!lazy_image_sync)
772                 {
773                 layout_image_set_index(lw, 0);
774                 }
775
776         return TRUE;
777 }
778
779 static void layout_refresh_lists(LayoutWindow *lw)
780 {
781         if (lw->path) lw->last_time = filetime(lw->path);
782
783         if (lw->vdl) vdlist_refresh(lw->vdl);
784         if (lw->vdt) vdtree_refresh(lw->vdt);
785
786         if (lw->vfl) vflist_refresh(lw->vfl);
787         if (lw->vfi) vficon_refresh(lw->vfi);
788 }
789
790 static void layout_refresh_by_time(LayoutWindow *lw)
791 {
792         layout_refresh_lists(lw);
793
794         if (lw->image && filetime(layout_image_get_path(lw)) >= lw->last_time)
795                 {
796                 layout_image_refresh(lw);
797                 }
798 }
799
800 void layout_refresh(LayoutWindow *lw)
801 {
802         if (!layout_valid(&lw)) return;
803
804         if (debug) printf("layout refresh\n");
805
806         layout_refresh_lists(lw);
807
808         if (lw->image) layout_image_refresh(lw);
809 }
810
811 static gint layout_check_for_update_cb(gpointer data)
812 {
813         LayoutWindow *lw = data;
814
815         if (!update_on_time_change) return TRUE;
816
817         if (lw->path)
818                 {
819                 time_t new_time;
820
821                 new_time = filetime(lw->path);
822
823                 if (new_time > 0 && new_time > lw->last_time)
824                         {
825                         if (debug) printf("layout path time changed, refreshing...\n");
826                         layout_refresh_by_time(lw);
827                         }
828                 }
829
830         return TRUE;
831 }
832
833 void layout_thumb_set(LayoutWindow *lw, gint enable)
834 {
835         if (!layout_valid(&lw)) return;
836
837         if (lw->thumbs_enabled == enable) return;
838
839         lw->thumbs_enabled = enable;
840
841         layout_util_sync_thumb(lw);
842         layout_list_sync_thumb(lw);
843 }
844
845 gint layout_thumb_get(LayoutWindow *lw)
846 {
847         if (!layout_valid(&lw)) return FALSE;
848
849         return lw->thumbs_enabled;
850 }
851
852 void layout_sort_set(LayoutWindow *lw, SortType type, gint ascend)
853 {
854         if (!layout_valid(&lw)) return;
855         if (lw->sort_method == type && lw->sort_ascend == ascend) return;
856
857         lw->sort_method = type;
858         lw->sort_ascend = ascend;
859
860         if (lw->info_sort) gtk_label_set_text(GTK_LABEL(GTK_BIN(lw->info_sort)->child),
861                                               sort_type_get_text(type));
862         layout_list_sync_sort(lw);
863 }
864
865 gint layout_sort_get(LayoutWindow *lw, SortType *type, gint *ascend)
866 {
867         if (!layout_valid(&lw)) return FALSE;
868
869         if (type) *type = lw->sort_method;
870         if (ascend) *ascend = lw->sort_ascend;
871
872         return TRUE;
873 }
874
875 gint layout_geometry_get(LayoutWindow *lw, gint *x, gint *y, gint *w, gint *h)
876 {
877         if (!layout_valid(&lw)) return FALSE;
878
879         gdk_window_get_root_origin(lw->window->window, x, y);
880         gdk_drawable_get_size(lw->window->window, w, h);
881
882         return TRUE;
883 }
884
885 gint layout_geometry_get_dividers(LayoutWindow *lw, gint *h, gint *v)
886 {
887         if (!layout_valid(&lw)) return FALSE;
888
889         if (lw->h_pane && GTK_PANED(lw->h_pane)->child1->allocation.x >= 0)
890                 {
891                 *h = GTK_PANED(lw->h_pane)->child1->allocation.width;
892                 }
893         else if (h != &lw->div_h)
894                 {
895                 *h = lw->div_h;
896                 }
897
898         if (lw->v_pane && GTK_PANED(lw->v_pane)->child1->allocation.x >= 0)
899                 {
900                 *v = GTK_PANED(lw->v_pane)->child1->allocation.height;
901                 }
902         else if (v != &lw->div_v)
903                 {
904                 *v = lw->div_v;
905                 }
906
907         return TRUE;
908 }
909
910 void layout_views_set(LayoutWindow *lw, gint tree, gint icons)
911 {
912         if (!layout_valid(&lw)) return;
913
914         if (lw->tree_view == tree && lw->icon_view == icons) return;
915
916         lw->tree_view = tree;
917         lw->icon_view = icons;
918
919         layout_style_set(lw, -1, NULL);
920 }
921
922 gint layout_views_get(LayoutWindow *lw, gint *tree, gint *icons)
923 {
924         if (!layout_valid(&lw)) return FALSE;
925
926         *tree = lw->tree_view;
927         *icons = lw->icon_view;
928
929         return TRUE;
930 }
931
932 /*
933  *-----------------------------------------------------------------------------
934  * location utils
935  *-----------------------------------------------------------------------------
936  */
937
938 static gint layout_location_single(LayoutLocation l)
939 {
940         return (l == LAYOUT_LEFT ||
941                 l == LAYOUT_RIGHT ||
942                 l == LAYOUT_TOP ||
943                 l == LAYOUT_BOTTOM);
944 }
945
946 static gint layout_location_vertical(LayoutLocation l)
947 {
948         return (l & LAYOUT_TOP ||
949                 l & LAYOUT_BOTTOM);
950 }
951
952 static gint layout_location_first(LayoutLocation l)
953 {
954         return (l & LAYOUT_TOP ||
955                 l & LAYOUT_LEFT);
956 }
957
958 static LayoutLocation layout_grid_compass(LayoutWindow *lw)
959 {
960         if (layout_location_single(lw->dir_location)) return lw->dir_location;
961         if (layout_location_single(lw->file_location)) return lw->file_location;
962         return lw->image_location;
963 }
964
965 static void layout_location_compute(LayoutLocation l1, LayoutLocation l2,
966                                     GtkWidget *s1, GtkWidget *s2,
967                                     GtkWidget **d1, GtkWidget **d2)
968 {
969         LayoutLocation l;
970
971         l = l1 & l2;    /* get common compass direction */
972         l = l1 - l;     /* remove it */
973
974         if (layout_location_first(l))
975                 {
976                 *d1 = s1;
977                 *d2 = s2;
978                 }
979         else
980                 {
981                 *d1 = s2;
982                 *d2 = s1;
983                 }
984 }
985
986 /*
987  *-----------------------------------------------------------------------------
988  * tools window (for floating/hidden)
989  *-----------------------------------------------------------------------------
990  */
991
992 gint layout_geometry_get_tools(LayoutWindow *lw, gint *x, gint *y, gint *w, gint *h, gint *divider_pos)
993 {
994         if (!layout_valid(&lw)) return FALSE;
995
996         if (!lw->tools || !GTK_WIDGET_VISIBLE(lw->tools))
997                 {
998                 /* use the stored values (sort of breaks success return value) */
999
1000                 *divider_pos = lw->div_float;
1001
1002                 return FALSE;
1003                 }
1004
1005         gdk_window_get_root_origin(lw->tools->window, x, y);
1006         gdk_drawable_get_size(lw->tools->window, w, h);
1007
1008         if (GTK_IS_VPANED(lw->tools_pane))
1009                 {
1010                 *divider_pos = GTK_PANED(lw->tools_pane)->child1->allocation.height;
1011                 }
1012         else
1013                 {
1014                 *divider_pos = GTK_PANED(lw->tools_pane)->child1->allocation.width;
1015                 }
1016
1017         return TRUE;
1018 }
1019
1020 static void layout_tools_geometry_sync(LayoutWindow *lw)
1021 {
1022         layout_geometry_get_tools(lw, &float_window_x, &float_window_x,
1023                                   &float_window_w, &float_window_h, &lw->div_float);
1024 }
1025
1026 static void layout_tools_hide(LayoutWindow *lw, gint hide)
1027 {
1028         if (!lw->tools) return;
1029
1030         if (hide)
1031                 {
1032                 if (GTK_WIDGET_VISIBLE(lw->tools))
1033                         {
1034                         layout_tools_geometry_sync(lw);
1035                         gtk_widget_hide(lw->tools);
1036                         }
1037                 }
1038         else
1039                 {
1040                 if (!GTK_WIDGET_VISIBLE(lw->tools))
1041                         {
1042                         gtk_widget_show(lw->tools);
1043                         if (lw->vfi) vficon_refresh(lw->vfi);
1044                         }
1045                 }
1046
1047         lw->tools_hidden = hide;
1048 }
1049
1050 static gint layout_tools_delete_cb(GtkWidget *widget, GdkEventAny *event, gpointer data)
1051 {
1052         LayoutWindow *lw = data;
1053
1054         layout_tools_float_toggle(lw);
1055
1056         return TRUE;
1057 }
1058
1059 static void layout_tools_setup(LayoutWindow *lw, GtkWidget *tools, GtkWidget *files)
1060 {
1061         GtkWidget *vbox;
1062         GtkWidget *w1, *w2;
1063         gint vertical;
1064         gint new_window = FALSE;
1065
1066         vertical = (layout_location_single(lw->image_location) && !layout_location_vertical(lw->image_location)) ||
1067                    (!layout_location_single(lw->image_location) && layout_location_vertical(layout_grid_compass(lw)));
1068 #if 0
1069         layout_location_compute(lw->dir_location, lw->file_location,
1070                                 tools, files, &w1, &w2);
1071 #endif
1072         /* for now, tools/dir are always first in order */
1073         w1 = tools;
1074         w2 = files;
1075
1076         if (!lw->tools)
1077                 {
1078                 GdkGeometry geometry;
1079                 GdkWindowHints hints;
1080
1081                 lw->tools = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1082                 g_signal_connect(G_OBJECT(lw->tools), "delete_event",
1083                                  G_CALLBACK(layout_tools_delete_cb), lw);
1084                 layout_keyboard_init(lw, lw->tools);
1085
1086                 if (save_window_positions)
1087                         {
1088                         hints = GDK_HINT_USER_POS | GDK_HINT_USER_SIZE;
1089                         }
1090                 else
1091                         {
1092                         hints = 0;
1093                         }
1094
1095                 geometry.min_width = 32;
1096                 geometry.min_height = 32;
1097                 geometry.base_width = TOOLWINDOW_DEF_WIDTH;
1098                 geometry.base_height = TOOLWINDOW_DEF_HEIGHT;
1099                 gtk_window_set_geometry_hints(GTK_WINDOW(lw->tools), NULL, &geometry,
1100                                               GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | hints);
1101
1102
1103                 gtk_window_set_resizable(GTK_WINDOW(lw->tools), TRUE);
1104                 gtk_window_set_title(GTK_WINDOW(lw->tools), _("GQview Tools"));
1105                 gtk_window_set_wmclass(GTK_WINDOW(lw->tools), "tools", "GQview");
1106                 gtk_container_set_border_width(GTK_CONTAINER(lw->tools), 0);
1107
1108                 window_set_icon(lw->tools, (const gchar **)tools_xpm, NULL);
1109
1110                 new_window = TRUE;
1111                 }
1112         else
1113                 {
1114                 layout_tools_geometry_sync(lw);
1115                 /* dump the contents */
1116                 gtk_widget_destroy(GTK_BIN(lw->tools)->child);
1117                 }
1118
1119         layout_actions_add_window(lw, lw->tools);
1120
1121         vbox = gtk_vbox_new(FALSE, 0);
1122         gtk_container_add(GTK_CONTAINER(lw->tools), vbox);
1123         gtk_widget_show(vbox);
1124
1125         layout_status_setup(lw, vbox, TRUE);
1126
1127         if (vertical)
1128                 {
1129                 lw->tools_pane = gtk_vpaned_new();
1130                 }
1131         else
1132                 {
1133                 lw->tools_pane = gtk_hpaned_new();
1134                 }
1135         gtk_box_pack_start(GTK_BOX(vbox), lw->tools_pane, TRUE, TRUE, 0);
1136         gtk_widget_show(lw->tools_pane);
1137
1138         gtk_paned_pack1(GTK_PANED(lw->tools_pane), w1, FALSE, TRUE);
1139         gtk_paned_pack2(GTK_PANED(lw->tools_pane), w2, TRUE, TRUE);
1140
1141         gtk_widget_show(tools);
1142         gtk_widget_show(files);
1143
1144         if (new_window)
1145                 {
1146                 if (save_window_positions)
1147                         {
1148                         gtk_window_set_default_size(GTK_WINDOW(lw->tools), float_window_w, float_window_h);
1149                         gtk_window_move(GTK_WINDOW(lw->tools), float_window_x, float_window_y);
1150                         }
1151                 else
1152                         {
1153                         if (vertical)
1154                                 {
1155                                 gtk_window_set_default_size(GTK_WINDOW(lw->tools),
1156                                                             TOOLWINDOW_DEF_WIDTH, TOOLWINDOW_DEF_HEIGHT);
1157                                 }
1158                         else
1159                                 {
1160                                 gtk_window_set_default_size(GTK_WINDOW(lw->tools),
1161                                                             TOOLWINDOW_DEF_HEIGHT, TOOLWINDOW_DEF_WIDTH);
1162                                 }
1163                         }
1164                 }
1165
1166         if (!save_window_positions)
1167                 {
1168                 if (vertical)
1169                         {
1170                         lw->div_float = MAIN_WINDOW_DIV_VPOS;
1171                         }
1172                 else
1173                         {
1174                         lw->div_float = MAIN_WINDOW_DIV_HPOS;
1175                         }
1176                 }
1177
1178         gtk_paned_set_position(GTK_PANED(lw->tools_pane), lw->div_float);
1179 }
1180
1181 /*
1182  *-----------------------------------------------------------------------------
1183  * glue (layout arrangement)
1184  *-----------------------------------------------------------------------------
1185  */
1186
1187 static void layout_grid_compute(LayoutWindow *lw,
1188                                 GtkWidget *image, GtkWidget *tools, GtkWidget *files,
1189                                 GtkWidget **w1, GtkWidget **w2, GtkWidget **w3)
1190 {
1191         /* heh, this was fun */
1192
1193         if (layout_location_single(lw->dir_location))
1194                 {
1195                 if (layout_location_first(lw->dir_location))
1196                         {
1197                         *w1 = tools;
1198                         layout_location_compute(lw->file_location, lw->image_location, files, image, w2, w3);
1199                         }
1200                 else
1201                         {
1202                         *w3 = tools;
1203                         layout_location_compute(lw->file_location, lw->image_location, files, image, w1, w2);
1204                         }
1205                 }
1206         else if (layout_location_single(lw->file_location))
1207                 {
1208                 if (layout_location_first(lw->file_location))
1209                         {
1210                         *w1 = files;
1211                         layout_location_compute(lw->dir_location, lw->image_location, tools, image, w2, w3);
1212                         }
1213                 else
1214                         {
1215                         *w3 = files;
1216                         layout_location_compute(lw->dir_location, lw->image_location, tools, image, w1, w2);
1217                         }
1218                 }
1219         else
1220                 {
1221                 /* image */
1222                 if (layout_location_first(lw->image_location))
1223                         {
1224                         *w1 = image;
1225                         layout_location_compute(lw->file_location, lw->dir_location, files, tools, w2, w3);
1226                         }
1227                 else
1228                         {
1229                         *w3 = image;
1230                         layout_location_compute(lw->file_location, lw->dir_location, files, tools, w1, w2);
1231                         }
1232                 }
1233 }
1234
1235 static void layout_grid_setup(LayoutWindow *lw)
1236 {
1237         gint priority_location;
1238         GtkWidget *h;
1239         GtkWidget *v;
1240         GtkWidget *w1, *w2, *w3;
1241
1242         GtkWidget *image;
1243         GtkWidget *tools;
1244         GtkWidget *files;
1245
1246         layout_actions_setup(lw);
1247         layout_actions_add_window(lw, lw->window);
1248
1249         lw->group_box = gtk_vbox_new(FALSE, 0);
1250         gtk_box_pack_start(GTK_BOX(lw->main_box), lw->group_box, TRUE, TRUE, 0);
1251         gtk_widget_show(lw->group_box);
1252
1253         priority_location = layout_grid_compass(lw);
1254
1255         image = layout_image_new(lw, NULL);
1256         tools = layout_tools_new(lw);
1257         files = layout_list_new(lw);
1258
1259         image = layout_bars_prepare(lw, image);
1260
1261         if (lw->tools_float || lw->tools_hidden)
1262                 {
1263                 gtk_box_pack_start(GTK_BOX(lw->group_box), image, TRUE, TRUE, 0);
1264                 gtk_widget_show(image);
1265
1266                 layout_tools_setup(lw, tools, files);
1267
1268                 gtk_widget_grab_focus(lw->image->widget);
1269
1270                 return;
1271                 }
1272         else if (lw->tools)
1273                 {
1274                 layout_tools_geometry_sync(lw);
1275                 gtk_widget_destroy(lw->tools);
1276                 lw->tools = NULL;
1277                 lw->tools_pane = NULL;
1278                 }
1279
1280         layout_status_setup(lw, lw->group_box, FALSE);
1281
1282         layout_grid_compute(lw, image, tools, files, &w1, &w2, &w3);
1283
1284         v = lw->v_pane = gtk_vpaned_new();
1285
1286         h = lw->h_pane = gtk_hpaned_new();
1287
1288         if (!layout_location_vertical(priority_location))
1289                 {
1290                 GtkWidget *tmp;
1291
1292                 tmp = v;
1293                 v = h;
1294                 h = tmp;
1295                 }
1296
1297         gtk_box_pack_start(GTK_BOX(lw->group_box), v, TRUE, TRUE, 0);
1298
1299         if (!layout_location_first(priority_location))
1300                 {
1301                 gtk_paned_pack1(GTK_PANED(v), h, FALSE, TRUE);
1302                 gtk_paned_pack2(GTK_PANED(v), w3, TRUE, TRUE);
1303
1304                 gtk_paned_pack1(GTK_PANED(h), w1, FALSE, TRUE);
1305                 gtk_paned_pack2(GTK_PANED(h), w2, TRUE, TRUE);
1306                 }
1307         else
1308                 {
1309                 gtk_paned_pack1(GTK_PANED(v), w1, FALSE, TRUE);
1310                 gtk_paned_pack2(GTK_PANED(v), h, TRUE, TRUE);
1311
1312                 gtk_paned_pack1(GTK_PANED(h), w2, FALSE, TRUE);
1313                 gtk_paned_pack2(GTK_PANED(h), w3, TRUE, TRUE);
1314                 }
1315
1316         gtk_widget_show(image);
1317         gtk_widget_show(tools);
1318         gtk_widget_show(files);
1319
1320         gtk_widget_show(v);
1321         gtk_widget_show(h);
1322
1323         /* fix to have image pane visible when it is left and priority widget */
1324         if (lw->div_h == -1 &&
1325             w1 == image &&
1326             !layout_location_vertical(priority_location) &&
1327             layout_location_first(priority_location))
1328                 {
1329                 gtk_widget_set_size_request(image, 200, -1);
1330                 }
1331
1332         gtk_paned_set_position(GTK_PANED(lw->h_pane), lw->div_h);
1333         gtk_paned_set_position(GTK_PANED(lw->v_pane), lw->div_v);
1334
1335         gtk_widget_grab_focus(lw->image->widget);
1336 }
1337
1338 void layout_style_set(LayoutWindow *lw, gint style, const gchar *order)
1339 {
1340         gchar *path;
1341         ImageWindow *old_image;
1342
1343         if (!layout_valid(&lw)) return;
1344
1345         if (style != -1)
1346                 {
1347                 LayoutLocation d, f, i;
1348
1349                 layout_config_parse(style, order, &d,  &f, &i);
1350
1351                 if (lw->dir_location == d &&
1352                     lw->file_location == f &&
1353                     lw->image_location == i) return;
1354
1355                 lw->dir_location = d;
1356                 lw->file_location = f;
1357                 lw->image_location = i;
1358                 }
1359
1360         /* remember state */
1361
1362         layout_image_slideshow_stop(lw);
1363         layout_image_full_screen_stop(lw);
1364
1365         path = lw->path;
1366         lw->path = NULL;
1367         old_image = lw->image;
1368         lw->image = NULL;
1369         lw->utility_box = NULL;
1370
1371         layout_geometry_get_dividers(lw, &lw->div_h, &lw->div_v);
1372
1373         /* clear it all */
1374
1375         gtk_widget_hide(old_image->widget);
1376         gtk_widget_ref(old_image->widget);
1377         gtk_container_remove(GTK_CONTAINER(old_image->widget->parent), old_image->widget);
1378
1379         lw->h_pane = NULL;
1380         lw->v_pane = NULL;
1381
1382         lw->toolbar = NULL;
1383         lw->thumb_button = NULL;
1384         lw->path_entry = NULL;
1385         lw->dir_view = NULL;
1386         lw->vdl = NULL;
1387         lw->vdt = NULL;
1388
1389         lw->file_view = NULL;
1390         lw->vfl = NULL;
1391         lw->vfi = NULL;
1392
1393         lw->info_box = NULL;
1394         lw->info_progress_bar = NULL;
1395         lw->info_sort = NULL;
1396         lw->info_status = NULL;
1397         lw->info_details = NULL;
1398         lw->info_zoom = NULL;
1399
1400 #if 0
1401         if (lw->menu_fact) g_object_unref(G_OBJECT(lw->menu_fact));
1402         lw->menu_fact = NULL;
1403 #endif
1404         if (lw->ui_manager) g_object_unref(lw->ui_manager);
1405         lw->ui_manager = NULL;
1406         lw->action_group = NULL;
1407
1408         gtk_container_remove(GTK_CONTAINER(lw->main_box), lw->group_box);
1409         lw->group_box = NULL;
1410
1411         /* re-fill */
1412
1413         layout_grid_setup(lw);
1414         layout_tools_hide(lw, lw->tools_hidden);
1415
1416         layout_list_sync_sort(lw);
1417         layout_util_sync(lw);
1418         layout_status_update_all(lw);
1419
1420         /* sync */
1421
1422         if (image_get_path(old_image))
1423                 {
1424                 layout_set_path(lw, image_get_path(old_image));
1425                 }
1426         else
1427                 {
1428                 layout_set_path(lw, path);
1429                 }
1430         image_change_from_image(lw->image, old_image);
1431         image_top_window_set_sync(lw->image, (lw->tools_float || lw->tools_hidden));
1432
1433         /* clean up */
1434
1435         gtk_widget_unref(old_image->widget);
1436         g_free(path);
1437 }
1438
1439 void layout_styles_update(void)
1440 {
1441         GList *work;
1442
1443         work = layout_window_list;
1444         while (work)
1445                 {
1446                 LayoutWindow *lw = work->data;
1447                 work = work->next;
1448
1449                 layout_style_set(lw, layout_style, layout_order);
1450                 }
1451 }
1452
1453 void layout_colors_update(void)
1454 {
1455         GList *work;
1456
1457         work = layout_window_list;
1458         while (work)
1459                 {
1460                 LayoutWindow *lw = work->data;
1461                 work = work->next;
1462
1463                 if (lw->image) image_background_set_black(lw->image, black_window_background);
1464                 }
1465 }
1466
1467 void layout_tools_float_toggle(LayoutWindow *lw)
1468 {
1469         gint popped;
1470
1471         if (!lw) return;
1472
1473         if (!lw->tools_hidden)
1474                 {
1475                 popped = !lw->tools_float;
1476                 }
1477         else
1478                 {
1479                 popped = TRUE;
1480                 }
1481
1482         if (lw->tools_float == popped)
1483                 {
1484                 if (popped && lw->tools_hidden)
1485                         {
1486                         layout_tools_float_set(lw, popped, FALSE);
1487                         }
1488                 }
1489         else
1490                 {
1491                 if (lw->tools_float)
1492                         {
1493                         layout_tools_float_set(lw, FALSE, FALSE);
1494                         }
1495                 else
1496                         {
1497                         layout_tools_float_set(lw, TRUE, FALSE);
1498                         }
1499                 }
1500 }
1501
1502 void layout_tools_hide_toggle(LayoutWindow *lw)
1503 {
1504         if (!lw) return;
1505
1506         layout_tools_float_set(lw, lw->tools_float, !lw->tools_hidden);
1507 }
1508
1509 void layout_tools_float_set(LayoutWindow *lw, gint popped, gint hidden)
1510 {
1511         if (!layout_valid(&lw)) return;
1512
1513         if (lw->tools_float == popped && lw->tools_hidden == hidden) return;
1514
1515         if (lw->tools_float == popped && lw->tools_float && lw->tools)
1516                 {
1517                 layout_tools_hide(lw, hidden);
1518                 return;
1519                 }
1520
1521         lw->tools_float = popped;
1522         lw->tools_hidden = hidden;
1523
1524         layout_style_set(lw, -1, NULL);
1525 }
1526
1527 gint layout_tools_float_get(LayoutWindow *lw, gint *popped, gint *hidden)
1528 {
1529         if (!layout_valid(&lw)) return FALSE;
1530
1531         *popped = lw->tools_float;
1532         *hidden = lw->tools_hidden;
1533
1534         return TRUE;
1535 }
1536
1537 void layout_toolbar_toggle(LayoutWindow *lw)
1538 {
1539         if (!layout_valid(&lw)) return;
1540         if (!lw->toolbar) return;
1541
1542         lw->toolbar_hidden = !lw->toolbar_hidden;
1543
1544         if (lw->toolbar_hidden)
1545                 {
1546                 if (GTK_WIDGET_VISIBLE(lw->toolbar)) gtk_widget_hide(lw->toolbar);
1547                 }
1548         else
1549                 {
1550                 if (!GTK_WIDGET_VISIBLE(lw->toolbar)) gtk_widget_show(lw->toolbar);
1551                 }
1552 }
1553
1554 gint layout_toolbar_hidden(LayoutWindow *lw)
1555 {
1556         if (!layout_valid(&lw)) return TRUE;
1557
1558         return lw->toolbar_hidden;
1559 }
1560
1561 /*
1562  *-----------------------------------------------------------------------------
1563  * base
1564  *-----------------------------------------------------------------------------
1565  */
1566
1567 void layout_close(LayoutWindow *lw)
1568 {
1569         if (layout_window_list && layout_window_list->next)
1570                 {
1571                 layout_free(lw);
1572                 }
1573         else
1574                 {
1575                 exit_gqview();
1576                 }
1577 }
1578
1579 void layout_free(LayoutWindow *lw)
1580 {
1581         if (!lw) return;
1582
1583         layout_window_list = g_list_remove(layout_window_list, lw);
1584
1585         if (lw->last_time_id != -1)
1586                 {
1587                 g_source_remove(lw->last_time_id);
1588                 }
1589
1590         layout_bars_close(lw);
1591
1592 #if 0
1593         if (lw->menu_fact) g_object_unref(G_OBJECT(lw->menu_fact));
1594 #endif
1595         if (lw->tooltips) g_object_unref(G_OBJECT(lw->tooltips));
1596         gtk_widget_destroy(lw->window);
1597
1598         g_free(lw->path);
1599
1600         g_free(lw);
1601 }
1602
1603 static gint layout_delete_cb(GtkWidget *widget, GdkEventAny *event, gpointer data)
1604 {
1605         LayoutWindow *lw = data;
1606
1607         layout_close(lw);
1608         return TRUE;
1609 }
1610
1611 LayoutWindow *layout_new(const gchar *path, gint popped, gint hidden)
1612 {
1613         LayoutWindow *lw;
1614         GdkGeometry geometry;
1615         GdkWindowHints hints;
1616
1617         lw = g_new0(LayoutWindow, 1);
1618
1619         lw->thumbs_enabled = thumbnails_enabled;
1620         lw->sort_method = SORT_NAME;
1621         lw->sort_ascend = TRUE;
1622
1623         lw->tools_float = popped;
1624         lw->tools_hidden = hidden;
1625
1626         lw->toolbar_hidden = toolbar_hidden;
1627
1628         lw->utility_box = NULL;
1629         lw->bar_sort = NULL;
1630         lw->bar_sort_enabled = FALSE;
1631         lw->bar_exif = NULL;
1632         lw->bar_exif_enabled = FALSE;
1633         lw->bar_exif_size = -1;
1634         lw->bar_exif_advanced = FALSE;
1635
1636         lw->full_screen_overlay_id = -1;
1637         lw->full_screen_overlay_on = FALSE;
1638
1639         /* default layout */
1640
1641         layout_config_parse(layout_style, layout_order,
1642                             &lw->dir_location,  &lw->file_location, &lw->image_location);
1643         lw->tree_view = layout_view_tree;
1644         lw->icon_view = layout_view_icons;
1645
1646         /* divider positions */
1647
1648         if (save_window_positions)
1649                 {
1650                 lw->div_h = window_hdivider_pos;
1651                 lw->div_v = window_vdivider_pos;
1652                 lw->div_float = float_window_divider;
1653                 }
1654         else
1655                 {
1656                 lw->div_h = MAIN_WINDOW_DIV_HPOS;
1657                 lw->div_v = MAIN_WINDOW_DIV_VPOS;
1658                 lw->div_float = MAIN_WINDOW_DIV_VPOS;
1659                 }
1660
1661         /* window */
1662
1663         lw->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1664         gtk_window_set_resizable(GTK_WINDOW(lw->window), TRUE);
1665
1666         gtk_window_set_title(GTK_WINDOW(lw->window), "GQview");
1667         gtk_window_set_wmclass(GTK_WINDOW(lw->window), "gqview", "GQview");
1668         gtk_container_set_border_width(GTK_CONTAINER(lw->window), 0);
1669
1670         window_set_icon(lw->window, NULL, NULL);
1671
1672         if (save_window_positions)
1673                 {
1674                 hints = GDK_HINT_USER_POS | GDK_HINT_USER_SIZE;
1675                 }
1676         else
1677                 {
1678                 hints = 0;
1679                 }
1680
1681         geometry.min_width = 32;
1682         geometry.min_height = 32;
1683         geometry.base_width = MAINWINDOW_DEF_WIDTH;
1684         geometry.base_height = MAINWINDOW_DEF_HEIGHT;
1685         gtk_window_set_geometry_hints(GTK_WINDOW(lw->window), NULL, &geometry,
1686                                       GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | hints);
1687
1688         if (save_window_positions)
1689                 {
1690                 gtk_window_set_default_size(GTK_WINDOW(lw->window), main_window_w, main_window_h);
1691                 if (!layout_window_list)
1692                         {
1693                         gtk_window_move(GTK_WINDOW(lw->window), main_window_x, main_window_y);
1694                         if (main_window_maximized) gtk_window_maximize(GTK_WINDOW(lw->window));
1695                         }
1696                 }
1697         else
1698                 {
1699                 gtk_window_set_default_size(GTK_WINDOW(lw->window), MAINWINDOW_DEF_WIDTH, MAINWINDOW_DEF_HEIGHT);
1700                 }
1701
1702         g_signal_connect(G_OBJECT(lw->window), "delete_event",
1703                          G_CALLBACK(layout_delete_cb), lw);
1704
1705         layout_keyboard_init(lw, lw->window);
1706
1707 #if 0
1708         gtk_widget_realize(lw->window);
1709 #endif
1710
1711         lw->tooltips = gtk_tooltips_new();
1712         g_object_ref(G_OBJECT(lw->tooltips));
1713         gtk_object_sink(GTK_OBJECT(lw->tooltips));
1714
1715         lw->main_box = gtk_vbox_new(FALSE, 0);
1716         gtk_container_add(GTK_CONTAINER(lw->window), lw->main_box);
1717         gtk_widget_show(lw->main_box);
1718
1719         layout_grid_setup(lw);
1720         image_top_window_set_sync(lw->image, (lw->tools_float || lw->tools_hidden));
1721
1722         layout_util_sync(lw);
1723         layout_status_update_all(lw);
1724
1725         if (path)
1726                 {
1727                 layout_set_path(lw, path);
1728                 }
1729         else
1730                 {
1731                 GdkPixbuf *pixbuf;
1732
1733                 pixbuf = pixbuf_inline(PIXBUF_INLINE_LOGO);
1734                 image_change_pixbuf(lw->image, pixbuf, 1.0);
1735                 gdk_pixbuf_unref(pixbuf);
1736                 }
1737
1738         /* set up the time stat timeout */
1739         lw->last_time = 0;
1740         lw->last_time_id = g_timeout_add(5000, layout_check_for_update_cb, lw);
1741
1742         gtk_widget_show(lw->window);
1743         layout_tools_hide(lw, lw->tools_hidden);
1744
1745         layout_window_list = g_list_append(layout_window_list, lw);
1746
1747         return lw;
1748 }
1749
1750 /*
1751  *-----------------------------------------------------------------------------
1752  * maintenance (for rename, move, remove)
1753  *-----------------------------------------------------------------------------
1754  */
1755
1756 static void layout_real_time_update(LayoutWindow *lw)
1757 {
1758         /* this resets the last time stamp of path so that a refresh does not occur
1759          * from an internal file operation.
1760          */
1761
1762         if (lw->path) lw->last_time = filetime(lw->path);
1763 }
1764
1765 static void layout_real_renamed(LayoutWindow *lw, const gchar *source, const gchar *dest)
1766 {
1767         gint update = FALSE;
1768
1769         if (lw->image) layout_image_maint_renamed(lw, source, dest);
1770
1771         if (lw->vfl) update |= vflist_maint_renamed(lw->vfl, source, dest);
1772         if (lw->vfi) update |= vficon_maint_renamed(lw->vfi, source, dest);
1773
1774         if (update) layout_real_time_update(lw);
1775 }
1776
1777 static void layout_real_removed(LayoutWindow *lw, const gchar *path, GList *ignore_list)
1778 {
1779         gint update = FALSE;
1780
1781         if (lw->image) layout_image_maint_removed(lw, path);
1782
1783         if (lw->vfl) update |= vflist_maint_removed(lw->vfl, path, ignore_list);
1784         if (lw->vfi) update |= vficon_maint_removed(lw->vfi, path, ignore_list);
1785
1786         if (update) layout_real_time_update(lw);
1787 }
1788
1789 static void layout_real_moved(LayoutWindow *lw, const gchar *source, const gchar *dest, GList *ignore_list)
1790 {
1791         gint update = FALSE;
1792
1793         if (lw->image) layout_image_maint_moved(lw, source, dest);
1794
1795         if (lw->vfl) update |= vflist_maint_moved(lw->vfl, source, dest, ignore_list);
1796         if (lw->vfi) update |= vficon_maint_moved(lw->vfi, source, dest, ignore_list);
1797
1798         if (update) layout_real_time_update(lw);
1799 }
1800
1801 void layout_maint_renamed(const gchar *source, const gchar *dest)
1802 {
1803         GList *work = layout_window_list;
1804         while (work)
1805                 {
1806                 LayoutWindow *lw = work->data;
1807                 work = work->next;
1808
1809                 layout_real_renamed(lw, source, dest);
1810                 }
1811 }
1812
1813 void layout_maint_removed(const gchar *path, GList *ignore_list)
1814 {
1815         GList *work = layout_window_list;
1816         while (work)
1817                 {
1818                 LayoutWindow *lw = work->data;
1819                 work = work->next;
1820
1821                 layout_real_removed(lw, path, ignore_list);
1822                 }
1823 }
1824
1825 void layout_maint_moved(const gchar *source, const gchar *dest, GList *ignore_list)
1826 {
1827         GList *work = layout_window_list;
1828         while (work)
1829                 {
1830                 LayoutWindow *lw = work->data;
1831                 work = work->next;
1832
1833                 layout_real_moved(lw, source, dest, ignore_list);
1834                 }
1835 }