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