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