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