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