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