Show .icc files when selecting color profiles
[geeqie.git] / src / preferences.c
1 /*
2  * Copyright (C) 2006 John Ellis
3  * Copyright (C) 2008 - 2016 The Geeqie Team
4  *
5  * Author: John Ellis
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "main.h"
23 #include "preferences.h"
24
25 #include "bar_exif.h"
26 #include "cache.h"
27 #include "cache_maint.h"
28 #include "editors.h"
29 #include "exif.h"
30 #include "filedata.h"
31 #include "filefilter.h"
32 #include "fullscreen.h"
33 #include "image.h"
34 #include "image-overlay.h"
35 #include "color-man.h"
36 #include "img-view.h"
37 #include "layout_config.h"
38 #include "layout_util.h"
39 #include "pixbuf_util.h"
40 #include "slideshow.h"
41 #include "toolbar.h"
42 #include "trash.h"
43 #include "utilops.h"
44 #include "ui_fileops.h"
45 #include "ui_misc.h"
46 #include "ui_tabcomp.h"
47 #include "ui_utildlg.h"
48 #include "window.h"
49
50 #include <math.h>
51
52 #ifdef HAVE_LCMS
53 #ifdef HAVE_LCMS2
54 #include <lcms2.h>
55 #else
56 #include <lcms.h>
57 #endif
58 #endif
59
60 #define EDITOR_NAME_MAX_LENGTH 32
61 #define EDITOR_COMMAND_MAX_LENGTH 1024
62
63 static void image_overlay_set_text_colours();
64
65 typedef struct _ThumbSize ThumbSize;
66 struct _ThumbSize
67 {
68         gint w;
69         gint h;
70 };
71
72 static ThumbSize thumb_size_list[] =
73 {
74         { 24, 24 },
75         { 32, 32 },
76         { 48, 48 },
77         { 64, 64 },
78         { 96, 72 },
79         { 96, 96 },
80         { 128, 96 },
81         { 128, 128 },
82         { 160, 120 },
83         { 160, 160 },
84         { 192, 144 },
85         { 192, 192 },
86         { 256, 192 },
87         { 256, 256 }
88 };
89
90 enum {
91         FE_ENABLE,
92         FE_EXTENSION,
93         FE_DESCRIPTION,
94         FE_CLASS,
95         FE_WRITABLE,
96         FE_ALLOW_SIDECAR
97 };
98
99 enum {
100         AE_ACTION,
101         AE_KEY,
102         AE_TOOLTIP,
103         AE_ACCEL
104 };
105
106 static gchar *format_class_list[] = {
107         N_("Unknown"),
108         N_("Image"),
109         N_("RAW Image"),
110         N_("Metadata"),
111         N_("Video")
112         };
113
114 /* config memory values */
115 static ConfOptions *c_options = NULL;
116
117
118 #ifdef DEBUG
119 static gint debug_c;
120 #endif
121
122 static GtkWidget *configwindow = NULL;
123 static GtkListStore *filter_store = NULL;
124 static GtkTreeStore *accel_store = NULL;
125
126 static GtkWidget *safe_delete_path_entry;
127
128 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
129 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
130 static GtkWidget *color_profile_screen_file_entry;
131
132 static GtkWidget *sidecar_ext_entry;
133
134
135 #define CONFIG_WINDOW_DEF_WIDTH         700
136 #define CONFIG_WINDOW_DEF_HEIGHT        600
137
138 /*
139  *-----------------------------------------------------------------------------
140  * option widget callbacks (private)
141  *-----------------------------------------------------------------------------
142  */
143
144 static void zoom_increment_cb(GtkWidget *spin, gpointer data)
145 {
146         c_options->image.zoom_increment = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
147 }
148
149 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer data)
150 {
151         gint mins_secs_tenths, delay;
152
153         mins_secs_tenths = c_options->slideshow.delay %
154                                                 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
155
156         delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
157                                                                 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
158                                                                 mins_secs_tenths);
159
160         c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
161                                                                                                         SLIDESHOW_SUBSECOND_PRECISION;
162 }
163
164 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer data)
165 {
166         gint hours, secs_tenths, delay;
167
168         hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
169         secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
170
171         delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
172                                         (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
173                                         (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
174
175         c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
176                                                                                                         SLIDESHOW_SUBSECOND_PRECISION;
177 }
178
179 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer data)
180 {
181         gint hours_mins, delay;
182
183         hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
184
185         delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
186                                                         (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
187                                                         (gdouble)(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
188
189         c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
190                                                                                                         SLIDESHOW_SUBSECOND_PRECISION;
191 }
192
193 /*
194  *-----------------------------------------------------------------------------
195  * sync progam to config window routine (private)
196  *-----------------------------------------------------------------------------
197  */
198
199 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
200 {
201         const gchar *buf;
202
203         g_free(*option);
204         *option = NULL;
205         buf = gtk_entry_get_text(GTK_ENTRY(entry));
206         if (buf && strlen(buf) > 0)
207                 {
208                 if (func)
209                         *option = func(buf);
210                 else
211                         *option = g_strdup(buf);
212                 }
213 }
214
215
216 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
217 {
218         gchar *accel_path, *accel;
219
220         gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
221
222         if (accel_path && accel_path[0])
223                 {
224                 GtkAccelKey key;
225                 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
226                 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
227                 }
228
229         g_free(accel_path);
230         g_free(accel);
231
232         return FALSE;
233 }
234
235
236 static void config_window_apply(void)
237 {
238         gint i;
239         gboolean refresh = FALSE;
240
241         config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
242
243         if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
244         if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
245         if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
246         if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
247         if (options->file_sort.natural != c_options->file_sort.natural) refresh = TRUE;
248         if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
249         if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
250
251         options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
252         options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
253         options->file_ops.safe_delete_enable = c_options->file_ops.safe_delete_enable;
254         options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
255         options->tools_restore_state = c_options->tools_restore_state;
256         options->save_window_positions = c_options->save_window_positions;
257         options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
258         options->save_dialog_window_positions = c_options->save_dialog_window_positions;
259         options->image.scroll_reset_method = c_options->image.scroll_reset_method;
260         options->image.zoom_2pass = c_options->image.zoom_2pass;
261         options->image.fit_window_to_image = c_options->image.fit_window_to_image;
262         options->image.limit_window_size = c_options->image.limit_window_size;
263         options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
264         options->image.max_window_size = c_options->image.max_window_size;
265         options->image.limit_autofit_size = c_options->image.limit_autofit_size;
266         options->image.max_autofit_size = c_options->image.max_autofit_size;
267         options->image.max_enlargement_size = c_options->image.max_enlargement_size;
268         options->image.use_clutter_renderer = c_options->image.use_clutter_renderer;
269         options->progressive_key_scrolling = c_options->progressive_key_scrolling;
270         options->keyboard_scroll_step = c_options->keyboard_scroll_step;
271
272         if (options->thumbnails.max_width != c_options->thumbnails.max_width
273             || options->thumbnails.max_height != c_options->thumbnails.max_height
274             || options->thumbnails.quality != c_options->thumbnails.quality)
275                 {
276                 thumb_format_changed = TRUE;
277                 refresh = TRUE;
278                 options->thumbnails.max_width = c_options->thumbnails.max_width;
279                 options->thumbnails.max_height = c_options->thumbnails.max_height;
280                 options->thumbnails.quality = c_options->thumbnails.quality;
281                 }
282         options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
283         options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
284         options->thumbnails.use_exif = c_options->thumbnails.use_exif;
285         options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
286 //      options->thumbnails.use_ft_metadata_small = c_options->thumbnails.use_ft_metadata_small;
287         options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
288         options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
289         options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
290         options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
291         options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
292         options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
293
294         options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
295         options->file_sort.natural = c_options->file_sort.natural;
296         options->file_filter.disable = c_options->file_filter.disable;
297
298         config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, NULL);
299         sidecar_ext_parse(options->sidecar.ext);
300
301         options->slideshow.random = c_options->slideshow.random;
302         options->slideshow.repeat = c_options->slideshow.repeat;
303         options->slideshow.delay = c_options->slideshow.delay;
304
305         options->mousewheel_scrolls = c_options->mousewheel_scrolls;
306         options->image_lm_click_nav = c_options->image_lm_click_nav;
307         options->image_l_click_video = c_options->image_l_click_video;
308         options->image_l_click_video_editor = c_options->image_l_click_video_editor;
309
310         options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
311
312         options->image.tile_cache_max = c_options->image.tile_cache_max;
313         options->image.image_cache_max = c_options->image.image_cache_max;
314
315         options->image.zoom_quality = c_options->image.zoom_quality;
316
317         options->image.zoom_increment = c_options->image.zoom_increment;
318
319         options->image.enable_read_ahead = c_options->image.enable_read_ahead;
320
321
322         if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
323             || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
324             || !gdk_color_equal(&options->image.border_color, &c_options->image.border_color))
325                 {
326                 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
327                 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
328                 options->image.border_color = c_options->image.border_color;
329                 layout_colors_update();
330                 view_window_colors_update();
331                 }
332
333         options->image.alpha_color_1 = c_options->image.alpha_color_1;
334         options->image.alpha_color_2 = c_options->image.alpha_color_2;
335
336         options->fullscreen.screen = c_options->fullscreen.screen;
337         options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
338         options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
339         options->fullscreen.above = c_options->fullscreen.above;
340         if (c_options->image_overlay.template_string)
341                 set_image_overlay_template_string(&options->image_overlay.template_string,
342                                                   c_options->image_overlay.template_string);
343         if (c_options->image_overlay.font)
344                 set_image_overlay_font_string(&options->image_overlay.font,
345                                                   c_options->image_overlay.font);
346         options->image_overlay.text_red = c_options->image_overlay.text_red;
347         options->image_overlay.text_green = c_options->image_overlay.text_green;
348         options->image_overlay.text_blue = c_options->image_overlay.text_blue;
349         options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
350         options->image_overlay.background_red = c_options->image_overlay.background_red;
351         options->image_overlay.background_green = c_options->image_overlay.background_green;
352         options->image_overlay.background_blue = c_options->image_overlay.background_blue;
353         options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
354         options->update_on_time_change = c_options->update_on_time_change;
355         options->image.exif_proof_rotate_enable = c_options->image.exif_proof_rotate_enable;
356
357         options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
358         options->rot_invariant_sim = c_options->rot_invariant_sim;
359
360         options->tree_descend_subdirs = c_options->tree_descend_subdirs;
361
362         options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
363
364         options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
365         options->dnd_icon_size = c_options->dnd_icon_size;
366         options->clipboard_selection = c_options->clipboard_selection;
367
368         options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
369         options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
370         options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
371         options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
372         options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
373         options->metadata.confirm_write = c_options->metadata.confirm_write;
374         options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
375         options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
376         options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
377         options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
378         options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
379         options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
380         options->metadata.write_orientation = c_options->metadata.write_orientation;
381         options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
382                                (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
383                                (c_options->stereo.tmp.flip_right   ? PR_STEREO_FLIP_RIGHT : 0) |
384                                (c_options->stereo.tmp.mirror_left  ? PR_STEREO_MIRROR_LEFT : 0) |
385                                (c_options->stereo.tmp.flip_left    ? PR_STEREO_FLIP_LEFT : 0) |
386                                (c_options->stereo.tmp.swap         ? PR_STEREO_SWAP : 0) |
387                                (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
388         options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
389                                (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
390                                (c_options->stereo.tmp.fs_flip_right   ? PR_STEREO_FLIP_RIGHT : 0) |
391                                (c_options->stereo.tmp.fs_mirror_left  ? PR_STEREO_MIRROR_LEFT : 0) |
392                                (c_options->stereo.tmp.fs_flip_left    ? PR_STEREO_FLIP_LEFT : 0) |
393                                (c_options->stereo.tmp.fs_swap         ? PR_STEREO_SWAP : 0) |
394                                (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
395         options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
396         options->stereo.fixed_w = c_options->stereo.fixed_w;
397         options->stereo.fixed_h = c_options->stereo.fixed_h;
398         options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
399         options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
400         options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
401         options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
402
403         options->info_keywords.height = c_options->info_keywords.height;
404         options->info_title.height = c_options->info_title.height;
405         options->info_comment.height = c_options->info_comment.height;
406         options->info_rating.height = c_options->info_rating.height;
407
408 #ifdef DEBUG
409         set_debug_level(debug_c);
410 #endif
411
412 #ifdef HAVE_LCMS
413         for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
414                 {
415                 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
416                 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
417                 }
418         config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
419         options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
420         if (options->color_profile.render_intent != c_options->color_profile.render_intent)
421                 {
422                 options->color_profile.render_intent = c_options->color_profile.render_intent;
423                 color_man_update();
424                 }
425 #endif
426
427         image_options_sync();
428
429         if (refresh)
430                 {
431                 filter_rebuild();
432                 layout_refresh(NULL);
433                 }
434
435         if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, NULL);
436
437         toolbar_apply();
438 }
439
440 /*
441  *-----------------------------------------------------------------------------
442  * config window main button callbacks (private)
443  *-----------------------------------------------------------------------------
444  */
445
446 static void config_window_close_cb(GtkWidget *widget, gpointer data)
447 {
448         gtk_widget_destroy(configwindow);
449         configwindow = NULL;
450         filter_store = NULL;
451 }
452
453 static void config_window_help_cb(GtkWidget *widget, gpointer data)
454 {
455         GtkWidget *notebook = data;
456         gint i;
457
458         static gchar *html_section[] =
459         {
460         "GuideOptionsGeneral.html",
461         "GuideOptionsImage.html",
462         "GuideOptionsWindow.html",
463         "GuideOptionsKeyboard.html",
464         "GuideOptionsFiltering.html",
465         "GuideOptionsMetadata.html",
466         "GuideOptionsColor.html",
467         "GuideOptionsStereo.html",
468         "GuideOptionsBehavior.html",
469         "GuideOptionsToolbar.html"
470         };
471
472         i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
473         help_window_show(html_section[i]);
474 }
475
476 static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpointer data)
477 {
478         config_window_close_cb(NULL, NULL);
479         return TRUE;
480 }
481
482 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
483 {
484         config_window_apply();
485         config_window_close_cb(NULL, NULL);
486 }
487
488 static void config_window_apply_cb(GtkWidget *widget, gpointer data)
489 {
490         LayoutWindow *lw;
491         lw = layout_window_list->data;
492
493         config_window_apply();
494         layout_util_sync(lw);
495 }
496
497 static void config_window_save_cb(GtkWidget *widget, gpointer data)
498 {
499         config_window_apply();
500         save_options(options);
501 }
502
503 /*
504  *-----------------------------------------------------------------------------
505  * config window setup (private)
506  *-----------------------------------------------------------------------------
507  */
508
509 static void quality_menu_cb(GtkWidget *combo, gpointer data)
510 {
511         gint *option = data;
512
513         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
514                 {
515                 case 0:
516                 default:
517                         *option = GDK_INTERP_NEAREST;
518                         break;
519                 case 1:
520                         *option = GDK_INTERP_TILES;
521                         break;
522                 case 2:
523                         *option = GDK_INTERP_BILINEAR;
524                         break;
525                 case 3:
526                         *option = GDK_INTERP_HYPER;
527                         break;
528                 }
529 }
530
531 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
532 {
533         gint *option = data;
534
535         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
536                 {
537                 case 0:
538                 default:
539                         *option = PRIMARY;
540                         break;
541                 case 1:
542                         *option = CLIPBOARD;
543                         break;
544                 }
545 }
546
547 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
548                              guint option, guint *option_c)
549 {
550         GtkWidget *combo;
551         gint current = 0;
552
553         *option_c = option;
554
555         pref_table_label(table, column, row, text, 0.0);
556
557         combo = gtk_combo_box_text_new();
558
559         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
560         if (option == GDK_INTERP_NEAREST) current = 0;
561         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
562         if (option == GDK_INTERP_TILES) current = 1;
563         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear"));
564         if (option == GDK_INTERP_BILINEAR) current = 2;
565         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Hyper (best, but slowest)"));
566         if (option == GDK_INTERP_HYPER) current = 3;
567
568         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
569
570         g_signal_connect(G_OBJECT(combo), "changed",
571                          G_CALLBACK(quality_menu_cb), option_c);
572
573         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
574                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
575         gtk_widget_show(combo);
576 }
577
578 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
579                              gint option, gint *option_c)
580 {
581         GtkWidget *combo;
582         gint current = 0;
583
584         *option_c = option;
585
586         pref_table_label(table, column, row, text, 0.0);
587
588         combo = gtk_combo_box_text_new();
589
590         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("PRIMARY"));
591         if (option == PRIMARY) current = 0;
592         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("CLIPBOARD"));
593         if (option == CLIPBOARD) current = 1;
594
595         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
596
597         g_signal_connect(G_OBJECT(combo), "changed",
598                          G_CALLBACK(clipboard_selection_menu_cb), option_c);
599
600         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
601                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
602         gtk_widget_show(combo);
603 }
604
605 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
606 {
607         gint n;
608
609         n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
610         if (n < 0) return;
611
612         if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
613                 {
614                 c_options->thumbnails.max_width = thumb_size_list[n].w;
615                 c_options->thumbnails.max_height = thumb_size_list[n].h;
616                 }
617         else
618                 {
619                 c_options->thumbnails.max_width = options->thumbnails.max_width;
620                 c_options->thumbnails.max_height = options->thumbnails.max_height;
621                 }
622 }
623
624 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
625 {
626         GtkWidget *combo;
627         gint current;
628         gint i;
629
630         c_options->thumbnails.max_width = options->thumbnails.max_width;
631         c_options->thumbnails.max_height = options->thumbnails.max_height;
632
633         pref_table_label(table, column, row, text, 0.0);
634
635         combo = gtk_combo_box_text_new();
636
637         current = -1;
638         for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
639                 {
640                 gint w, h;
641                 gchar *buf;
642
643                 w = thumb_size_list[i].w;
644                 h = thumb_size_list[i].h;
645
646                 buf = g_strdup_printf("%d x %d", w, h);
647                 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
648                 g_free(buf);
649
650                 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
651                 }
652
653         if (current == -1)
654                 {
655                 gchar *buf;
656
657                 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
658                 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
659                 g_free(buf);
660
661                 current = i;
662                 }
663
664         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
665         g_signal_connect(G_OBJECT(combo), "changed",
666                          G_CALLBACK(thumb_size_menu_cb), NULL);
667
668         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
669                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
670         gtk_widget_show(combo);
671 }
672
673 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
674 {
675         gint *option = data;
676
677         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
678                 {
679                 case 0:
680                 default:
681                         *option = PR_STEREO_NONE;
682                         break;
683                 case 1:
684                         *option = PR_STEREO_ANAGLYPH_RC;
685                         break;
686                 case 2:
687                         *option = PR_STEREO_ANAGLYPH_GM;
688                         break;
689                 case 3:
690                         *option = PR_STEREO_ANAGLYPH_YB;
691                         break;
692                 case 4:
693                         *option = PR_STEREO_ANAGLYPH_GRAY_RC;
694                         break;
695                 case 5:
696                         *option = PR_STEREO_ANAGLYPH_GRAY_GM;
697                         break;
698                 case 6:
699                         *option = PR_STEREO_ANAGLYPH_GRAY_YB;
700                         break;
701                 case 7:
702                         *option = PR_STEREO_ANAGLYPH_DB_RC;
703                         break;
704                 case 8:
705                         *option = PR_STEREO_ANAGLYPH_DB_GM;
706                         break;
707                 case 9:
708                         *option = PR_STEREO_ANAGLYPH_DB_YB;
709                         break;
710                 case 10:
711                         *option = PR_STEREO_HORIZ;
712                         break;
713                 case 11:
714                         *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
715                         break;
716                 case 12:
717                         *option = PR_STEREO_VERT;
718                         break;
719                 case 13:
720                         *option = PR_STEREO_VERT | PR_STEREO_HALF;
721                         break;
722                 case 14:
723                         *option = PR_STEREO_FIXED;
724                         break;
725                 }
726 }
727
728 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
729                              gint option, gint *option_c, gboolean add_fixed)
730 {
731         GtkWidget *combo;
732         gint current = 0;
733
734         *option_c = option;
735
736         pref_table_label(table, column, row, text, 0.0);
737
738         combo = gtk_combo_box_text_new();
739
740         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
741
742         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
743         if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
744         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
745         if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
746         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
747         if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
748         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
749         if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
750         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
751         if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
752         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
753         if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
754         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
755         if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
756         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
757         if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
758         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
759         if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
760
761         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
762         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
763         if (option & PR_STEREO_HORIZ)
764                 {
765                 current = 10;
766                 if (option & PR_STEREO_HALF) current = 11;
767                 }
768
769         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
770         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
771         if (option & PR_STEREO_VERT)
772                 {
773                 current = 12;
774                 if (option & PR_STEREO_HALF) current = 13;
775                 }
776
777         if (add_fixed)
778                 {
779                 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
780                 if (option & PR_STEREO_FIXED) current = 14;
781                 }
782
783         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
784
785         g_signal_connect(G_OBJECT(combo), "changed",
786                          G_CALLBACK(stereo_mode_menu_cb), option_c);
787
788         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
789                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
790         gtk_widget_show(combo);
791 }
792
793 static void video_menu_cb(GtkWidget *combo, gpointer data)
794 {
795         gchar **option = data;
796
797         EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
798         *option = ed->key;
799 }
800
801 static void video_menu_populate(gpointer data, gpointer user_data)
802 {
803         GtkWidget *combo = user_data;
804         EditorDescription *ed = data;
805
806         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
807 }
808
809 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
810                              gchar *option, gchar **option_c)
811 {
812         GtkWidget *combo;
813         gint current;
814 /* use lists since they are sorted */
815         GList *eds = editor_list_get();
816
817         *option_c = option;
818
819         pref_table_label(table, column, row, text, 0.0);
820
821         combo = gtk_combo_box_text_new();
822         g_list_foreach(eds,video_menu_populate,(gpointer)combo);
823         current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
824
825         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
826
827         g_signal_connect(G_OBJECT(combo), "changed",
828                          G_CALLBACK(video_menu_cb), option_c);
829
830         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
831                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
832         gtk_widget_show(combo);
833 }
834
835 static void filter_store_populate(void)
836 {
837         GList *work;
838
839         if (!filter_store) return;
840
841         gtk_list_store_clear(filter_store);
842
843         work = filter_get_list();
844         while (work)
845                 {
846                 FilterEntry *fe;
847                 GtkTreeIter iter;
848
849                 fe = work->data;
850                 work = work->next;
851
852                 gtk_list_store_append(filter_store, &iter);
853                 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
854                 }
855 }
856
857 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
858                                      gchar *new_text, gpointer data)
859 {
860         GtkWidget *model = data;
861         FilterEntry *fe = data;
862         GtkTreePath *tpath;
863         GtkTreeIter iter;
864
865         if (!new_text || strlen(new_text) < 1) return;
866
867         tpath = gtk_tree_path_new_from_string(path_str);
868         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
869         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
870
871         g_free(fe->extensions);
872         fe->extensions = g_strdup(new_text);
873
874         gtk_tree_path_free(tpath);
875         filter_rebuild();
876 }
877
878 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
879                                        gchar *new_text, gpointer data)
880 {
881         GtkWidget *model = data;
882         FilterEntry *fe = data;
883         GtkTreePath *tpath;
884         GtkTreeIter iter;
885         gint i;
886
887         if (!new_text || !new_text[0]) return;
888
889         tpath = gtk_tree_path_new_from_string(path_str);
890         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
891         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
892
893         for (i = 0; i < FILE_FORMAT_CLASSES; i++)
894                 {
895                 if (strcmp(new_text, _(format_class_list[i])) == 0)
896                         {
897                         fe->file_class = i;
898                         break;
899                         }
900                 }
901
902         gtk_tree_path_free(tpath);
903         filter_rebuild();
904 }
905
906 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
907                                       gchar *new_text, gpointer data)
908 {
909         GtkWidget *model = data;
910         FilterEntry *fe;
911         GtkTreePath *tpath;
912         GtkTreeIter iter;
913
914         if (!new_text || !new_text[0]) return;
915
916         tpath = gtk_tree_path_new_from_string(path_str);
917         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
918         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
919
920         g_free(fe->description);
921         fe->description = g_strdup(new_text);
922
923         gtk_tree_path_free(tpath);
924 }
925
926 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
927                                    gchar *path_str, gpointer data)
928 {
929         GtkWidget *model = data;
930         FilterEntry *fe;
931         GtkTreePath *tpath;
932         GtkTreeIter iter;
933
934         tpath = gtk_tree_path_new_from_string(path_str);
935         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
936         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
937
938         fe->enabled = !fe->enabled;
939
940         gtk_tree_path_free(tpath);
941         filter_rebuild();
942 }
943
944 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
945                                      gchar *path_str, gpointer data)
946 {
947         GtkWidget *model = data;
948         FilterEntry *fe;
949         GtkTreePath *tpath;
950         GtkTreeIter iter;
951
952         tpath = gtk_tree_path_new_from_string(path_str);
953         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
954         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
955
956         fe->writable = !fe->writable;
957         if (fe->writable) fe->allow_sidecar = FALSE;
958
959         gtk_tree_path_free(tpath);
960         filter_rebuild();
961 }
962
963 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
964                                     gchar *path_str, gpointer data)
965 {
966         GtkWidget *model = data;
967         FilterEntry *fe;
968         GtkTreePath *tpath;
969         GtkTreeIter iter;
970
971         tpath = gtk_tree_path_new_from_string(path_str);
972         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
973         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
974
975         fe->allow_sidecar = !fe->allow_sidecar;
976         if (fe->allow_sidecar) fe->writable = FALSE;
977
978         gtk_tree_path_free(tpath);
979         filter_rebuild();
980 }
981
982 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
983                             GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
984 {
985         FilterEntry *fe;
986
987         gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
988
989         switch (GPOINTER_TO_INT(data))
990                 {
991                 case FE_ENABLE:
992                         g_object_set(GTK_CELL_RENDERER(cell),
993                                      "active", fe->enabled, NULL);
994                         break;
995                 case FE_EXTENSION:
996                         g_object_set(GTK_CELL_RENDERER(cell),
997                                      "text", fe->extensions, NULL);
998                         break;
999                 case FE_DESCRIPTION:
1000                         g_object_set(GTK_CELL_RENDERER(cell),
1001                                      "text", fe->description, NULL);
1002                         break;
1003                 case FE_CLASS:
1004                         g_object_set(GTK_CELL_RENDERER(cell),
1005                                      "text", _(format_class_list[fe->file_class]), NULL);
1006                         break;
1007                 case FE_WRITABLE:
1008                         g_object_set(GTK_CELL_RENDERER(cell),
1009                                      "active", fe->writable, NULL);
1010                         break;
1011                 case FE_ALLOW_SIDECAR:
1012                         g_object_set(GTK_CELL_RENDERER(cell),
1013                                      "active", fe->allow_sidecar, NULL);
1014                         break;
1015                 }
1016 }
1017
1018 static gboolean filter_add_scroll(gpointer data)
1019 {
1020         GtkTreePath *path;
1021         GList *list_cells;
1022         GtkCellRenderer *cell;
1023         GtkTreeViewColumn *column;
1024         GList *list_columns;
1025         const gchar *title;
1026         guint i = 0;
1027         gint rows;
1028
1029         rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1030         path = gtk_tree_path_new_from_indices(rows-1, -1);
1031
1032         list_columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(data));
1033         do {
1034                 column = g_list_nth(list_columns,i)->data;
1035                 title = gtk_tree_view_column_get_title(GTK_TREE_VIEW_COLUMN(column));
1036                 i++;
1037                 } while (strcmp(title, "Filter") !=0 );
1038
1039         list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1040         cell = g_list_last(list_cells)->data;
1041
1042         gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1043                                                                 path, column, FALSE, 0.0, 0.0 );
1044         gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1045                                                                 path, column, cell, TRUE);
1046
1047         gtk_tree_path_free(path);
1048         g_list_free(list_cells);
1049         g_list_free(list_columns);
1050
1051         return(FALSE);
1052 }
1053
1054 static void filter_add_cb(GtkWidget *widget, gpointer data)
1055 {
1056         filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1057         filter_store_populate();
1058
1059         g_idle_add((GSourceFunc)filter_add_scroll, data);
1060 }
1061
1062 static void filter_remove_cb(GtkWidget *widget, gpointer data)
1063 {
1064         GtkWidget *filter_view = data;
1065         GtkTreeSelection *selection;
1066         GtkTreeIter iter;
1067         FilterEntry *fe;
1068
1069         if (!filter_store) return;
1070         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1071         if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1072         gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1073         if (!fe) return;
1074
1075         filter_remove_entry(fe);
1076         filter_rebuild();
1077         filter_store_populate();
1078 }
1079
1080 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1081 {
1082         GtkTreeIter iter;
1083         GtkTreePath *path;
1084         GtkTreeViewColumn *column;
1085
1086         gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1087         path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1088         column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1089
1090         gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1091                                      path, column,
1092                                      FALSE, 0.0, 0.0);
1093
1094         gtk_tree_path_free(path);
1095
1096         return(FALSE);
1097 }
1098
1099 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
1100 {
1101         filter_reset();
1102         filter_add_defaults();
1103         filter_rebuild();
1104         filter_store_populate();
1105
1106         g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1107 }
1108
1109 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1110 {
1111         /* no op, only so cancel button appears */
1112 }
1113
1114 static void filter_default_cb(GtkWidget *widget, gpointer data)
1115 {
1116         GenericDialog *gd;
1117
1118         gd = generic_dialog_new(_("Reset filters"),
1119                                 "reset_filter", widget, TRUE,
1120                                 dummy_cancel_cb, data);
1121         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1122                                    _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1123         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1124         gtk_widget_show(gd->dialog);
1125 }
1126
1127 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1128 {
1129         GtkWidget *frame = data;
1130
1131         gtk_widget_set_sensitive(frame,
1132                                  !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1133 }
1134
1135 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
1136 {
1137         layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1138 }
1139
1140 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
1141 {
1142         file_util_trash_clear();
1143 }
1144
1145 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
1146 {
1147         GenericDialog *gd;
1148         GtkWidget *entry;
1149         gd = generic_dialog_new(_("Clear trash"),
1150                                 "clear_trash", widget, TRUE,
1151                                 dummy_cancel_cb, NULL);
1152         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1153                                     _("This will remove the trash contents."), FALSE);
1154         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1155         entry = gtk_entry_new();
1156         gtk_widget_set_can_focus(entry, FALSE);
1157         gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1158         if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1159         gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1160         gtk_widget_show(entry);
1161         gtk_widget_show(gd->dialog);
1162 }
1163
1164 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
1165 {
1166         GtkWidget *pTextView;
1167         GtkTextBuffer *pTextBuffer;
1168         GtkTextIter iStart;
1169         GtkTextIter iEnd;
1170
1171         pTextView = GTK_WIDGET(data);
1172
1173         pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1174         gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1175         gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1176
1177         set_image_overlay_template_string(&c_options->image_overlay.template_string,
1178                                           gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1179 }
1180
1181 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
1182 {
1183         GtkTextView *text_view = data;
1184         GtkTextBuffer *buffer;
1185
1186         set_default_image_overlay_template_string(&options->image_overlay.template_string);
1187         if (!configwindow) return;
1188
1189         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1190         gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1191 }
1192
1193 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1194 {
1195         GenericDialog *gd;
1196
1197         gd = generic_dialog_new(_("Reset image overlay template string"),
1198                                 "reset_image_overlay_template_string", widget, TRUE,
1199                                 dummy_cancel_cb, data);
1200         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1201                                    _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1202         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1203         gtk_widget_show(gd->dialog);
1204 }
1205
1206 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
1207 {
1208         help_window_show("GuideOptionsWindow.html#OverlayScreenDisplay");
1209 }
1210
1211 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer data)
1212 {
1213 #if GTK_CHECK_VERSION(3,4,0)
1214         GtkWidget *dialog;
1215         char *font;
1216         PangoFontDescription *font_desc;
1217
1218         dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1219         gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1220
1221         if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1222                 {
1223                 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1224                 font = pango_font_description_to_string(font_desc);
1225                 g_free(c_options->image_overlay.font);
1226                 c_options->image_overlay.font = g_strdup(font);
1227                 g_free(font);
1228                 }
1229
1230         gtk_widget_destroy(dialog);
1231 #else
1232         const char *font;
1233
1234         font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
1235         c_options->image_overlay.font = g_strdup(font);
1236 #endif
1237 }
1238
1239 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer data)
1240 {
1241         GtkWidget *dialog;
1242 #if GTK_CHECK_VERSION(3,4,0)
1243         GdkRGBA colour;
1244
1245         dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1246         colour.red = options->image_overlay.text_red;
1247         colour.green = options->image_overlay.text_green;
1248         colour.blue = options->image_overlay.text_blue;
1249         colour.alpha = options->image_overlay.text_alpha;
1250         gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1251         gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1252
1253         if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1254                 {
1255                 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1256                 c_options->image_overlay.text_red = colour.red*255;
1257                 c_options->image_overlay.text_green = colour.green*255;
1258                 c_options->image_overlay.text_blue = colour.blue*255;
1259                 c_options->image_overlay.text_alpha = colour.alpha*255;
1260                 }
1261         gtk_widget_destroy(dialog);
1262 #else
1263         GdkColor colour;
1264         GtkColorSelection *colorsel;
1265
1266         dialog = gtk_color_selection_dialog_new("Image Overlay Text Colour");
1267         gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1268         colour.red = options->image_overlay.text_red*257;
1269         colour.green = options->image_overlay.text_green*257;
1270         colour.blue = options->image_overlay.text_blue*257;
1271         colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1272         gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1273         gtk_color_selection_set_current_color(colorsel, &colour);
1274         gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.text_alpha*257);
1275
1276         if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1277                 {
1278                 gtk_color_selection_get_current_color(colorsel, &colour);
1279                 c_options->image_overlay.text_red = colour.red/257;
1280                 c_options->image_overlay.text_green = colour.green/257;
1281                 c_options->image_overlay.text_blue = colour.blue/257;
1282                 c_options->image_overlay.text_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1283                 }
1284         gtk_widget_destroy (dialog);
1285 #endif
1286 }
1287
1288
1289 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer data)
1290 {
1291         GtkWidget *dialog;
1292 #if GTK_CHECK_VERSION(3,4,0)
1293         GdkRGBA colour;
1294
1295         dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1296         colour.red = options->image_overlay.background_red;
1297         colour.green = options->image_overlay.background_green;
1298         colour.blue = options->image_overlay.background_blue;
1299         colour.alpha = options->image_overlay.background_alpha;
1300         gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1301         gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1302
1303         if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1304                 {
1305                 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1306                 c_options->image_overlay.background_red = colour.red*255;
1307                 c_options->image_overlay.background_green = colour.green*255;
1308                 c_options->image_overlay.background_blue = colour.blue*255;
1309                 c_options->image_overlay.background_alpha = colour.alpha*255;
1310                 }
1311         gtk_widget_destroy(dialog);
1312 #else
1313         GdkColor colour;
1314         GtkColorSelection *colorsel;
1315
1316         dialog = gtk_color_selection_dialog_new("Image Overlay Background Colour");
1317         gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1318         colour.red = options->image_overlay.background_red*257;
1319         colour.green = options->image_overlay.background_green*257;
1320         colour.blue = options->image_overlay.background_blue*257;
1321         colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1322         gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1323         gtk_color_selection_set_current_color(colorsel, &colour);
1324         gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.background_alpha*257);
1325
1326         if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1327                 {
1328                 gtk_color_selection_get_current_color(colorsel, &colour);
1329                 c_options->image_overlay.background_red = colour.red/257;
1330                 c_options->image_overlay.background_green = colour.green/257;
1331                 c_options->image_overlay.background_blue = colour.blue/257;
1332                 c_options->image_overlay.background_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1333                 }
1334         gtk_widget_destroy(dialog);
1335 #endif
1336 }
1337
1338 static void accel_store_populate(void)
1339 {
1340         LayoutWindow *lw;
1341         GList *groups, *actions;
1342         GtkAction *action;
1343         const gchar *accel_path;
1344         GtkAccelKey key;
1345         GtkTreeIter iter;
1346
1347         if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1348
1349         gtk_tree_store_clear(accel_store);
1350         lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
1351
1352         g_assert(lw && lw->ui_manager);
1353         groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1354         while (groups)
1355                 {
1356                 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1357                 while (actions)
1358                         {
1359                         action = GTK_ACTION(actions->data);
1360                         accel_path = gtk_action_get_accel_path(action);
1361                         if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1362                                 {
1363                                 gchar *label, *label2, *tooltip, *accel;
1364                                 g_object_get(action,
1365                                              "tooltip", &tooltip,
1366                                              "label", &label,
1367                                              NULL);
1368
1369                                 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1370                                         {
1371                                         g_free(label);
1372                                         label = label2;
1373                                         }
1374
1375                                 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1376
1377                                 if (tooltip)
1378                                         {
1379                                         gtk_tree_store_append(accel_store, &iter, NULL);
1380                                         gtk_tree_store_set(accel_store, &iter,
1381                                                            AE_ACTION, label,
1382                                                            AE_KEY, accel,
1383                                                            AE_TOOLTIP, tooltip ? tooltip : "",
1384                                                            AE_ACCEL, accel_path,
1385                                                            -1);
1386                                         }
1387
1388                                 g_free(accel);
1389                                 g_free(label);
1390                                 g_free(tooltip);
1391                                 }
1392                         actions = actions->next;
1393                         }
1394
1395                 groups = groups->next;
1396                 }
1397 }
1398
1399 static void accel_store_cleared_cb(GtkCellRendererAccel *accel, gchar *path_string, gpointer user_data)
1400 {
1401
1402 }
1403
1404 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1405 {
1406         gchar *accel1 = data;
1407         gchar *accel2;
1408         GtkAccelKey key1;
1409         GtkAccelKey key2;
1410
1411         gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1412
1413         gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1414         gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1415
1416         if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1417                 {
1418                 gtk_tree_store_set(accel_store, iter, AE_KEY, "",  -1);
1419                 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1420                 }
1421
1422         g_free(accel2);
1423
1424         return FALSE;
1425 }
1426
1427
1428 static void accel_store_edited_cb(GtkCellRendererAccel *accel, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode, gpointer user_data)
1429 {
1430         GtkTreeModel *model = (GtkTreeModel *)accel_store;
1431         GtkTreeIter iter;
1432         gchar *acc;
1433         gchar *accel_path;
1434         GtkAccelKey old_key, key;
1435         GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1436
1437         gtk_tree_model_get_iter(model, &iter, path);
1438         gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1439
1440         /* test if the accelerator can be stored without conflicts*/
1441         gtk_accel_map_lookup_entry(accel_path, &old_key);
1442
1443         /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1444         gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1445         gtk_accel_map_lookup_entry(accel_path, &key);
1446
1447         /* restore the original for now, the key will be really changed when the changes are confirmed */
1448         gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1449
1450         acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1451         gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1452
1453         gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1454         gtk_tree_path_free(path);
1455         g_free(acc);
1456 }
1457
1458 static gboolean accel_default_scroll(GtkTreeView *data)
1459 {
1460         GtkTreeIter iter;
1461         GtkTreePath *path;
1462         GtkTreeViewColumn *column;
1463
1464         gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1465         path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1466         column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1467
1468         gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1469                                      path, column,
1470                                      FALSE, 0.0, 0.0);
1471
1472         gtk_tree_path_free(path);
1473
1474         return(FALSE);
1475 }
1476
1477 static void accel_default_cb(GtkWidget *widget, gpointer data)
1478 {
1479         accel_store_populate();
1480
1481         g_idle_add((GSourceFunc)accel_default_scroll, data);
1482 }
1483
1484 void accel_remove_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1485 {
1486         gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1487 }
1488
1489 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1490 {
1491         GtkAccelKey key;
1492         gchar *accel_path, *accel;
1493
1494         gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1495         gtk_accel_map_lookup_entry(accel_path, &key);
1496         accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1497
1498         gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1499
1500         gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1501         g_free(accel_path);
1502         g_free(accel);
1503 }
1504
1505 static void accel_reset_cb(GtkWidget *widget, gpointer data)
1506 {
1507         GtkTreeSelection *selection;
1508
1509         if (!accel_store) return;
1510         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1511         gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1512 }
1513
1514
1515
1516 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1517 {
1518         GtkWidget *label;
1519         GtkWidget *vbox;
1520         GtkWidget *scrolled;
1521         GtkWidget *viewport;
1522
1523         scrolled = gtk_scrolled_window_new(NULL, NULL);
1524         gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1525         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1526                                        GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1527         label = gtk_label_new(title);
1528         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1529         gtk_widget_show(scrolled);
1530
1531         viewport = gtk_viewport_new(NULL, NULL);
1532         gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1533         gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1534         gtk_widget_show(viewport);
1535
1536         vbox = gtk_vbox_new(FALSE, 0);
1537         gtk_container_add(GTK_CONTAINER(viewport), vbox);
1538         gtk_widget_show(vbox);
1539
1540         return vbox;
1541 }
1542
1543 static void cache_standard_cb(GtkWidget *widget, gpointer data)
1544 {
1545         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1546                 {
1547                 c_options->thumbnails.spec_standard =TRUE;
1548                 c_options->thumbnails.cache_into_dirs = FALSE;
1549                 }
1550         else
1551                 {
1552                 c_options->thumbnails.spec_standard =FALSE;
1553                 }
1554 }
1555
1556 static void cache_geeqie_cb(GtkWidget *widget, gpointer data)
1557 {
1558         if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1559                 {
1560                 c_options->thumbnails.spec_standard =TRUE;
1561                 c_options->thumbnails.cache_into_dirs = FALSE;
1562                 }
1563         else
1564                 {
1565                 c_options->thumbnails.spec_standard =FALSE;
1566                 }
1567 }
1568
1569 static void cache_local_cb(GtkWidget *widget, gpointer data)
1570 {
1571         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1572                 {
1573                 c_options->thumbnails.cache_into_dirs = TRUE;
1574                 c_options->thumbnails.spec_standard =FALSE;
1575                 }
1576         else
1577                 {
1578                 c_options->thumbnails.cache_into_dirs = FALSE;
1579                 }
1580 }
1581
1582 /* general options tab */
1583 static void config_tab_general(GtkWidget *notebook)
1584 {
1585         GtkWidget *vbox;
1586         GtkWidget *hbox;
1587         GtkWidget *group;
1588         GtkWidget *group_frame;
1589         GtkWidget *subgroup;
1590         GtkWidget *button;
1591         GtkWidget *ct_button;
1592         GtkWidget *table;
1593         GtkWidget *spin;
1594         gint hours, minutes, remainder;
1595         gdouble seconds;
1596
1597         vbox = scrolled_notebook_page(notebook, _("General"));
1598
1599         group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1600
1601         table = pref_table_new(group, 2, 2, FALSE, FALSE);
1602         add_thumb_size_menu(table, 0, 0, _("Size:"));
1603         add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1604
1605         ct_button = pref_checkbox_new_int(group, _("Cache thumbnails"),
1606                                           options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1607
1608         subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1609         pref_checkbox_link_sensitivity(ct_button, subgroup);
1610
1611         group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
1612                                                                                 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1613         button = pref_radiobutton_new(group_frame, NULL,  get_thumbnails_cache_dir(),
1614                                                         !options->thumbnails.spec_standard,
1615                                                         G_CALLBACK(cache_geeqie_cb), NULL);
1616
1617         group_frame = pref_frame_new(subgroup, TRUE,
1618                                                         _("Store thumbnails local to image folder (non-standard)"),
1619                                                         GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1620         pref_radiobutton_new(group_frame, button, "*/.thumbnails",
1621                                                         options->thumbnails.cache_into_dirs,
1622                                                         G_CALLBACK(cache_local_cb), NULL);
1623
1624         group_frame = pref_frame_new(subgroup, TRUE,
1625                                                         _("Use standard thumbnail style and cache, shared with other applications"),
1626                                                         GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1627         pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
1628                                                         options->thumbnails.spec_standard,
1629                                                         G_CALLBACK(cache_standard_cb), NULL);
1630
1631         pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
1632                               options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
1633
1634 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
1635         pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
1636                               options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
1637
1638 //      pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
1639 //                            options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
1640 #endif
1641
1642         group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
1643
1644         c_options->slideshow.delay = options->slideshow.delay;
1645         hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
1646         remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
1647         minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
1648         seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
1649                                                                                         SLIDESHOW_SUBSECOND_PRECISION;
1650
1651         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1652
1653         spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
1654                                                                                 0, 23, 1.0, 0,
1655                                                                                 options->slideshow.delay ? hours : 0.0,
1656                                                                                 G_CALLBACK(slideshow_delay_hours_cb), NULL);
1657         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
1658         spin = pref_spin_new(hbox, ":" , NULL,
1659                                                                                 0, 59, 1.0, 0,
1660                                                                                 options->slideshow.delay ? minutes: 0.0,
1661                                                                                 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
1662         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
1663         spin = pref_spin_new(hbox, ":", NULL,
1664                                                                                 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
1665                                                                                 options->slideshow.delay ? seconds : 10.0,
1666                                                                                 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
1667         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
1668
1669         pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
1670         pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
1671
1672         group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
1673
1674         pref_spin_new_int(group, _("Decoded image cache size (Mb):"), NULL,
1675                           0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
1676         pref_checkbox_new_int(group, _("Preload next image"),
1677                               options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
1678
1679         pref_checkbox_new_int(group, _("Refresh on file change"),
1680                               options->update_on_time_change, &c_options->update_on_time_change);
1681
1682         group = pref_group_new(vbox, FALSE, _("Info sidebar heights"), GTK_ORIENTATION_VERTICAL);
1683         pref_label_new(group, _("NOTE! Geeqie must be restarted for changes to take effect"));
1684         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1685         pref_spin_new_int(hbox, _("Keywords:"), NULL,
1686                                  1, 9999, 1,
1687                                  options->info_keywords.height, &c_options->info_keywords.height);
1688         pref_spin_new_int(hbox, _("Title:"), NULL,
1689                                  1, 9999, 1,
1690                                  options->info_title.height, &c_options->info_title.height);
1691         pref_spin_new_int(hbox, _("Comment:"), NULL,
1692                                  1, 9999, 1,
1693                                  options->info_comment.height, &c_options->info_comment.height);
1694         pref_spin_new_int(hbox, _("Rating:"), NULL,
1695                                  1, 9999, 1,
1696                                  options->info_rating.height, &c_options->info_rating.height);
1697 }
1698
1699 /* image tab */
1700 static void config_tab_image(GtkWidget *notebook)
1701 {
1702         GtkWidget *hbox;
1703         GtkWidget *vbox;
1704         GtkWidget *group;
1705         GtkWidget *ct_button;
1706         GtkWidget *enlargement_button;
1707         GtkWidget *table;
1708         GtkWidget *spin;
1709
1710         vbox = scrolled_notebook_page(notebook, _("Image"));
1711
1712         group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
1713
1714         table = pref_table_new(group, 2, 1, FALSE, FALSE);
1715         add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
1716
1717 #ifdef HAVE_CLUTTER
1718         pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library"),
1719                               options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
1720 #endif
1721
1722         pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
1723                               options->image.zoom_2pass, &c_options->image.zoom_2pass);
1724
1725         c_options->image.zoom_increment = options->image.zoom_increment;
1726         spin = pref_spin_new(group, _("Zoom increment:"), NULL,
1727                              0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
1728                              G_CALLBACK(zoom_increment_cb), NULL);
1729         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
1730
1731         group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
1732
1733         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1734         enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
1735                               options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
1736         spin = pref_spin_new_int(hbox, NULL, NULL,
1737                                  100, 999, 1,
1738                                  options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
1739         pref_checkbox_link_sensitivity(enlargement_button, spin);
1740         gtk_widget_set_tooltip_text(GTK_WIDGET(hbox), _("Enable this to allow Geeqie to increase the image size for images that are smaller than the current view area when the zoom is set to \"Fit image to window\". This value sets the maximum expansion permitted in percent i.e. 100% is full-size."));
1741
1742         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1743         ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
1744                                           options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
1745         spin = pref_spin_new_int(hbox, NULL, NULL,
1746                                  10, 150, 1,
1747                                  options->image.max_autofit_size, &c_options->image.max_autofit_size);
1748         pref_checkbox_link_sensitivity(ct_button, spin);
1749         gtk_widget_set_tooltip_text(GTK_WIDGET(hbox), _("This value will set the virtual size of the window when \"Fit image to window\" is set. Instead of using the actual size of the window, the specified percentage of the window will be used. It allows one to keep a border around the image (values lower than 100%) or to auto zoom the image (values greater than 100%). It affects fullscreen mode too."));
1750
1751         group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
1752
1753         pref_checkbox_new_int(group, _("Use custom border color in window mode"),
1754                               options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
1755
1756         pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
1757                               options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
1758
1759         pref_color_button_new(group, _("Border color"), &options->image.border_color,
1760                               G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
1761
1762         c_options->image.border_color = options->image.border_color;
1763
1764         pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
1765                               G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
1766
1767         pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
1768                               G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
1769
1770         c_options->image.alpha_color_1 = options->image.alpha_color_1;
1771         c_options->image.alpha_color_2 = options->image.alpha_color_2;
1772
1773         group = pref_group_new(vbox, FALSE, _("Convenience"), GTK_ORIENTATION_VERTICAL);
1774
1775         pref_checkbox_new_int(group, _("Auto rotate proofs using Exif information"),
1776                               options->image.exif_proof_rotate_enable, &c_options->image.exif_proof_rotate_enable);
1777 }
1778
1779 /* windows tab */
1780 static void config_tab_windows(GtkWidget *notebook)
1781 {
1782         GtkWidget *hbox;
1783         GtkWidget *vbox;
1784         GtkWidget *group;
1785         GtkWidget *button;
1786         GtkWidget *ct_button;
1787         GtkWidget *spin;
1788         GtkWidget *image_overlay_template_view;
1789         GtkWidget *scrolled;
1790         GtkTextBuffer *buffer;
1791
1792         vbox = scrolled_notebook_page(notebook, _("Windows"));
1793
1794         group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
1795
1796         ct_button = pref_checkbox_new_int(group, _("Remember window positions"),
1797                                           options->save_window_positions, &c_options->save_window_positions);
1798
1799         button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
1800                                        options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
1801         pref_checkbox_link_sensitivity(ct_button, button);
1802
1803         pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
1804                               options->tools_restore_state, &c_options->tools_restore_state);
1805
1806         pref_checkbox_new_int(group, _("Remember dialog window positions"),
1807                               options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
1808
1809         group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
1810
1811         pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
1812                               options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
1813
1814         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1815         ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
1816                                           options->image.limit_window_size, &c_options->image.limit_window_size);
1817         spin = pref_spin_new_int(hbox, NULL, NULL,
1818                                  10, 150, 1,
1819                                  options->image.max_window_size, &c_options->image.max_window_size);
1820         pref_checkbox_link_sensitivity(ct_button, spin);
1821
1822         group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
1823
1824         c_options->fullscreen.screen = options->fullscreen.screen;
1825         c_options->fullscreen.above = options->fullscreen.above;
1826         hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
1827         gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
1828         gtk_widget_show(hbox);
1829
1830         pref_checkbox_new_int(group, _("Smooth image flip"),
1831                               options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
1832         pref_checkbox_new_int(group, _("Disable screen saver"),
1833                               options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
1834
1835
1836         group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
1837
1838         pref_label_new(group, _("Image overlay template"));
1839
1840         scrolled = gtk_scrolled_window_new(NULL, NULL);
1841         gtk_widget_set_size_request(scrolled, 200, 150);
1842         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
1843         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1844                                        GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1845         gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
1846         gtk_widget_show(scrolled);
1847
1848         image_overlay_template_view = gtk_text_view_new();
1849
1850         gtk_widget_set_tooltip_markup(image_overlay_template_view,
1851         _("<i>%name%</i> results in the filename of the picture.\n"
1852           "Also available: <i>%collection%</i>, <i>%number%</i>, <i>%total%</i>, <i>%date%</i>,\n"
1853           "<i>%size%</i> (filesize), <i>%width%</i>, <i>%height%</i>, <i>%res%</i> (resolution),\n"
1854           "<i>%rating%</i>, <i>%keywords%</i>, <i>%comment%</i> (XMP), <i>%imagecomment%</i> (JPEG)\n"
1855           "To access exif data use the exif name, e. g. <i>%formatted.Camera%</i> is the formatted camera name,\n"
1856           "<i>%Exif.Photo.DateTimeOriginal%</i> the date of the original shot.\n"
1857           "<i>%formatted.Camera:20</i> notation will truncate the displayed data to 20 characters and will add 3 dots at the end to denote the truncation.\n"
1858           "If two or more variables are connected with the |-sign, it prints available variables with a separator.\n"
1859           "<i>%formatted.ShutterSpeed%</i>|<i>%formatted.ISOSpeedRating%</i>|<i>%formatted.FocalLength%</i> could show \"1/20s - 400 - 80 mm\" or \"1/200 - 80 mm\",\n"
1860           "if there's no ISO information in the Exif data.\n"
1861           "If a line is empty, it is removed. This allows one to add lines that totally disappear when no data is available.\n"
1862         ));
1863         gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
1864         gtk_widget_show(image_overlay_template_view);
1865
1866         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
1867
1868 #if GTK_CHECK_VERSION(3,4,0)
1869         button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
1870                                  G_CALLBACK(image_overlay_set_font_cb), notebook);
1871 #else
1872         button = gtk_font_button_new();
1873         gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
1874         gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
1875         g_signal_connect(G_OBJECT(button), "font-set",
1876                                  G_CALLBACK(image_overlay_set_font_cb),NULL);
1877 #endif
1878         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1879         gtk_widget_show(button);
1880
1881         button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
1882                                  G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
1883         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1884         gtk_widget_show(button);
1885
1886         button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
1887                                  G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
1888         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1889         gtk_widget_show(button);
1890         image_overlay_set_text_colours();
1891
1892         button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
1893                                  G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
1894         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1895         gtk_widget_show(button);
1896
1897         button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
1898                                  G_CALLBACK(image_overlay_help_cb), NULL);
1899         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1900         gtk_widget_show(button);
1901
1902         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
1903         if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1904         g_signal_connect(G_OBJECT(buffer), "changed",
1905                          G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
1906
1907
1908 }
1909
1910 static GtkTreeModel *create_class_model(void)
1911 {
1912         GtkListStore *model;
1913         GtkTreeIter iter;
1914         gint i;
1915
1916         /* create list store */
1917         model = gtk_list_store_new(1, G_TYPE_STRING);
1918         for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1919                 {
1920                 gtk_list_store_append(model, &iter);
1921                 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
1922                 }
1923         return GTK_TREE_MODEL (model);
1924 }
1925
1926
1927 /* filtering tab */
1928 static void config_tab_files(GtkWidget *notebook)
1929 {
1930         GtkWidget *hbox;
1931         GtkWidget *frame;
1932         GtkWidget *vbox;
1933         GtkWidget *group;
1934         GtkWidget *button;
1935         GtkWidget *ct_button;
1936         GtkWidget *scrolled;
1937         GtkWidget *filter_view;
1938         GtkCellRenderer *renderer;
1939         GtkTreeSelection *selection;
1940         GtkTreeViewColumn *column;
1941
1942         vbox = scrolled_notebook_page(notebook, _("Files"));
1943
1944         group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1945
1946         pref_checkbox_new_int(group, _("Show hidden files or folders"),
1947                               options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
1948         pref_checkbox_new_int(group, _("Show parent folder (..)"),
1949                               options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
1950         pref_checkbox_new_int(group, _("Case sensitive sort"),
1951                               options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
1952         pref_checkbox_new_int(group, _("Natural sort order"),
1953                                           options->file_sort.natural, &c_options->file_sort.natural);
1954         pref_checkbox_new_int(group, _("Disable file extension checks"),
1955                               options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
1956
1957         ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
1958                                           options->file_filter.disable, &c_options->file_filter.disable);
1959
1960
1961         group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
1962
1963         sidecar_ext_entry = gtk_entry_new();
1964         gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
1965         gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
1966         gtk_widget_show(sidecar_ext_entry);
1967
1968         group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
1969
1970         frame = pref_group_parent(group);
1971         g_signal_connect(G_OBJECT(ct_button), "toggled",
1972                          G_CALLBACK(filter_disable_cb), frame);
1973         gtk_widget_set_sensitive(frame, !options->file_filter.disable);
1974
1975         scrolled = gtk_scrolled_window_new(NULL, NULL);
1976         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
1977         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1978         gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
1979         gtk_widget_show(scrolled);
1980
1981         filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
1982         filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
1983         g_object_unref(filter_store);
1984         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1985         gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
1986
1987         gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
1988
1989         column = gtk_tree_view_column_new();
1990         gtk_tree_view_column_set_title(column, _("Filter"));
1991         gtk_tree_view_column_set_resizable(column, TRUE);
1992
1993         renderer = gtk_cell_renderer_toggle_new();
1994         g_signal_connect(G_OBJECT(renderer), "toggled",
1995                          G_CALLBACK(filter_store_enable_cb), filter_store);
1996         gtk_tree_view_column_pack_start(column, renderer, FALSE);
1997         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
1998                                                 GINT_TO_POINTER(FE_ENABLE), NULL);
1999
2000         renderer = gtk_cell_renderer_text_new();
2001         g_signal_connect(G_OBJECT(renderer), "edited",
2002                          G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2003         gtk_tree_view_column_pack_start(column, renderer, TRUE);
2004         g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2005         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2006                                                 GINT_TO_POINTER(FE_EXTENSION), NULL);
2007         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2008
2009         column = gtk_tree_view_column_new();
2010         gtk_tree_view_column_set_title(column, _("Description"));
2011         gtk_tree_view_column_set_resizable(column, TRUE);
2012         gtk_tree_view_column_set_fixed_width(column, 200);
2013         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2014
2015         renderer = gtk_cell_renderer_text_new();
2016         g_signal_connect(G_OBJECT(renderer), "edited",
2017                          G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2018         g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2019         gtk_tree_view_column_pack_start(column, renderer, FALSE);
2020         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2021                                                 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2022         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2023
2024         column = gtk_tree_view_column_new();
2025         gtk_tree_view_column_set_title(column, _("Class"));
2026         gtk_tree_view_column_set_resizable(column, TRUE);
2027         renderer = gtk_cell_renderer_combo_new();
2028         g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2029                                          "model", create_class_model(),
2030                                          "text-column", 0,
2031                                          "has-entry", FALSE,
2032                                          NULL);
2033
2034         g_signal_connect(G_OBJECT(renderer), "edited",
2035                          G_CALLBACK(filter_store_class_edit_cb), filter_store);
2036         gtk_tree_view_column_pack_start(column, renderer, TRUE);
2037         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2038                                                 GINT_TO_POINTER(FE_CLASS), NULL);
2039         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2040
2041         column = gtk_tree_view_column_new();
2042         gtk_tree_view_column_set_title(column, _("Writable"));
2043         gtk_tree_view_column_set_resizable(column, FALSE);
2044         renderer = gtk_cell_renderer_toggle_new();
2045         g_signal_connect(G_OBJECT(renderer), "toggled",
2046                          G_CALLBACK(filter_store_writable_cb), filter_store);
2047         gtk_tree_view_column_pack_start(column, renderer, FALSE);
2048         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2049                                                 GINT_TO_POINTER(FE_WRITABLE), NULL);
2050         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2051
2052         column = gtk_tree_view_column_new();
2053         gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2054         gtk_tree_view_column_set_resizable(column, FALSE);
2055         renderer = gtk_cell_renderer_toggle_new();
2056         g_signal_connect(G_OBJECT(renderer), "toggled",
2057                          G_CALLBACK(filter_store_sidecar_cb), filter_store);
2058         gtk_tree_view_column_pack_start(column, renderer, FALSE);
2059         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2060                                                 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2061         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2062
2063
2064         filter_store_populate();
2065         gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2066         gtk_widget_show(filter_view);
2067
2068         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2069
2070         button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2071                                  G_CALLBACK(filter_default_cb), filter_view);
2072         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2073         gtk_widget_show(button);
2074
2075         button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2076                                  G_CALLBACK(filter_remove_cb), filter_view);
2077         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2078         gtk_widget_show(button);
2079
2080         button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2081                                  G_CALLBACK(filter_add_cb), filter_view);
2082         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2083         gtk_widget_show(button);
2084 }
2085
2086 /* metadata tab */
2087 static void config_tab_metadata(GtkWidget *notebook)
2088 {
2089         GtkWidget *vbox;
2090         GtkWidget *hbox;
2091         GtkWidget *group;
2092         GtkWidget *ct_button;
2093         GtkWidget *label;
2094         gchar *text;
2095
2096         vbox = scrolled_notebook_page(notebook, _("Metadata"));
2097
2098
2099         group = pref_group_new(vbox, FALSE, _("Metadata writing process"), GTK_ORIENTATION_VERTICAL);
2100 #ifndef HAVE_EXIV2
2101         label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2102 #endif
2103         label = pref_label_new(group, _("Metadata are written in the following order. The process ends after first success."));
2104         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2105
2106         ct_button = pref_checkbox_new_int(group, _("1) Save metadata in image files, or sidecar files, according to the XMP standard"),
2107                               options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2108 #ifndef HAVE_EXIV2
2109         gtk_widget_set_sensitive(ct_button, FALSE);
2110 #endif
2111
2112         pref_checkbox_new_int(group, _("2) Save metadata in '.metadata' folder, local to image folder (non-standard)"),
2113                               options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2114
2115         text = g_strdup_printf(_("3) Save metadata in Geeqie private directory '%s'"), get_metadata_cache_dir());
2116         label = pref_label_new(group, text);
2117         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2118         gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2119         g_free(text);
2120
2121         group = pref_group_new(vbox, FALSE, _("Step 1: Write to image files"), GTK_ORIENTATION_VERTICAL);
2122 #ifndef HAVE_EXIV2
2123         gtk_widget_set_sensitive(group, FALSE);
2124 #endif
2125
2126         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2127         pref_checkbox_link_sensitivity(ct_button, hbox);
2128
2129         pref_checkbox_new_int(hbox, _("Store metadata also in legacy IPTC tags (converted according to IPTC4XMP standard)"),
2130                               options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2131
2132         pref_checkbox_new_int(hbox, _("Warn if the image files are unwritable"),
2133                               options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2134
2135         pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
2136                               options->metadata.confirm_write, &c_options->metadata.confirm_write);
2137
2138         pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
2139                               options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2140
2141         group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
2142 #ifndef HAVE_EXIV2
2143         gtk_widget_set_sensitive(group, FALSE);
2144 #endif
2145
2146         pref_checkbox_new_int(group, _("Use GQview legacy metadata format (supports only keywords and comments) instead of XMP"),
2147                               options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2148
2149
2150         group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2151         pref_checkbox_new_int(group, _("Write the same description tags (keywords, comment, etc.) to all grouped sidecars"),
2152                               options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2153
2154         pref_checkbox_new_int(group, _("Allow keywords to differ only in case"),
2155                               options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2156
2157         ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"),
2158                               options->metadata.write_orientation, &c_options->metadata.write_orientation);
2159 #ifndef HAVE_EXIV2
2160         gtk_widget_set_sensitive(ct_button, FALSE);
2161 #endif
2162
2163         group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2164
2165         ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"),
2166                               options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2167
2168         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2169         pref_checkbox_link_sensitivity(ct_button, hbox);
2170
2171         pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1,
2172                               options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2173
2174         pref_checkbox_new_int(group, _("Write metadata on image change"),
2175                               options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2176
2177         pref_checkbox_new_int(group, _("Write metadata on directory change"),
2178                               options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2179 }
2180
2181 /* metadata tab */
2182 #ifdef HAVE_LCMS
2183 static void intent_menu_cb(GtkWidget *combo, gpointer data)
2184 {
2185         gint *option = data;
2186
2187         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
2188                 {
2189                 case 0:
2190                 default:
2191                         *option = INTENT_PERCEPTUAL;
2192                         break;
2193                 case 1:
2194                         *option = INTENT_RELATIVE_COLORIMETRIC;
2195                         break;
2196                 case 2:
2197                         *option = INTENT_SATURATION;
2198                         break;
2199                 case 3:
2200                         *option = INTENT_ABSOLUTE_COLORIMETRIC;
2201                         break;
2202                 }
2203 }
2204
2205 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
2206                              gint option, gint *option_c)
2207 {
2208         GtkWidget *combo;
2209         gint current = 0;
2210
2211         *option_c = option;
2212
2213         pref_table_label(table, column, row, text, 0.0);
2214
2215         combo = gtk_combo_box_text_new();
2216
2217         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
2218         if (option == INTENT_PERCEPTUAL) current = 0;
2219         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
2220         if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
2221         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
2222         if (option == INTENT_SATURATION) current = 2;
2223         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
2224         if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
2225
2226         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
2227
2228         gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
2229
2230         g_signal_connect(G_OBJECT(combo), "changed",
2231                          G_CALLBACK(intent_menu_cb), option_c);
2232
2233         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1,
2234                          GTK_EXPAND | GTK_FILL, 0, 0, 0);
2235         gtk_widget_show(combo);
2236 }
2237 #endif
2238
2239 static void config_tab_color(GtkWidget *notebook)
2240 {
2241         GtkWidget *label;
2242         GtkWidget *vbox;
2243         GtkWidget *group;
2244         GtkWidget *tabcomp;
2245         GtkWidget *table;
2246         gint i;
2247
2248         vbox = scrolled_notebook_page(notebook, _("Color management"));
2249
2250         group =  pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
2251 #ifndef HAVE_LCMS
2252         gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
2253 #endif
2254
2255         table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
2256         gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
2257
2258         label = pref_table_label(table, 0, 0, _("Type"), 0.0);
2259         pref_label_bold(label, TRUE, FALSE);
2260
2261         label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
2262         pref_label_bold(label, TRUE, FALSE);
2263
2264         label = pref_table_label(table, 2, 0, _("File"), 0.0);
2265         pref_label_bold(label, TRUE, FALSE);
2266
2267         for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
2268                 {
2269                 GtkWidget *entry;
2270                 gchar *buf;
2271
2272                 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
2273                 pref_table_label(table, 0, i + 1, buf, 1.0);
2274                 g_free(buf);
2275
2276                 entry = gtk_entry_new();
2277                 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
2278                 if (options->color_profile.input_name[i])
2279                         {
2280                         gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
2281                         }
2282                 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
2283                                  GTK_FILL | GTK_EXPAND, 0, 0, 0);
2284                 gtk_widget_show(entry);
2285                 color_profile_input_name_entry[i] = entry;
2286
2287                 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
2288                 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
2289                 gtk_widget_set_size_request(entry, 160, -1);
2290                 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
2291                                  GTK_FILL | GTK_EXPAND, 0, 0, 0);
2292                 gtk_widget_show(tabcomp);
2293                 color_profile_input_file_entry[i] = entry;
2294                 }
2295
2296         group =  pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
2297 #ifndef HAVE_LCMS
2298         gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
2299 #endif
2300         pref_checkbox_new_int(group, _("Use system screen profile if available"),
2301                               options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
2302
2303         table = pref_table_new(group, 2, 1, FALSE, FALSE);
2304
2305         pref_table_label(table, 0, 0, _("Screen:"), 1.0);
2306         tabcomp = tab_completion_new(&color_profile_screen_file_entry,
2307                                      options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
2308         tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
2309         gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
2310 #ifdef HAVE_LCMS
2311         add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
2312 #endif
2313         gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
2314                          0, 1,
2315                          GTK_FILL | GTK_EXPAND, 0, 0, 0);
2316
2317         gtk_widget_show(tabcomp);
2318 }
2319
2320 /* advanced entry tab */
2321 static void config_tab_behavior(GtkWidget *notebook)
2322 {
2323         GtkWidget *hbox;
2324         GtkWidget *vbox;
2325         GtkWidget *group;
2326         GtkWidget *button;
2327         GtkWidget *tabcomp;
2328         GtkWidget *ct_button;
2329         GtkWidget *spin;
2330         GtkWidget *table;
2331
2332         vbox = scrolled_notebook_page(notebook, _("Behavior"));
2333
2334         group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
2335
2336         pref_checkbox_new_int(group, _("Confirm file delete"),
2337                               options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
2338         pref_checkbox_new_int(group, _("Enable Delete key"),
2339                               options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
2340
2341         ct_button = pref_checkbox_new_int(group, _("Safe delete"),
2342                                           options->file_ops.safe_delete_enable, &c_options->file_ops.safe_delete_enable);
2343
2344         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2345         pref_checkbox_link_sensitivity(ct_button, hbox);
2346
2347         pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
2348         pref_label_new(hbox, _("Folder:"));
2349
2350         tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
2351         tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
2352         gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
2353         gtk_widget_show(tabcomp);
2354
2355         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2356         pref_checkbox_link_sensitivity(ct_button, hbox);
2357
2358         pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
2359         spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MB"),
2360                                  0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
2361         gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
2362         button = pref_button_new(NULL, NULL, _("View"), FALSE,
2363                                  G_CALLBACK(safe_delete_view_cb), NULL);
2364         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2365         gtk_widget_show(button);
2366
2367         button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
2368                                  G_CALLBACK(safe_delete_clear_cb), NULL);
2369         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2370         gtk_widget_show(button);
2371
2372
2373         group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
2374
2375         pref_checkbox_new_int(group, _("Descend folders in tree view"),
2376                               options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
2377
2378         pref_checkbox_new_int(group, _("In place renaming"),
2379                               options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
2380
2381         pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
2382                               options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
2383
2384         pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
2385                           1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
2386
2387         pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
2388                           16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
2389
2390         table = pref_table_new(group, 2, 1, FALSE, FALSE);
2391         add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
2392
2393         group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
2394
2395         pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
2396                               options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
2397         pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
2398                           1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
2399         pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
2400                               options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
2401         pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
2402                               options->image_lm_click_nav, &c_options->image_lm_click_nav);
2403         pref_checkbox_new_int(group, _("Play video by left click on image"),
2404                               options->image_l_click_video, &c_options->image_l_click_video);
2405         table = pref_table_new(group, 2, 1, FALSE, FALSE);
2406         add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
2407
2408
2409 #ifdef DEBUG
2410         group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
2411
2412         pref_spin_new_int(group, _("Debug level:"), NULL,
2413                           DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
2414
2415         pref_checkbox_new_int(group, _("Timer data"),
2416                         options->log_window.timer_data, &c_options->log_window.timer_data);
2417
2418         pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
2419                           1, 99999, 1, options->log_window_lines, &options->log_window_lines);
2420 #endif
2421 }
2422
2423 /* accelerators tab */
2424 static void config_tab_accelerators(GtkWidget *notebook)
2425 {
2426         GtkWidget *hbox;
2427         GtkWidget *vbox;
2428         GtkWidget *group;
2429         GtkWidget *button;
2430         GtkWidget *scrolled;
2431         GtkWidget *accel_view;
2432         GtkCellRenderer *renderer;
2433         GtkTreeSelection *selection;
2434         GtkTreeViewColumn *column;
2435
2436         vbox = scrolled_notebook_page(notebook, _("Keyboard"));
2437
2438         group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
2439
2440         scrolled = gtk_scrolled_window_new(NULL, NULL);
2441         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2442         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2443         gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2444         gtk_widget_show(scrolled);
2445
2446         accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
2447
2448         accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
2449         g_object_unref(accel_store);
2450         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
2451         gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
2452
2453         gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
2454
2455         renderer = gtk_cell_renderer_text_new();
2456
2457         column = gtk_tree_view_column_new_with_attributes(_("Action"),
2458                                                           renderer,
2459                                                           "text", AE_ACTION,
2460                                                           NULL);
2461
2462         gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
2463         gtk_tree_view_column_set_resizable(column, TRUE);
2464         gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
2465
2466
2467         renderer = gtk_cell_renderer_accel_new();
2468         g_signal_connect(G_OBJECT(renderer), "accel-cleared",
2469                          G_CALLBACK(accel_store_cleared_cb), accel_store);
2470         g_signal_connect(G_OBJECT(renderer), "accel-edited",
2471                          G_CALLBACK(accel_store_edited_cb), accel_store);
2472
2473
2474         g_object_set (renderer,
2475                       "editable", TRUE,
2476                       "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
2477                       NULL);
2478
2479         column = gtk_tree_view_column_new_with_attributes(_("KEY"),
2480                                                           renderer,
2481                                                           "text", AE_KEY,
2482                                                           NULL);
2483
2484         gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
2485         gtk_tree_view_column_set_resizable(column, TRUE);
2486         gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
2487
2488         renderer = gtk_cell_renderer_text_new();
2489
2490         column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
2491                                                           renderer,
2492                                                           "text", AE_TOOLTIP,
2493                                                           NULL);
2494
2495         gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
2496         gtk_tree_view_column_set_resizable(column, TRUE);
2497         gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
2498
2499         renderer = gtk_cell_renderer_text_new();
2500
2501         column = gtk_tree_view_column_new_with_attributes("Accel",
2502                                                           renderer,
2503                                                           "text", AE_ACCEL,
2504                                                           NULL);
2505
2506         gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
2507         gtk_tree_view_column_set_resizable(column, TRUE);
2508         gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
2509
2510         accel_store_populate();
2511         gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
2512         gtk_widget_show(accel_view);
2513
2514         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2515
2516         button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2517                                  G_CALLBACK(accel_default_cb), accel_view);
2518         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2519         gtk_widget_show(button);
2520
2521         button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
2522                                  G_CALLBACK(accel_reset_cb), accel_view);
2523         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2524         gtk_widget_show(button);
2525 }
2526
2527 /* toolbar tab */
2528 static void config_tab_toolbar(GtkWidget *notebook)
2529 {
2530         GtkWidget *vbox;
2531         GtkWidget *toolbardata;
2532         LayoutWindow *lw;
2533
2534         lw = layout_window_list->data;
2535
2536         vbox = scrolled_notebook_page(notebook, _("Toolbar"));
2537
2538         toolbardata = toolbar_select_new(lw);
2539         gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
2540         gtk_widget_show(vbox);
2541 }
2542
2543 /* stereo tab */
2544 static void config_tab_stereo(GtkWidget *notebook)
2545 {
2546         GtkWidget *vbox;
2547         GtkWidget *group;
2548         GtkWidget *group2;
2549         GtkWidget *table;
2550         GtkWidget *box;
2551         GtkWidget *box2;
2552         GtkWidget *fs_button;
2553         vbox = scrolled_notebook_page(notebook, _("Stereo"));
2554
2555         group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
2556
2557         table = pref_table_new(group, 2, 1, FALSE, FALSE);
2558         add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
2559
2560         table = pref_table_new(group, 2, 2, TRUE, FALSE);
2561         box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
2562         pref_checkbox_new_int(box, _("Mirror left image"),
2563                               options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
2564         box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
2565         pref_checkbox_new_int(box, _("Flip left image"),
2566                               options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
2567         box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
2568         pref_checkbox_new_int(box, _("Mirror right image"),
2569                               options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
2570         box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
2571         pref_checkbox_new_int(box, _("Flip right image"),
2572                               options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
2573         pref_checkbox_new_int(group, _("Swap left and right images"),
2574                               options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
2575         pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
2576                               options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
2577
2578         group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
2579         fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
2580                               options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
2581         box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2582         pref_checkbox_link_sensitivity(fs_button, box2);
2583         table = pref_table_new(box2, 2, 1, FALSE, FALSE);
2584         add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
2585         table = pref_table_new(box2, 2, 2, TRUE, FALSE);
2586         box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
2587         pref_checkbox_new_int(box, _("Mirror left image"),
2588                               options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
2589         box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
2590         pref_checkbox_new_int(box, _("Flip left image"),
2591                               options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
2592         box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
2593         pref_checkbox_new_int(box, _("Mirror right image"),
2594                               options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
2595         box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
2596         pref_checkbox_new_int(box, _("Flip right image"),
2597                               options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
2598         pref_checkbox_new_int(box2, _("Swap left and right images"),
2599                               options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
2600         pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
2601                               options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
2602
2603         group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
2604         table = pref_table_new(group2, 5, 3, FALSE, FALSE);
2605         pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
2606                           1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
2607         pref_table_spin_new_int(table, 3, 0,  _("Height"), NULL,
2608                           1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
2609         pref_table_spin_new_int(table, 0, 1,  _("Left X"), NULL,
2610                           0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
2611         pref_table_spin_new_int(table, 3, 1,  _("Left Y"), NULL,
2612                           0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
2613         pref_table_spin_new_int(table, 0, 2,  _("Right X"), NULL,
2614                           0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
2615         pref_table_spin_new_int(table, 3, 2,  _("Right Y"), NULL,
2616                           0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
2617
2618 }
2619
2620 /* Main preferences window */
2621 static void config_window_create(void)
2622 {
2623         GtkWidget *win_vbox;
2624         GtkWidget *hbox;
2625         GtkWidget *notebook;
2626         GtkWidget *button;
2627         GtkWidget *ct_button;
2628
2629         if (!c_options) c_options = init_options(NULL);
2630
2631         configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
2632         gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
2633         g_signal_connect(G_OBJECT(configwindow), "delete_event",
2634                          G_CALLBACK(config_window_delete), NULL);
2635         gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
2636         gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
2637         gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
2638
2639         win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
2640         gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
2641         gtk_widget_show(win_vbox);
2642
2643         notebook = gtk_notebook_new();
2644         gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
2645         gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
2646
2647         config_tab_general(notebook);
2648         config_tab_image(notebook);
2649         config_tab_windows(notebook);
2650         config_tab_accelerators(notebook);
2651         config_tab_files(notebook);
2652         config_tab_metadata(notebook);
2653         config_tab_color(notebook);
2654         config_tab_stereo(notebook);
2655         config_tab_behavior(notebook);
2656         config_tab_toolbar(notebook);
2657
2658         hbox = gtk_hbutton_box_new();
2659         gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
2660         gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
2661         gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
2662         gtk_widget_show(hbox);
2663
2664         button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2665                                  G_CALLBACK(config_window_help_cb), notebook);
2666         gtk_container_add(GTK_CONTAINER(hbox), button);
2667         gtk_widget_set_can_default(button, TRUE);
2668         gtk_widget_show(button);
2669
2670         button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
2671                                  G_CALLBACK(config_window_ok_cb), NULL);
2672         gtk_container_add(GTK_CONTAINER(hbox), button);
2673         gtk_widget_set_can_default(button, TRUE);
2674         gtk_widget_grab_default(button);
2675         gtk_widget_show(button);
2676
2677         ct_button = button;
2678
2679         button = pref_button_new(NULL, GTK_STOCK_SAVE, NULL, FALSE,
2680                                  G_CALLBACK(config_window_save_cb), NULL);
2681         gtk_container_add(GTK_CONTAINER(hbox), button);
2682         gtk_widget_set_can_default(button, TRUE);
2683         gtk_widget_show(button);
2684
2685         button = pref_button_new(NULL, GTK_STOCK_APPLY, NULL, FALSE,
2686                                  G_CALLBACK(config_window_apply_cb), NULL);
2687         gtk_container_add(GTK_CONTAINER(hbox), button);
2688         gtk_widget_set_can_default(button, TRUE);
2689         gtk_widget_show(button);
2690
2691         button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
2692                                  G_CALLBACK(config_window_close_cb), NULL);
2693         gtk_container_add(GTK_CONTAINER(hbox), button);
2694         gtk_widget_set_can_default(button, TRUE);
2695         gtk_widget_show(button);
2696
2697         if (!generic_dialog_get_alternative_button_order(configwindow))
2698                 {
2699                 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
2700                 }
2701
2702         gtk_widget_show(notebook);
2703
2704         gtk_widget_show(configwindow);
2705 }
2706
2707 /*
2708  *-----------------------------------------------------------------------------
2709  * config window show (public)
2710  *-----------------------------------------------------------------------------
2711  */
2712
2713 void show_config_window(void)
2714 {
2715         if (configwindow)
2716                 {
2717                 gtk_window_present(GTK_WINDOW(configwindow));
2718                 return;
2719                 }
2720
2721         config_window_create();
2722 }
2723
2724 /*
2725  *-----------------
2726  * about window
2727  *-----------------
2728  */
2729
2730 void show_about_window(LayoutWindow *lw)
2731 {
2732         GdkPixbuf *pixbuf_logo;
2733         GdkPixbuf *pixbuf_icon;
2734         gchar *authors[1000];
2735         gchar *comment;
2736         gint i_authors = 0;
2737         gchar *path;
2738         FILE *fp = NULL;
2739 #define LINE_LENGTH 1000
2740         gchar line[LINE_LENGTH];
2741
2742 #if !GTK_CHECK_VERSION(3,0,0)
2743         GString *copyright;
2744
2745         copyright = g_string_new(NULL);
2746         path = g_build_filename(GQ_HELPDIR, "COPYING", NULL);
2747         fp = fopen(path, "r");
2748         if (fp)
2749                 {
2750                 while(fgets(line, LINE_LENGTH, fp))
2751                         {
2752                         copyright = g_string_append(copyright, line);
2753                         }
2754                 fclose(fp);
2755                 }
2756         g_free(path);
2757 #endif
2758
2759         authors[0] = NULL;
2760         path = g_build_filename(GQ_HELPDIR, "AUTHORS", NULL);
2761         fp = fopen(path, "r");
2762         if (fp)
2763                 {
2764                 while(fgets(line, LINE_LENGTH, fp))
2765                         {
2766                         /* get rid of ending \n from fgets */
2767                         line[strlen(line) - 1] = '\0';
2768                         authors[i_authors] = g_strdup(line);
2769                         i_authors++;
2770                         }
2771                 authors[i_authors] = NULL;
2772                 fclose(fp);
2773                 }
2774         g_free(path);
2775
2776         comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
2777                                                 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
2778
2779         pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
2780         pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
2781         gtk_show_about_dialog(GTK_WINDOW(lw->window),
2782                 "title", _("About Geeqie"),
2783                 "resizable", TRUE,
2784                 "program-name", GQ_APPNAME,
2785                 "version", VERSION,
2786                 "logo", pixbuf_logo,
2787                 "icon", pixbuf_icon,
2788                 "website", GQ_WEBSITE,
2789                 "website-label", "Website",
2790                 "comments", comment,
2791                 "authors", authors,
2792                 "translator-credits", _("translator-credits"),
2793 #if GTK_CHECK_VERSION(3,0,0)
2794                 "license-type", GTK_LICENSE_GPL_2_0,
2795 #else
2796                 "license",  copyright->str,
2797 #endif
2798                 NULL);
2799
2800 #if !GTK_CHECK_VERSION(3,0,0)
2801         g_string_free(copyright, TRUE);
2802 #endif
2803         gint n = 0;
2804         while(n < i_authors)
2805                 {
2806                 g_free(authors[n]);
2807                 n++;
2808                 }
2809         g_free(comment);
2810
2811         return;
2812 }
2813
2814 static void image_overlay_set_text_colours()
2815 {
2816         c_options->image_overlay.text_red = options->image_overlay.text_red;
2817         c_options->image_overlay.text_green = options->image_overlay.text_green;
2818         c_options->image_overlay.text_blue = options->image_overlay.text_blue;
2819         c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
2820         c_options->image_overlay.background_red = options->image_overlay.background_red;
2821         c_options->image_overlay.background_green = options->image_overlay.background_green;
2822         c_options->image_overlay.background_blue = options->image_overlay.background_blue;
2823         c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
2824 }
2825 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */