479703a86e390ea207772213b10c594a152a8f93
[geeqie.git] / src / preferences.c
1 /*
2  * GQview
3  * (C) 2006 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
13 #include "gqview.h"
14 #include "preferences.h"
15
16 #include "cache_maint.h"
17 #include "editors.h"
18 #include "filelist.h"
19 #include "fullscreen.h"
20 #include "image.h"
21 #include "img-view.h"
22 #include "layout_config.h"
23 #include "layout_util.h"
24 #include "pixbuf_util.h"
25 #include "slideshow.h"
26 #include "utilops.h"
27 #include "ui_fileops.h"
28 #include "ui_misc.h"
29 #include "ui_tabcomp.h"
30 #include "ui_utildlg.h"
31
32 #include "icons/config.xpm"
33
34 #include <math.h>
35
36
37 #define EDITOR_NAME_MAX_LENGTH 32
38 #define EDITOR_COMMAND_MAX_LENGTH 1024
39
40
41 typedef struct _ThumbSize ThumbSize;
42 struct _ThumbSize
43 {
44         gint w;
45         gint h;
46 };
47
48 static ThumbSize thumb_size_list[] =
49 {
50         { 24, 24 },
51         { 32, 32 },
52         { 48, 48 },
53         { 64, 64 },
54         { 96, 72 },
55         { 96, 96 },
56         { 128, 96 },
57         { 128, 128 },
58         { 160, 120 },
59         { 160, 160 },
60         { 192, 144 },
61         { 192, 192 },
62         { 256, 192 },
63         { 256, 256 }
64 };
65
66 enum {
67         FE_ENABLE,
68         FE_EXTENSION,
69         FE_DESCRIPTION
70 };
71
72 /* config memory values */
73 static gint startup_path_enable_c;
74 static gint confirm_delete_c;
75 static gint enable_delete_key_c;
76 static gint safe_delete_enable_c;
77 static gint safe_delete_size_c;
78 static gint restore_tool_c;
79 static gint save_window_positions_c;
80 static gint zoom_mode_c;
81 static gint two_pass_zoom_c;
82 static gint fit_window_c;
83 static gint limit_window_size_c;
84 static gint zoom_to_fit_expands_c;
85 static gint max_window_size_c;
86 static gint progressive_key_scrolling_c;
87 static gint thumb_max_width_c;
88 static gint thumb_max_height_c;
89 static gint enable_thumb_caching_c;
90 static gint enable_thumb_dirs_c;
91 static gint thumbnail_fast_c;
92 #if 0
93 static gint use_xvpics_thumbnails_c;
94 #endif
95 static gint thumbnail_spec_standard_c;
96 static gint enable_metadata_dirs_c;
97 static gint show_dot_files_c;
98 static gint file_filter_disable_c;
99 static gint file_sort_case_sensitive_c;
100 static gint slideshow_delay_c;
101 static gint slideshow_random_c;
102 static gint slideshow_repeat_c;
103
104 static gint mousewheel_scrolls_c;
105
106 static gint enable_in_place_rename_c;
107
108 static gint collection_rectangular_selection_c;
109
110 static gint tile_cache_max_c;
111
112 static gint thumbnail_quality_c;
113 static gint zoom_quality_c;
114
115 static gint zoom_increment_c;
116
117 static gint enable_read_ahead_c;
118
119 static gint black_window_background_c;
120
121 static gint fullscreen_screen_c;
122 static gint fullscreen_clean_flip_c;
123 static gint fullscreen_disable_saver_c;
124 static gint fullscreen_above_c;
125
126 static gint dupe_custom_threshold_c;
127
128 static GtkWidget *configwindow = NULL;
129 static GtkWidget *startup_path_entry;
130 static GtkListStore *filter_store = NULL;
131 static GtkWidget *editor_name_entry[GQVIEW_EDITOR_SLOTS];
132 static GtkWidget *editor_command_entry[GQVIEW_EDITOR_SLOTS];
133
134 static GtkWidget *layout_widget;
135
136 static GtkWidget *safe_delete_path_entry;
137
138 static gint tree_descend_subdirs_c;
139
140 static gint update_on_time_change_c;
141 static gint exif_rotate_enable_c;
142
143
144 /*
145  *-----------------------------------------------------------------------------
146  * option widget callbacks (private)
147  *-----------------------------------------------------------------------------
148  */ 
149
150 static void startup_path_set_current(GtkWidget *widget, gpointer data)
151 {
152         gtk_entry_set_text(GTK_ENTRY(startup_path_entry), layout_get_path(NULL));
153 }
154
155 static void zoom_mode_original_cb(GtkWidget *widget, gpointer data)
156 {
157         if (GTK_TOGGLE_BUTTON (widget)->active)
158                 zoom_mode_c = ZOOM_RESET_ORIGINAL;
159 }
160
161 static void zoom_mode_fit_cb(GtkWidget *widget, gpointer data)
162 {
163         if (GTK_TOGGLE_BUTTON (widget)->active)
164                 zoom_mode_c = ZOOM_RESET_FIT_WINDOW;
165 }
166
167 static void zoom_mode_none_cb(GtkWidget *widget, gpointer data)
168 {
169         if (GTK_TOGGLE_BUTTON (widget)->active)
170                 zoom_mode_c = ZOOM_RESET_NONE;
171 }
172
173 static void zoom_increment_cb(GtkWidget *spin, gpointer data)
174 {
175         zoom_increment_c = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 10.0 + 0.01);
176 }
177
178 static void slideshow_delay_cb(GtkWidget *spin, gpointer data)
179 {
180         slideshow_delay_c = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
181                                    (double)SLIDESHOW_SUBSECOND_PRECISION + 0.01);
182 }
183
184 /*
185  *-----------------------------------------------------------------------------
186  * sync progam to config window routine (private)
187  *-----------------------------------------------------------------------------
188  */ 
189
190 static void config_window_apply(void)
191 {
192         const gchar *buf;
193         gchar *l_conf;
194         gint new_style;
195         gint i;
196         gint refresh = FALSE;
197
198         for(i = 0; i < GQVIEW_EDITOR_SLOTS; i++)
199                 {
200                 g_free(editor_name[i]);
201                 editor_name[i] = NULL;
202                 buf = gtk_entry_get_text(GTK_ENTRY(editor_name_entry[i]));
203                 if (buf && strlen(buf) > 0) editor_name[i] = g_strdup(buf);
204
205                 g_free(editor_command[i]);
206                 editor_command[i] = NULL;
207                 buf = gtk_entry_get_text(GTK_ENTRY(editor_command_entry[i]));
208                 if (buf && strlen(buf) > 0) editor_command[i] = g_strdup(buf);
209                 }
210         layout_edit_update_all();
211
212         g_free(startup_path);
213         startup_path = NULL;
214         buf = gtk_entry_get_text(GTK_ENTRY(startup_path_entry));
215         if (buf && strlen(buf) > 0) startup_path = remove_trailing_slash(buf);
216
217         g_free(safe_delete_path);
218         safe_delete_path = NULL;
219         buf = gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry));
220         if (buf && strlen(buf) > 0) safe_delete_path = remove_trailing_slash(buf);
221
222         if (show_dot_files != show_dot_files_c) refresh = TRUE;
223         if (file_sort_case_sensitive != file_sort_case_sensitive_c) refresh = TRUE;
224         if (file_filter_disable != file_filter_disable_c) refresh = TRUE;
225
226         startup_path_enable = startup_path_enable_c;
227         confirm_delete = confirm_delete_c;
228         enable_delete_key = enable_delete_key_c;
229         safe_delete_enable = safe_delete_enable_c;
230         safe_delete_size = safe_delete_size_c;
231         restore_tool = restore_tool_c;
232         save_window_positions = save_window_positions_c;
233         zoom_mode = zoom_mode_c;
234         two_pass_zoom = two_pass_zoom_c;
235         fit_window = fit_window_c;
236         limit_window_size = limit_window_size_c;
237         zoom_to_fit_expands = zoom_to_fit_expands_c;
238         max_window_size = max_window_size_c;
239         progressive_key_scrolling = progressive_key_scrolling_c;
240         thumb_max_width = thumb_max_width_c;
241         thumb_max_height = thumb_max_height_c;
242         enable_thumb_caching = enable_thumb_caching_c;
243         enable_thumb_dirs = enable_thumb_dirs_c;
244         thumbnail_fast = thumbnail_fast_c;
245 #if 0
246         use_xvpics_thumbnails = use_xvpics_thumbnails_c;
247 #endif
248         thumbnail_spec_standard = thumbnail_spec_standard_c;
249         enable_metadata_dirs = enable_metadata_dirs_c;
250         show_dot_files = show_dot_files_c;
251         file_sort_case_sensitive = file_sort_case_sensitive_c;
252         file_filter_disable = file_filter_disable_c;
253
254         slideshow_random = slideshow_random_c;
255         slideshow_repeat = slideshow_repeat_c;
256         slideshow_delay = slideshow_delay_c;
257
258         mousewheel_scrolls = mousewheel_scrolls_c;
259
260         enable_in_place_rename = enable_in_place_rename_c;
261
262         collection_rectangular_selection = collection_rectangular_selection_c;
263
264         tile_cache_max = tile_cache_max_c;
265
266         thumbnail_quality = thumbnail_quality_c;
267         zoom_quality = zoom_quality_c;
268
269         zoom_increment = zoom_increment_c;
270
271         enable_read_ahead = enable_read_ahead_c;
272
273         if (black_window_background != black_window_background_c)
274                 {
275                 black_window_background = black_window_background_c;
276
277                 layout_colors_update();
278                 view_window_colors_update();
279                 }
280
281         fullscreen_screen = fullscreen_screen_c;
282         fullscreen_clean_flip = fullscreen_clean_flip_c;
283         fullscreen_disable_saver = fullscreen_disable_saver_c;
284         fullscreen_above = fullscreen_above_c;
285
286         update_on_time_change = update_on_time_change_c;
287         exif_rotate_enable = exif_rotate_enable_c;
288
289         dupe_custom_threshold = dupe_custom_threshold_c;
290
291         tree_descend_subdirs = tree_descend_subdirs_c;
292
293         l_conf = layout_config_get(layout_widget, &new_style);
294
295         if (new_style != layout_style ||
296             (l_conf == NULL) != (layout_order == NULL) ||
297             !layout_order ||
298             strcmp(buf, layout_order) != 0)
299                 {
300                 if (refresh) filter_rebuild();
301                 refresh = FALSE;
302
303                 g_free(layout_order);
304                 layout_order = l_conf;
305                 l_conf = NULL;
306
307                 layout_style = new_style;
308
309                 layout_styles_update();
310                 }
311
312         g_free(l_conf);
313
314         image_options_sync();
315
316         if (refresh)
317                 {
318                 filter_rebuild();
319                 layout_refresh(NULL);
320                 }
321 }
322
323 /*
324  *-----------------------------------------------------------------------------
325  * config window main button callbacks (private)
326  *-----------------------------------------------------------------------------
327  */ 
328
329 static void config_window_close_cb(GtkWidget *widget, gpointer data)
330 {
331         gtk_widget_destroy(configwindow);
332         configwindow = NULL;
333         filter_store = NULL;
334 }
335
336 static gint config_window_delete(GtkWidget *w, GdkEventAny *event, gpointer data)
337 {
338         config_window_close_cb(NULL, NULL);
339         return TRUE;
340 }
341
342 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
343 {
344         config_window_apply();
345         config_window_close_cb(NULL, NULL);
346 }
347
348 static void config_window_apply_cb(GtkWidget *widget, gpointer data)
349 {
350         config_window_apply();
351 }
352
353 /*
354  *-----------------------------------------------------------------------------
355  * config window setup (private)
356  *-----------------------------------------------------------------------------
357  */ 
358
359 static void quality_menu_cb(GtkWidget *combo, gpointer data)
360 {
361         gint *option = data;
362
363         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
364                 {
365                 case 0:
366                 default:
367                         *option = GDK_INTERP_NEAREST;
368                         break;
369                 case 1:
370                         *option = GDK_INTERP_TILES;
371                         break;
372                 case 2:
373                         *option = GDK_INTERP_BILINEAR;
374                         break;
375                 case 3:
376                         *option = GDK_INTERP_HYPER;
377                         break;
378                 }
379 }
380
381 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
382                              gint option, gint *option_c)
383 {
384         GtkWidget *combo;
385         gint current = 0;
386
387         *option_c = option;
388
389         pref_table_label(table, column, row, text, 0.0);
390
391         combo = gtk_combo_box_new_text();
392
393         gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Nearest (worst, but fastest)"));
394         if (option == GDK_INTERP_NEAREST) current = 0;
395         gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Tiles"));
396         if (option == GDK_INTERP_TILES) current = 1;
397         gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Bilinear"));
398         if (option == GDK_INTERP_BILINEAR) current = 2;
399         gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Hyper (best, but slowest)"));
400         if (option == GDK_INTERP_HYPER) current = 3;
401
402         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
403
404         g_signal_connect(G_OBJECT(combo), "changed",
405                          G_CALLBACK(quality_menu_cb), option_c);
406
407         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
408                          GTK_EXPAND | GTK_FILL, FALSE, 0, 0);
409         gtk_widget_show(combo);
410 }
411
412 #if 0
413 static void add_dither_menu(gint option, gint *option_c, gchar *text, GtkWidget *box)
414 {
415         GtkWidget *hbox;
416         GtkWidget *omenu;
417         GtkWidget *menu;
418
419         *option_c = option;
420
421         hbox = pref_box_new(box, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
422         pref_label_new(hbox, text);
423
424         omenu = gtk_option_menu_new();
425         menu = gtk_menu_new();
426
427         add_menu_item(menu, _("None"), option_c, (gint)GDK_RGB_DITHER_NONE);
428         add_menu_item(menu, _("Normal"), option_c, (gint)GDK_RGB_DITHER_NORMAL);
429         add_menu_item(menu, _("Best"), option_c, (gint)GDK_RGB_DITHER_MAX);
430
431         gtk_option_menu_set_menu(GTK_OPTION_MENU(omenu), menu);
432         gtk_option_menu_set_history(GTK_OPTION_MENU(omenu), *option_c);
433
434         gtk_box_pack_start(GTK_BOX(hbox), omenu, FALSE, FALSE, 0);
435         gtk_widget_show(omenu);
436 }
437 #endif
438
439 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
440 {
441         gint n;
442
443         n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
444
445         if (n >= 0 && n < sizeof(thumb_size_list) / sizeof(ThumbSize))
446                 {
447                 thumb_max_width_c = thumb_size_list[n].w;
448                 thumb_max_height_c = thumb_size_list[n].h;
449                 }
450         else if (n > 0)
451                 {
452                 thumb_max_width_c = thumb_max_width;
453                 thumb_max_height_c = thumb_max_height;
454                 }
455 }
456
457 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
458 {
459         GtkWidget *combo;
460         gint current;
461         gint last_w, last_h;
462         gint i;
463         gint c;
464
465         thumb_max_width_c = thumb_max_width;
466         thumb_max_height_c = thumb_max_height;
467
468         pref_table_label(table, column, row, text, 0.0);
469
470         combo = gtk_combo_box_new_text();
471
472         last_w = last_h = 0;
473         current = -1;
474         i = 0;
475         c = TRUE;
476         while (c)
477                 {
478                 gint w, h;
479
480                 w = thumb_size_list[i].w;
481                 h = thumb_size_list[i].h;
482
483                 if ( w > 0 && h > 0)
484                         {
485                         gchar *buf;
486
487                         buf = g_strdup_printf("%d x %d", w, h);
488                         gtk_combo_box_append_text(GTK_COMBO_BOX(combo), buf);
489                         g_free(buf);
490
491                         if (w == thumb_max_width && h == thumb_max_height) current = i;
492
493                         last_w = w;
494                         last_h = h;
495                         }
496                 else
497                         {
498                         c = FALSE;
499                         }
500                 i++;
501                 }
502
503         if (current == -1)
504                 {
505                 gchar *buf;
506
507                 buf = g_strdup_printf("%s %d x %d", _("Custom"), thumb_max_width, thumb_max_height);
508                 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), buf);
509                 g_free(buf);
510
511                 current = i - 1;
512                 }
513
514         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
515         g_signal_connect(G_OBJECT(combo), "changed",
516                          G_CALLBACK(thumb_size_menu_cb), NULL);
517
518         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
519                          GTK_EXPAND | GTK_FILL, FALSE, 0, 0);
520         gtk_widget_show(combo);
521 }
522
523 static void filter_store_populate(void)
524 {
525         GList *work;
526
527         if (!filter_store) return;
528
529         gtk_list_store_clear(filter_store);
530
531         work = filter_get_list();
532         while (work)
533                 {
534                 FilterEntry *fe;
535                 GtkTreeIter iter;
536
537                 fe = work->data;
538                 work = work->next;
539
540                 gtk_list_store_append(filter_store, &iter);
541                 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
542                 }
543 }
544
545 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
546                                      gchar *new_text, gpointer data)
547 {
548         GtkWidget *model = data;
549         FilterEntry *fe = data;
550         GtkTreePath *tpath;
551         GtkTreeIter iter;
552
553         if (!new_text || strlen(new_text) < 1) return;
554
555         tpath = gtk_tree_path_new_from_string(path_str);
556         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
557         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
558
559         g_free(fe->extensions);
560         fe->extensions = g_strdup(new_text);
561
562         gtk_tree_path_free(tpath);
563         filter_rebuild();
564 }
565
566 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
567                                       gchar *new_text, gpointer data)
568 {
569         GtkWidget *model = data;
570         FilterEntry *fe;
571         GtkTreePath *tpath;
572         GtkTreeIter iter;
573
574         if (!new_text || strlen(new_text) < 1) return;
575
576         tpath = gtk_tree_path_new_from_string(path_str);
577         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
578         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
579
580         g_free(fe->description);
581         fe->description = g_strdup(new_text);
582
583         gtk_tree_path_free(tpath);
584 }
585
586 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
587                                    gchar *path_str, gpointer data)
588 {
589         GtkWidget *model = data;
590         FilterEntry *fe;
591         GtkTreePath *tpath;
592         GtkTreeIter iter;
593
594         tpath = gtk_tree_path_new_from_string(path_str);
595         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
596         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
597
598         fe->enabled = !fe->enabled;
599
600         gtk_tree_path_free(tpath);
601         filter_rebuild();
602 }
603
604 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
605                             GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
606 {
607         FilterEntry *fe;
608
609         gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
610
611         switch(GPOINTER_TO_INT(data))
612                 {
613                 case FE_ENABLE:
614                         g_object_set(GTK_CELL_RENDERER(cell),
615                                      "active", fe->enabled, NULL);
616                         break;
617                 case FE_EXTENSION:
618                         g_object_set(GTK_CELL_RENDERER(cell),
619                                      "text", fe->extensions, NULL);
620                         break;
621                 case FE_DESCRIPTION:
622                         g_object_set(GTK_CELL_RENDERER(cell),
623                                      "text", fe->description, NULL);
624                         break;
625                 }
626 }
627
628 static void filter_add_cb(GtkWidget *widget, gpointer data)
629 {
630         filter_add_unique("description", ".new", TRUE);
631         filter_store_populate();
632
633         /* FIXME: implement the scroll to/select row stuff for tree view */
634 }
635
636 static void filter_remove_cb(GtkWidget *widget, gpointer data)
637 {
638         GtkWidget *filter_view = data;
639         GtkTreeSelection *selection;
640         GtkTreeIter iter;
641         FilterEntry *fe;
642
643         if (!filter_store) return;
644         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
645         if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
646         gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
647         if (!fe) return;
648
649         filter_remove_entry(fe);
650         filter_rebuild();
651         filter_store_populate();
652 }
653
654 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
655 {
656         filter_reset();
657         filter_add_defaults();
658         filter_rebuild();
659         filter_store_populate();
660 }
661
662 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
663 {
664         /* no op, only so cancel button appears */
665 }
666
667 static void filter_default_cb(GtkWidget *widget, gpointer data)
668 {
669         GenericDialog *gd;
670
671         gd = generic_dialog_new(_("Reset filters"),
672                                 "GQview", "reset_filter", widget, TRUE,
673                                 dummy_cancel_cb, NULL);
674         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
675                                    _("This will reset the file filters to the defaults.\nContinue?"));
676         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
677         gtk_widget_show(gd->dialog);
678 }
679
680 static void filter_disable_cb(GtkWidget* widget, gpointer data)
681 {
682         GtkWidget *frame = data;
683
684         gtk_widget_set_sensitive(frame,
685                                  !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
686 }
687
688 static void editor_default_ok_cb(GenericDialog *gd, gpointer data)
689 {
690         gint i;
691
692         editor_reset_defaults();
693         if (!configwindow) return;
694
695         for (i = 0; i < GQVIEW_EDITOR_SLOTS; i++)
696                 {
697                 gtk_entry_set_text(GTK_ENTRY(editor_name_entry[i]),
698                                    (editor_name[i]) ? editor_name[i] : "");
699                 gtk_entry_set_text(GTK_ENTRY(editor_command_entry[i]),
700                                    (editor_command[i]) ? editor_command[i] : "");
701                 }
702 }
703
704 static void editor_default_cb(GtkWidget *widget, gpointer data)
705 {
706         GenericDialog *gd;
707
708         gd = generic_dialog_new(_("Reset editors"),
709                                 "GQview", "reset_filter", widget, TRUE,
710                                 dummy_cancel_cb, NULL);
711         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset editors"),
712                                    _("This will reset the edit commands to the defaults.\nContinue?"));
713         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, editor_default_ok_cb, TRUE);
714         gtk_widget_show(gd->dialog);
715 }
716
717 static void editor_help_cb(GtkWidget *widget, gpointer data)
718 {
719         help_window_show("editors");
720 }
721
722 static void safe_delete_view_cb(GtkWidget* widget, gpointer data)
723 {
724         layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
725 }
726
727 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
728 {
729         file_util_trash_clear();
730 }
731
732 static void safe_delete_clear_cb(GtkWidget* widget, gpointer data)
733 {
734         GenericDialog *gd;
735         GtkWidget *entry;
736         gd = generic_dialog_new(_("Clear trash"),
737                                 "GQview", "clear_trash", widget, TRUE,
738                                 dummy_cancel_cb, NULL);
739         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
740                                     _("This will remove the trash contents."));
741         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
742         entry = gtk_entry_new();
743         GTK_WIDGET_UNSET_FLAGS(entry, GTK_CAN_FOCUS);
744         gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
745         if (safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), safe_delete_path);
746         gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
747         gtk_widget_show(entry);
748         gtk_widget_show(gd->dialog);
749 }
750
751 static void config_window_create(void)
752 {
753         GtkWidget *win_vbox;
754         GtkWidget *hbox;
755         GtkWidget *notebook;
756         GtkWidget *frame;
757         GtkWidget *label;
758         GtkWidget *vbox;
759         GtkWidget *group;
760         GtkWidget *subgroup;
761         GtkWidget *button;
762         GtkWidget *tabcomp;
763         GtkWidget *ct_button;
764         GtkWidget *table;
765         GtkWidget *spin;
766         GtkWidget *scrolled;
767         GtkWidget *viewport;
768         GtkWidget *filter_view;
769         GtkCellRenderer *renderer;
770         GtkTreeSelection *selection;
771         GtkTreeViewColumn *column;
772         gint i;
773
774         configwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
775         gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
776         g_signal_connect(G_OBJECT (configwindow), "delete_event",
777                          G_CALLBACK(config_window_delete), NULL);
778         gtk_window_set_resizable(GTK_WINDOW(configwindow), FALSE);
779         gtk_window_set_title(GTK_WINDOW(configwindow), _("GQview Preferences"));
780         gtk_window_set_wmclass(GTK_WINDOW(configwindow), "config", "GQview");
781         gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
782
783         window_set_icon(configwindow, (const gchar **)config_xpm, NULL);
784
785         win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
786         gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
787         gtk_widget_show(win_vbox);
788
789         hbox = gtk_hbutton_box_new();
790         gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
791         gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
792         gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
793         gtk_widget_show(hbox);
794
795         button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
796                                  G_CALLBACK(config_window_ok_cb), NULL);
797         gtk_container_add(GTK_CONTAINER(hbox), button);
798         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
799         gtk_widget_grab_default(button);
800         gtk_widget_show(button);
801
802         ct_button = button;
803
804         button = pref_button_new(NULL, GTK_STOCK_APPLY, NULL, FALSE,
805                                  G_CALLBACK(config_window_apply_cb), NULL);
806         gtk_container_add(GTK_CONTAINER(hbox), button);
807         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
808         gtk_widget_show(button);
809
810         button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
811                                  G_CALLBACK(config_window_close_cb), NULL);
812         gtk_container_add(GTK_CONTAINER(hbox), button);
813         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
814         gtk_widget_show(button);
815
816         if (!generic_dialog_get_alternative_button_order(configwindow))
817                 {
818                 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
819                 }
820
821         notebook = gtk_notebook_new();
822         gtk_notebook_set_tab_pos (GTK_NOTEBOOK(notebook), GTK_POS_TOP);
823         gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
824
825         /* general options tab */
826
827         vbox = gtk_vbox_new(FALSE, 0);
828         gtk_container_set_border_width(GTK_CONTAINER(vbox), PREF_PAD_BORDER);
829         gtk_widget_show(vbox);
830         label = gtk_label_new(_("General"));
831         gtk_notebook_append_page (GTK_NOTEBOOK(notebook), vbox, label);
832
833         group = pref_group_new(vbox, FALSE, _("Startup"), GTK_ORIENTATION_VERTICAL);
834
835         button = pref_checkbox_new_int(group, _("Change to folder:"),
836                                        startup_path_enable, &startup_path_enable_c);
837
838         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
839         pref_checkbox_link_sensitivity(button, hbox);
840
841         tabcomp = tab_completion_new(&startup_path_entry, startup_path, NULL, NULL);
842         tab_completion_add_select_button(startup_path_entry, NULL, TRUE);
843         gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
844         gtk_widget_show(tabcomp);
845
846         button = pref_button_new(hbox, NULL, _("Use current"), FALSE,
847                                  G_CALLBACK(startup_path_set_current), NULL);
848
849         group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
850
851         table = pref_table_new(group, 2, 2, FALSE, FALSE);
852         add_thumb_size_menu(table, 0, 0, _("Size:"));
853         add_quality_menu(table, 0, 1, _("Quality:"), thumbnail_quality, &thumbnail_quality_c);
854
855         ct_button = pref_checkbox_new_int(group, _("Cache thumbnails"),
856                                           enable_thumb_caching, &enable_thumb_caching_c);
857
858         subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
859         pref_checkbox_link_sensitivity(ct_button, subgroup);
860
861         button = pref_checkbox_new_int(subgroup, _("Use shared thumbnail cache"),
862                                        thumbnail_spec_standard, &thumbnail_spec_standard_c);
863
864         subgroup = pref_box_new(subgroup, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
865         pref_checkbox_link_sensitivity_swap(button, subgroup);
866
867         pref_checkbox_new_int(subgroup, _("Cache thumbnails into .thumbnails"),
868                               enable_thumb_dirs, &enable_thumb_dirs_c);
869
870 #if 0
871         pref_checkbox_new_int(subgroup, _("Use xvpics thumbnails when found (read only)"),
872                               use_xvpics_thumbnails, &use_xvpics_thumbnails_c);
873 #endif
874
875         pref_checkbox_new_int(group, _("Faster jpeg thumbnailing (may reduce quality)"),
876                               thumbnail_fast, &thumbnail_fast_c);
877
878         group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
879
880         slideshow_delay_c = slideshow_delay;
881         spin = pref_spin_new(group, _("Delay between image change:"), _("seconds"),
882                              SLIDESHOW_MIN_SECONDS, SLIDESHOW_MAX_SECONDS, 1.0, 1,
883                              slideshow_delay ? (double)slideshow_delay / SLIDESHOW_SUBSECOND_PRECISION : 10.0,
884                              G_CALLBACK(slideshow_delay_cb), NULL);
885         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
886
887         pref_checkbox_new_int(group, _("Random"), slideshow_random, &slideshow_random_c);
888         pref_checkbox_new_int(group, _("Repeat"), slideshow_repeat, &slideshow_repeat_c);
889
890         /* image tab */
891
892         vbox = gtk_vbox_new(FALSE, 0);
893         gtk_container_set_border_width(GTK_CONTAINER(vbox), PREF_PAD_BORDER);
894         gtk_widget_show(vbox);
895         label = gtk_label_new(_("Image"));
896         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label);
897
898         group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
899
900 #if 0
901         add_dither_menu(dither_quality, &dither_quality_c, _("Dithering method:"), group);
902 #endif
903         table = pref_table_new(group, 2, 1, FALSE, FALSE);
904         add_quality_menu(table, 0, 0, _("Quality:"), zoom_quality, &zoom_quality_c);
905
906         pref_checkbox_new_int(group, _("Two pass zooming"),
907                               two_pass_zoom, &two_pass_zoom_c);
908
909         pref_checkbox_new_int(group, _("Allow enlargement of image for zoom to fit"),
910                               zoom_to_fit_expands, &zoom_to_fit_expands_c);
911
912         zoom_increment_c = zoom_increment;
913         spin = pref_spin_new(group, _("Zoom increment:"), NULL,
914                              0.1, 4.0, 1.0, 1, (double)zoom_increment / 10.0,
915                              G_CALLBACK(zoom_increment_cb), NULL);
916         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
917
918         group = pref_group_new(vbox, FALSE, _("When new image is selected:"), GTK_ORIENTATION_VERTICAL);
919
920         zoom_mode_c = zoom_mode;
921         button = pref_radiobutton_new(group, NULL, _("Zoom to original size"),
922                                       (zoom_mode == ZOOM_RESET_ORIGINAL),
923                                       G_CALLBACK(zoom_mode_original_cb), NULL);
924         button = pref_radiobutton_new(group, button, _("Fit image to window"),
925                                       (zoom_mode == ZOOM_RESET_FIT_WINDOW),
926                                       G_CALLBACK(zoom_mode_fit_cb), NULL);
927         button = pref_radiobutton_new(group, button, _("Leave Zoom at previous setting"),
928                                       (zoom_mode == ZOOM_RESET_NONE),
929                                       G_CALLBACK(zoom_mode_none_cb), NULL);
930
931         group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
932
933         pref_checkbox_new_int(group, _("Black background"),
934                               black_window_background, &black_window_background_c);
935
936         group = pref_group_new(vbox, FALSE, _("Convenience"), GTK_ORIENTATION_VERTICAL);
937
938         pref_checkbox_new_int(group, _("Refresh on file change"),
939                               update_on_time_change, &update_on_time_change_c);
940         pref_checkbox_new_int(group, _("Preload next image"),
941                               enable_read_ahead, &enable_read_ahead_c);
942         pref_checkbox_new_int(group, _("Auto rotate image using Exif information"),
943                               exif_rotate_enable, &exif_rotate_enable_c);
944
945
946         /* window tab */
947
948         vbox = gtk_vbox_new(FALSE, 0);
949         gtk_container_set_border_width(GTK_CONTAINER(vbox), PREF_PAD_BORDER);
950         gtk_widget_show(vbox);
951         label = gtk_label_new(_("Windows"));
952         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label);
953
954         group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
955
956         pref_checkbox_new_int(group, _("Remember window positions"),
957                               save_window_positions, &save_window_positions_c);
958         pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
959                               restore_tool, &restore_tool_c);
960
961         group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
962
963         pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
964                               fit_window, &fit_window_c);
965
966         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
967         ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
968                                           limit_window_size, &limit_window_size_c);
969         spin = pref_spin_new_int(hbox, NULL, NULL,
970                                  10, 150, 1,
971                                  max_window_size, &max_window_size_c);
972         pref_checkbox_link_sensitivity(ct_button, spin);
973
974         group = pref_group_new(vbox, FALSE, _("Layout"), GTK_ORIENTATION_VERTICAL);
975
976         layout_widget = layout_config_new();
977         layout_config_set(layout_widget, layout_style, layout_order);
978         gtk_box_pack_start(GTK_BOX(group), layout_widget, FALSE, FALSE, 0);
979         gtk_widget_show(layout_widget);
980
981
982         /* filtering tab */
983
984         vbox = gtk_vbox_new(FALSE, 0);
985         gtk_container_set_border_width(GTK_CONTAINER (vbox), PREF_PAD_BORDER);
986         gtk_widget_show(vbox);
987         label = gtk_label_new(_("Filtering"));
988         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label);
989
990         group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
991
992         pref_checkbox_new_int(group, _("Show entries that begin with a dot"),
993                               show_dot_files, &show_dot_files_c);
994         pref_checkbox_new_int(group, _("Case sensitive sort"),
995                               file_sort_case_sensitive, &file_sort_case_sensitive_c);
996
997         ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
998                                           file_filter_disable, &file_filter_disable_c);
999
1000         group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
1001
1002         frame = pref_group_parent(group);
1003         g_signal_connect(G_OBJECT(ct_button), "toggled",
1004                          G_CALLBACK(filter_disable_cb), frame);
1005         gtk_widget_set_sensitive(frame, !file_filter_disable);
1006
1007         scrolled = gtk_scrolled_window_new(NULL, NULL);
1008         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
1009         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1010         gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
1011         gtk_widget_show(scrolled);
1012
1013         filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
1014         filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
1015         g_object_unref(filter_store);
1016         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1017         gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
1018
1019         gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
1020
1021         column = gtk_tree_view_column_new();
1022         gtk_tree_view_column_set_title(column, _("Filter"));
1023         gtk_tree_view_column_set_resizable(column, TRUE);
1024
1025         renderer = gtk_cell_renderer_toggle_new();
1026         g_signal_connect(G_OBJECT(renderer), "toggled",
1027                          G_CALLBACK(filter_store_enable_cb), filter_store);
1028         gtk_tree_view_column_pack_start(column, renderer, FALSE);
1029         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
1030                                                 GINT_TO_POINTER(FE_ENABLE), NULL);
1031         
1032         renderer = gtk_cell_renderer_text_new();
1033         g_signal_connect(G_OBJECT(renderer), "edited",
1034                          G_CALLBACK(filter_store_ext_edit_cb), filter_store);
1035         gtk_tree_view_column_pack_start(column, renderer, TRUE);
1036         g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
1037         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
1038                                                 GINT_TO_POINTER(FE_EXTENSION), NULL);
1039         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
1040
1041         column = gtk_tree_view_column_new();
1042         gtk_tree_view_column_set_title(column, _("Description"));
1043         gtk_tree_view_column_set_resizable(column, TRUE);
1044         renderer = gtk_cell_renderer_text_new();
1045         g_signal_connect(G_OBJECT(renderer), "edited",
1046                          G_CALLBACK(filter_store_desc_edit_cb), filter_store);
1047         g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
1048         gtk_tree_view_column_pack_start(column, renderer, FALSE);
1049         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
1050                                                 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
1051         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
1052
1053         filter_store_populate();
1054         gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
1055         gtk_widget_show(filter_view);
1056
1057         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
1058
1059         button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
1060                                  G_CALLBACK(filter_default_cb), NULL);
1061         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1062         gtk_widget_show(button);
1063
1064         button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
1065                                  G_CALLBACK(filter_remove_cb), filter_view);
1066         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1067         gtk_widget_show(button);
1068
1069         button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
1070                                  G_CALLBACK(filter_add_cb), NULL);
1071         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1072         gtk_widget_show(button);
1073
1074
1075         /* editor entry tab */
1076
1077         vbox = gtk_vbox_new(FALSE, PREF_PAD_GAP);
1078         gtk_container_set_border_width(GTK_CONTAINER(vbox), PREF_PAD_BORDER);
1079         gtk_widget_show(vbox);
1080         label = gtk_label_new(_("Editors"));
1081         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label);
1082
1083         table = pref_table_new(vbox, 3, 9, FALSE, FALSE);
1084         gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
1085
1086         label = pref_table_label(table, 0, 0, _("#"), 1.0);
1087         pref_label_bold(label, TRUE, FALSE);
1088
1089         label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
1090         pref_label_bold(label, TRUE, FALSE);
1091
1092         label = pref_table_label(table, 2, 0, _("Command Line"), 0.0);
1093         pref_label_bold(label, TRUE, FALSE);
1094
1095         for (i = 0; i < GQVIEW_EDITOR_SLOTS; i++)
1096                 {
1097                 gchar *buf;
1098
1099                 buf = g_strdup_printf("%d", i+1);
1100                 pref_table_label(table, 0, i+1, buf, 1.0);
1101                 g_free(buf);
1102
1103                 editor_name_entry[i] = gtk_entry_new();
1104                 gtk_entry_set_max_length(GTK_ENTRY(editor_name_entry[i]), EDITOR_NAME_MAX_LENGTH);
1105                 gtk_widget_set_size_request(editor_name_entry[i],80,-1);
1106                 if (editor_name[i]) gtk_entry_set_text(GTK_ENTRY(editor_name_entry[i]),editor_name[i]);
1107                 gtk_table_attach(GTK_TABLE (table),editor_name_entry[i],1,2,i+1,i+2,
1108                                  GTK_FILL | GTK_EXPAND, FALSE, 0, 0);
1109                 gtk_widget_show(editor_name_entry[i]);
1110
1111                 editor_command_entry[i] = gtk_entry_new();
1112                 gtk_entry_set_max_length(GTK_ENTRY(editor_command_entry[i]), EDITOR_COMMAND_MAX_LENGTH);
1113                 gtk_widget_set_size_request(editor_command_entry[i],160,-1);
1114                 tab_completion_add_to_entry(editor_command_entry[i], NULL, NULL);
1115                 if (editor_command[i]) gtk_entry_set_text(GTK_ENTRY(editor_command_entry[i]), editor_command[i]);
1116                 gtk_table_attach(GTK_TABLE (table),editor_command_entry[i],2,3,i+1,i+2,
1117                                  GTK_FILL | GTK_EXPAND, FALSE, 0, 0);
1118                 gtk_widget_show(editor_command_entry[i]);
1119                 }
1120
1121         hbox = pref_box_new(vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
1122
1123         button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
1124                                  G_CALLBACK(editor_default_cb), NULL);
1125         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1126         gtk_widget_show(button);
1127
1128         button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
1129                                  G_CALLBACK(editor_help_cb), NULL);
1130         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1131         gtk_widget_show(button);
1132
1133         /* advanced entry tab */
1134
1135         scrolled = gtk_scrolled_window_new(NULL, NULL);
1136         gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1137         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1138                                        GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1139         label = gtk_label_new(_("Advanced"));
1140         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1141         gtk_widget_show(scrolled);
1142
1143         viewport = gtk_viewport_new(NULL, NULL);
1144         gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1145         gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1146         gtk_widget_show(viewport);
1147
1148         vbox = gtk_vbox_new(FALSE, 0);
1149         gtk_container_add(GTK_CONTAINER(viewport), vbox);
1150         gtk_widget_show(vbox);
1151
1152         group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
1153
1154         fullscreen_screen_c = fullscreen_screen;
1155         fullscreen_above_c = fullscreen_above;
1156         hbox = fullscreen_prefs_selection_new(_("Location:"), &fullscreen_screen_c, &fullscreen_above_c);
1157         gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
1158         gtk_widget_show(hbox);
1159
1160         pref_checkbox_new_int(group, _("Smooth image flip"),
1161                               fullscreen_clean_flip, &fullscreen_clean_flip_c);
1162         pref_checkbox_new_int(group, _("Disable screen saver"),
1163                               fullscreen_disable_saver, &fullscreen_disable_saver_c);
1164
1165         group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
1166
1167         pref_checkbox_new_int(group, _("Confirm file delete"),
1168                               confirm_delete, &confirm_delete_c);
1169         pref_checkbox_new_int(group, _("Enable Delete key"),
1170                               enable_delete_key, &enable_delete_key_c);
1171
1172         ct_button = pref_checkbox_new_int(group, _("Safe delete"),
1173                                           safe_delete_enable, &safe_delete_enable_c);
1174
1175         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1176         pref_checkbox_link_sensitivity(ct_button, hbox);
1177
1178         pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
1179         pref_label_new(hbox, _("Folder:"));
1180
1181         tabcomp = tab_completion_new(&safe_delete_path_entry, safe_delete_path, NULL, NULL);
1182         tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
1183         gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
1184         gtk_widget_show(tabcomp);
1185
1186         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
1187         pref_checkbox_link_sensitivity(ct_button, hbox);
1188
1189         pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
1190         pref_spin_new_int(hbox, _("Maximum size:"), _("MB"),
1191                           1, 500, 1, safe_delete_size, &safe_delete_size_c);
1192
1193         button = pref_button_new(NULL, NULL, _("View"), FALSE,
1194                                  G_CALLBACK(safe_delete_view_cb), NULL);
1195         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1196         gtk_widget_show(button);
1197
1198         button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
1199                                  G_CALLBACK(safe_delete_clear_cb), NULL);
1200         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1201         gtk_widget_show(button);
1202
1203         group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
1204
1205         pref_checkbox_new_int(group, _("Rectangular selection in icon view"),
1206                               collection_rectangular_selection, &collection_rectangular_selection_c);
1207
1208         pref_checkbox_new_int(group, _("Descend folders in tree view"),
1209                               tree_descend_subdirs, &tree_descend_subdirs_c);
1210
1211         pref_checkbox_new_int(group, _("In place renaming"),
1212                               enable_in_place_rename, &enable_in_place_rename_c);
1213
1214         group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
1215
1216         pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
1217                               progressive_key_scrolling, &progressive_key_scrolling_c);
1218         pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
1219                               mousewheel_scrolls, &mousewheel_scrolls_c);
1220
1221         group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
1222
1223         pref_checkbox_new_int(group, _("Store keywords and comments local to source images"),
1224                               enable_metadata_dirs, &enable_metadata_dirs_c);
1225
1226         pref_spin_new_int(group, _("Custom similarity threshold:"), NULL,
1227                           0, 100, 1, dupe_custom_threshold, &dupe_custom_threshold_c);
1228
1229         pref_spin_new_int(group, _("Offscreen cache size (Mb per image):"), NULL,
1230                           0, 128, 1, tile_cache_max, &tile_cache_max_c);
1231
1232         gtk_widget_show(notebook);
1233
1234         gtk_widget_show(configwindow);
1235 }
1236
1237 /*
1238  *-----------------------------------------------------------------------------
1239  * config window show (public)
1240  *-----------------------------------------------------------------------------
1241  */ 
1242
1243 void show_config_window(void)
1244 {
1245         if (configwindow)
1246                 {
1247                 gtk_window_present(GTK_WINDOW(configwindow));
1248                 return;
1249                 }
1250
1251         config_window_create();
1252 }
1253
1254 /*
1255  *-----------------
1256  * about window
1257  *-----------------
1258  */
1259
1260 static GtkWidget *about = NULL;
1261
1262 static gint about_delete_cb(GtkWidget *widget, GdkEventAny *event, gpointer data)
1263 {
1264         gtk_widget_destroy(about);
1265         about = NULL;
1266
1267         return TRUE;
1268 }
1269
1270 static void about_window_close(GtkWidget *widget, gpointer data)
1271 {
1272         if (!about) return;
1273
1274         gtk_widget_destroy(about);
1275         about = NULL;
1276 }
1277
1278 static void about_credits_cb(GtkWidget *widget, gpointer data)
1279 {
1280         help_window_show("credits");
1281 }
1282
1283 void show_about_window(void)
1284 {
1285         GtkWidget *vbox;
1286         GtkWidget *hbox;
1287         GtkWidget *label;
1288         GtkWidget *button;
1289         GdkPixbuf *pixbuf;
1290
1291         gchar *buf;
1292
1293         if (about)
1294                 {
1295                 gtk_window_present(GTK_WINDOW(about));
1296                 return;
1297                 }
1298
1299         about = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1300         gtk_window_set_type_hint(GTK_WINDOW(about), GDK_WINDOW_TYPE_HINT_DIALOG);
1301         gtk_window_set_wmclass(GTK_WINDOW(about), "about", "GQview");
1302         g_signal_connect(G_OBJECT(about), "delete_event",
1303                          G_CALLBACK(about_delete_cb), NULL);
1304
1305         gtk_window_set_title(GTK_WINDOW(about), _("About - GQview"));
1306         gtk_container_set_border_width(GTK_CONTAINER(about), PREF_PAD_BORDER);
1307
1308         vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
1309         gtk_container_add(GTK_CONTAINER(about), vbox);
1310         gtk_widget_show(vbox);
1311
1312         pixbuf = pixbuf_inline(PIXBUF_INLINE_LOGO);
1313         button = gtk_image_new_from_pixbuf(pixbuf);
1314         g_object_unref(pixbuf);
1315         gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 0);
1316         gtk_widget_show(button);
1317
1318         buf = g_strdup_printf(_("GQview %s\n\nCopyright (c) %s John Ellis\nwebsite: %s\nemail: %s\n\nReleased under the GNU General Public License"),
1319                               VERSION,
1320                               "2006",
1321                               "gqview.sourceforge.net",
1322                               "gqview@users.sourceforge.net");
1323         label = gtk_label_new(buf);
1324         g_free(buf);
1325
1326         gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
1327         gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
1328         gtk_widget_show(label);
1329
1330         hbox = gtk_hbutton_box_new();
1331         gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
1332         gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
1333         gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1334         gtk_widget_show(hbox);
1335
1336         button = pref_button_new(NULL, NULL, _("Credits..."), FALSE,
1337                                  G_CALLBACK(about_credits_cb), NULL);
1338         gtk_container_add(GTK_CONTAINER(hbox), button);
1339         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1340         gtk_widget_show(button);
1341
1342         button = pref_button_new(NULL, GTK_STOCK_CLOSE, NULL, FALSE,
1343                                  G_CALLBACK(about_window_close), NULL);
1344         gtk_container_add(GTK_CONTAINER(hbox), button);
1345         GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1346         gtk_widget_grab_default(button);
1347         gtk_widget_show(button);
1348
1349         window_set_icon(about, NULL, NULL);
1350         gtk_widget_show(about);
1351 }
1352