Addl fix #521: zoom increment is not multiplicative
[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 "bar_keywords.h"
27 #include "cache.h"
28 #include "cache_maint.h"
29 #include "dnd.h"
30 #include "editors.h"
31 #include "exif.h"
32 #include "filedata.h"
33 #include "filefilter.h"
34 #include "fullscreen.h"
35 #include "image.h"
36 #include "image-overlay.h"
37 #include "color-man.h"
38 #include "img-view.h"
39 #include "layout_config.h"
40 #include "layout_util.h"
41 #include "metadata.h"
42 #include "misc.h"
43 #include "osd.h"
44 #include "pixbuf_util.h"
45 #include "rcfile.h"
46 #include "slideshow.h"
47 #include "toolbar.h"
48 #include "trash.h"
49 #include "utilops.h"
50 #include "ui_fileops.h"
51 #include "ui_misc.h"
52 #include "ui_spinner.h"
53 #include "ui_tabcomp.h"
54 #include "ui_utildlg.h"
55 #include "window.h"
56 #include "zonedetect.h"
57
58 #ifdef HAVE_LCMS
59 #ifdef HAVE_LCMS2
60 #include <lcms2.h>
61 #else
62 #include <lcms.h>
63 #endif
64 #endif
65
66 #define EDITOR_NAME_MAX_LENGTH 32
67 #define EDITOR_COMMAND_MAX_LENGTH 1024
68
69 static void image_overlay_set_text_colours();
70
71 GtkWidget *keyword_text;
72 static void config_tab_keywords_save();
73
74 typedef struct _ThumbSize ThumbSize;
75 struct _ThumbSize
76 {
77         gint w;
78         gint h;
79 };
80
81 static ThumbSize thumb_size_list[] =
82 {
83         { 24, 24 },
84         { 32, 32 },
85         { 48, 48 },
86         { 64, 64 },
87         { 96, 72 },
88         { 96, 96 },
89         { 128, 96 },
90         { 128, 128 },
91         { 160, 120 },
92         { 160, 160 },
93         { 192, 144 },
94         { 192, 192 },
95         { 256, 192 },
96         { 256, 256 }
97 };
98
99 enum {
100         FE_ENABLE,
101         FE_EXTENSION,
102         FE_DESCRIPTION,
103         FE_CLASS,
104         FE_WRITABLE,
105         FE_ALLOW_SIDECAR
106 };
107
108 enum {
109         AE_ACTION,
110         AE_KEY,
111         AE_TOOLTIP,
112         AE_ACCEL
113 };
114
115 gchar *format_class_list[] = {
116         N_("Unknown"),
117         N_("Image"),
118         N_("RAW Image"),
119         N_("Metadata"),
120         N_("Video"),
121         N_("Collection"),
122         N_("Document"),
123         N_("Archive")
124         };
125
126 /* config memory values */
127 static ConfOptions *c_options = NULL;
128
129
130 #ifdef DEBUG
131 static gint debug_c;
132 #endif
133
134 static GtkWidget *configwindow = NULL;
135 static GtkListStore *filter_store = NULL;
136 static GtkTreeStore *accel_store = NULL;
137
138 static GtkWidget *safe_delete_path_entry;
139
140 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
141 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
142 static GtkWidget *color_profile_screen_file_entry;
143 static GtkWidget *external_preview_select_entry;
144 static GtkWidget *external_preview_extract_entry;
145
146 static GtkWidget *sidecar_ext_entry;
147 static GtkWidget *help_search_engine_entry;
148
149
150 #define CONFIG_WINDOW_DEF_WIDTH         700
151 #define CONFIG_WINDOW_DEF_HEIGHT        600
152
153 /*
154  *-----------------------------------------------------------------------------
155  * option widget callbacks (private)
156  *-----------------------------------------------------------------------------
157  */
158
159 static void zoom_increment_cb(GtkWidget *spin, gpointer data)
160 {
161         c_options->image.zoom_increment = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
162 }
163
164 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer data)
165 {
166         gint mins_secs_tenths, delay;
167
168         mins_secs_tenths = c_options->slideshow.delay %
169                                                 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
170
171         delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
172                                                                 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
173                                                                 mins_secs_tenths);
174
175         c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
176                                                                                                         SLIDESHOW_SUBSECOND_PRECISION;
177 }
178
179 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer data)
180 {
181         gint hours, secs_tenths, delay;
182
183         hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
184         secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
185
186         delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
187                                         (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
188                                         (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
189
190         c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
191                                                                                                         SLIDESHOW_SUBSECOND_PRECISION;
192 }
193
194 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer data)
195 {
196         gint hours_mins, delay;
197
198         hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
199
200         delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
201                                                         (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
202                                                         (gdouble)(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
203
204         c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
205                                                                                                         SLIDESHOW_SUBSECOND_PRECISION;
206 }
207
208 /*
209  *-----------------------------------------------------------------------------
210  * sync program to config window routine (private)
211  *-----------------------------------------------------------------------------
212  */
213
214 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
215 {
216         const gchar *buf;
217
218         g_free(*option);
219         *option = NULL;
220         buf = gtk_entry_get_text(GTK_ENTRY(entry));
221         if (buf && strlen(buf) > 0)
222                 {
223                 if (func)
224                         *option = func(buf);
225                 else
226                         *option = g_strdup(buf);
227                 }
228 }
229
230
231 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
232 {
233         gchar *accel_path, *accel;
234
235         gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
236
237         if (accel_path && accel_path[0])
238                 {
239                 GtkAccelKey key;
240                 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
241                 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
242                 }
243
244         g_free(accel_path);
245         g_free(accel);
246
247         return FALSE;
248 }
249
250
251 static void config_window_apply(void)
252 {
253         gboolean refresh = FALSE;
254 #ifdef HAVE_LCMS2
255         int i = 0;
256 #endif
257
258         config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
259
260         if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
261         if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
262         if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
263         if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
264         if (options->file_sort.natural != c_options->file_sort.natural) refresh = TRUE;
265         if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
266         if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
267
268         options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
269         options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
270         options->file_ops.confirm_move_to_trash = c_options->file_ops.confirm_move_to_trash;
271         options->file_ops.use_system_trash = c_options->file_ops.use_system_trash;
272         options->file_ops.no_trash = c_options->file_ops.no_trash;
273         options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
274         options->tools_restore_state = c_options->tools_restore_state;
275         options->save_window_positions = c_options->save_window_positions;
276         options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
277         options->save_window_workspace = c_options->save_window_workspace;
278         options->save_dialog_window_positions = c_options->save_dialog_window_positions;
279         options->show_window_ids = c_options->show_window_ids;
280         options->image.scroll_reset_method = c_options->image.scroll_reset_method;
281         options->image.zoom_2pass = c_options->image.zoom_2pass;
282         options->image.fit_window_to_image = c_options->image.fit_window_to_image;
283         options->image.limit_window_size = c_options->image.limit_window_size;
284         options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
285         options->image.max_window_size = c_options->image.max_window_size;
286         options->image.limit_autofit_size = c_options->image.limit_autofit_size;
287         options->image.max_autofit_size = c_options->image.max_autofit_size;
288         options->image.max_enlargement_size = c_options->image.max_enlargement_size;
289         options->image.use_clutter_renderer = c_options->image.use_clutter_renderer;
290         options->image.tile_size = c_options->image.tile_size;
291         options->progressive_key_scrolling = c_options->progressive_key_scrolling;
292         options->keyboard_scroll_step = c_options->keyboard_scroll_step;
293
294         if (options->thumbnails.max_width != c_options->thumbnails.max_width
295             || options->thumbnails.max_height != c_options->thumbnails.max_height
296             || options->thumbnails.quality != c_options->thumbnails.quality)
297                 {
298                 thumb_format_changed = TRUE;
299                 refresh = TRUE;
300                 options->thumbnails.max_width = c_options->thumbnails.max_width;
301                 options->thumbnails.max_height = c_options->thumbnails.max_height;
302                 options->thumbnails.quality = c_options->thumbnails.quality;
303                 }
304         options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
305         options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
306         options->thumbnails.use_exif = c_options->thumbnails.use_exif;
307         options->thumbnails.use_color_management = c_options->thumbnails.use_color_management;
308         options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
309         options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
310 //      options->thumbnails.use_ft_metadata_small = c_options->thumbnails.use_ft_metadata_small;
311         options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
312         options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
313         options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
314         options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
315         options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
316         options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
317
318         options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
319         options->file_sort.natural = c_options->file_sort.natural;
320         options->file_filter.disable = c_options->file_filter.disable;
321
322         config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, NULL);
323         sidecar_ext_parse(options->sidecar.ext);
324
325         options->slideshow.random = c_options->slideshow.random;
326         options->slideshow.repeat = c_options->slideshow.repeat;
327         options->slideshow.delay = c_options->slideshow.delay;
328
329         options->mousewheel_scrolls = c_options->mousewheel_scrolls;
330         options->image_lm_click_nav = c_options->image_lm_click_nav;
331         options->image_l_click_archive = c_options->image_l_click_archive;
332         options->image_l_click_video = c_options->image_l_click_video;
333         options->image_l_click_video_editor = c_options->image_l_click_video_editor;
334
335         options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
336
337         options->image.tile_cache_max = c_options->image.tile_cache_max;
338         options->image.image_cache_max = c_options->image.image_cache_max;
339
340         options->image.zoom_quality = c_options->image.zoom_quality;
341
342         options->image.zoom_increment = c_options->image.zoom_increment;
343
344         options->image.zoom_style = c_options->image.zoom_style;
345
346         options->image.enable_read_ahead = c_options->image.enable_read_ahead;
347
348
349         if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
350             || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
351             || !gdk_color_equal(&options->image.border_color, &c_options->image.border_color))
352                 {
353                 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
354                 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
355                 options->image.border_color = c_options->image.border_color;
356                 layout_colors_update();
357                 view_window_colors_update();
358                 }
359
360         options->image.alpha_color_1 = c_options->image.alpha_color_1;
361         options->image.alpha_color_2 = c_options->image.alpha_color_2;
362
363         options->fullscreen.screen = c_options->fullscreen.screen;
364         options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
365         options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
366         options->fullscreen.above = c_options->fullscreen.above;
367         if (c_options->image_overlay.template_string)
368                 set_image_overlay_template_string(&options->image_overlay.template_string,
369                                                   c_options->image_overlay.template_string);
370         if (c_options->image_overlay.font)
371                 set_image_overlay_font_string(&options->image_overlay.font,
372                                                   c_options->image_overlay.font);
373         options->image_overlay.text_red = c_options->image_overlay.text_red;
374         options->image_overlay.text_green = c_options->image_overlay.text_green;
375         options->image_overlay.text_blue = c_options->image_overlay.text_blue;
376         options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
377         options->image_overlay.background_red = c_options->image_overlay.background_red;
378         options->image_overlay.background_green = c_options->image_overlay.background_green;
379         options->image_overlay.background_blue = c_options->image_overlay.background_blue;
380         options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
381         options->update_on_time_change = c_options->update_on_time_change;
382         options->image.exif_proof_rotate_enable = c_options->image.exif_proof_rotate_enable;
383
384         options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
385         options->rot_invariant_sim = c_options->rot_invariant_sim;
386
387         options->tree_descend_subdirs = c_options->tree_descend_subdirs;
388
389         options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
390         options->circular_selection_lists = c_options->circular_selection_lists;
391
392         options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
393         options->dnd_icon_size = c_options->dnd_icon_size;
394         options->clipboard_selection = c_options->clipboard_selection;
395         options->dnd_default_action = c_options->dnd_default_action;
396
397         options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
398         options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
399         options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
400         options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
401         options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
402         options->metadata.confirm_write = c_options->metadata.confirm_write;
403         options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
404         options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
405         options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
406         options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
407         options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
408         options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
409         options->metadata.write_orientation = c_options->metadata.write_orientation;
410         options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
411                                (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
412                                (c_options->stereo.tmp.flip_right   ? PR_STEREO_FLIP_RIGHT : 0) |
413                                (c_options->stereo.tmp.mirror_left  ? PR_STEREO_MIRROR_LEFT : 0) |
414                                (c_options->stereo.tmp.flip_left    ? PR_STEREO_FLIP_LEFT : 0) |
415                                (c_options->stereo.tmp.swap         ? PR_STEREO_SWAP : 0) |
416                                (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
417         options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
418                                (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
419                                (c_options->stereo.tmp.fs_flip_right   ? PR_STEREO_FLIP_RIGHT : 0) |
420                                (c_options->stereo.tmp.fs_mirror_left  ? PR_STEREO_MIRROR_LEFT : 0) |
421                                (c_options->stereo.tmp.fs_flip_left    ? PR_STEREO_FLIP_LEFT : 0) |
422                                (c_options->stereo.tmp.fs_swap         ? PR_STEREO_SWAP : 0) |
423                                (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
424         options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
425         options->stereo.fixed_w = c_options->stereo.fixed_w;
426         options->stereo.fixed_h = c_options->stereo.fixed_h;
427         options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
428         options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
429         options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
430         options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
431
432         options->info_keywords.height = c_options->info_keywords.height;
433         options->info_title.height = c_options->info_title.height;
434         options->info_comment.height = c_options->info_comment.height;
435         options->info_rating.height = c_options->info_rating.height;
436
437         options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
438         options->expand_menu_toolbar = c_options->expand_menu_toolbar;
439
440         options->marks_save = c_options->marks_save;
441         options->with_rename = c_options->with_rename;
442         options->collections_on_top = c_options->collections_on_top;
443         options->hide_window_in_fullscreen = c_options->hide_window_in_fullscreen;
444         config_entry_to_option(help_search_engine_entry, &options->help_search_engine, NULL);
445
446         options->external_preview.enable = c_options->external_preview.enable;
447         config_entry_to_option(external_preview_select_entry, &options->external_preview.select, NULL);
448         config_entry_to_option(external_preview_extract_entry, &options->external_preview.extract, NULL);
449
450         options->read_metadata_in_idle = c_options->read_metadata_in_idle;
451
452         options->star_rating.star = c_options->star_rating.star;
453         options->star_rating.rejected = c_options->star_rating.rejected;
454
455         options->threads.duplicates = c_options->threads.duplicates > 0 ? c_options->threads.duplicates : -1;
456
457 #ifdef DEBUG
458         set_debug_level(debug_c);
459 #endif
460
461 #ifdef HAVE_LCMS
462         for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
463                 {
464                 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
465                 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
466                 }
467         config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
468         options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
469         if (options->color_profile.render_intent != c_options->color_profile.render_intent)
470                 {
471                 options->color_profile.render_intent = c_options->color_profile.render_intent;
472                 color_man_update();
473                 }
474 #endif
475
476         options->mouse_button_8 = c_options->mouse_button_8;
477         options->mouse_button_9 = c_options->mouse_button_9;
478
479         options->override_disable_gpu = c_options->override_disable_gpu;
480
481         config_tab_keywords_save();
482
483         image_options_sync();
484
485         if (refresh)
486                 {
487                 filter_rebuild();
488                 layout_refresh(NULL);
489                 }
490
491         if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, NULL);
492
493         toolbar_apply(TOOLBAR_MAIN);
494         toolbar_apply(TOOLBAR_STATUS);
495 }
496
497 /*
498  *-----------------------------------------------------------------------------
499  * config window main button callbacks (private)
500  *-----------------------------------------------------------------------------
501  */
502
503 static void config_window_close_cb(GtkWidget *widget, gpointer data)
504 {
505         gtk_widget_destroy(configwindow);
506         configwindow = NULL;
507         filter_store = NULL;
508 }
509
510 static void config_window_help_cb(GtkWidget *widget, gpointer data)
511 {
512         GtkWidget *notebook = data;
513         gint i;
514
515         static gchar *html_section[] =
516         {
517         "GuideOptionsGeneral.html",
518         "GuideOptionsImage.html",
519         "GuideOptionsOSD.html",
520         "GuideOptionsWindow.html",
521         "GuideOptionsKeyboard.html",
522         "GuideOptionsFiltering.html",
523         "GuideOptionsMetadata.html",
524         "GuideOptionsKeywords.html",
525         "GuideOptionsColor.html",
526         "GuideOptionsStereo.html",
527         "GuideOptionsBehavior.html",
528         "GuideOptionsToolbar.html",
529         "GuideOptionsToolbar.html",
530         "GuideOptionsAdvanced.html"
531         };
532
533         i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
534         help_window_show(html_section[i]);
535 }
536
537 static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpointer data)
538 {
539         config_window_close_cb(NULL, NULL);
540         return TRUE;
541 }
542
543 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
544 {
545         LayoutWindow *lw;
546         GtkNotebook *notebook = data;
547         GdkWindow *window;
548         gint x;
549         gint y;
550         gint w;
551         gint h;
552         gint page_number;
553
554         lw = layout_window_list->data;
555
556         window = gtk_widget_get_window(widget);
557         gdk_window_get_root_origin(window, &x, &y);
558         w = gdk_window_get_width(window);
559         h = gdk_window_get_height(window);
560         page_number = gtk_notebook_get_current_page(notebook);
561
562         lw->options.preferences_window.x = x;
563         lw->options.preferences_window.y = y;
564         lw->options.preferences_window.w = w;
565         lw->options.preferences_window.h = h;
566         lw->options.preferences_window.page_number = page_number;
567
568         config_window_apply();
569         layout_util_sync(lw);
570         save_options(options);
571         config_window_close_cb(NULL, NULL);
572 }
573
574 /*
575  *-----------------------------------------------------------------------------
576  * config window setup (private)
577  *-----------------------------------------------------------------------------
578  */
579
580 static void quality_menu_cb(GtkWidget *combo, gpointer data)
581 {
582         gint *option = data;
583
584         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
585                 {
586                 case 0:
587                 default:
588                         *option = GDK_INTERP_NEAREST;
589                         break;
590                 case 1:
591                         *option = GDK_INTERP_TILES;
592                         break;
593                 case 2:
594                         *option = GDK_INTERP_BILINEAR;
595                         break;
596                 }
597 }
598
599 static void dnd_default_action_selection_menu_cb(GtkWidget *combo, gpointer data)
600 {
601         gint *option = data;
602
603         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
604                 {
605                 case 0:
606                 default:
607                         *option = DND_ACTION_ASK;
608                         break;
609                 case 1:
610                         *option = DND_ACTION_COPY;
611                         break;
612                 case 2:
613                         *option = DND_ACTION_MOVE;
614                         break;
615                 }
616 }
617 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
618 {
619         gint *option = data;
620
621         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
622                 {
623                 case 0:
624                         *option = CLIPBOARD_PRIMARY;
625                         break;
626                 case 1:
627                         *option = CLIPBOARD_CLIPBOARD;
628                         break;
629                 case 2:
630                         *option = CLIPBOARD_BOTH;
631                         break;
632                 default:
633                         *option = CLIPBOARD_BOTH;
634                 }
635 }
636
637 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
638                              guint option, guint *option_c)
639 {
640         GtkWidget *combo;
641         gint current = 0;
642
643         *option_c = option;
644
645         pref_table_label(table, column, row, text, 0.0);
646
647         combo = gtk_combo_box_text_new();
648
649         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
650         if (option == GDK_INTERP_NEAREST) current = 0;
651         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
652         if (option == GDK_INTERP_TILES) current = 1;
653         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear (best, but slowest)"));
654         if (option == GDK_INTERP_BILINEAR) current = 2;
655
656         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
657
658         g_signal_connect(G_OBJECT(combo), "changed",
659                          G_CALLBACK(quality_menu_cb), option_c);
660
661         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
662         gtk_widget_show(combo);
663 }
664
665 static void add_dnd_default_action_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, DnDAction option, DnDAction *option_c)
666 {
667         GtkWidget *combo;
668         gint current = 0;
669
670         *option_c = option;
671
672         pref_table_label(table, column, row, text, 0.0);
673
674         combo = gtk_combo_box_text_new();
675
676         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Ask"));
677         if (option == DND_ACTION_ASK) current = 0;
678         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Copy"));
679         if (option == DND_ACTION_COPY) current = 1;
680         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Move"));
681         if (option == DND_ACTION_MOVE) current = 2;
682
683         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
684
685         g_signal_connect(G_OBJECT(combo), "changed",
686                          G_CALLBACK(dnd_default_action_selection_menu_cb), option_c);
687
688         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
689         gtk_widget_show(combo);
690 }
691
692 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
693                              gint option, gint *option_c)
694 {
695         GtkWidget *combo;
696         gint current = 0;
697
698         *option_c = option;
699
700         pref_table_label(table, column, row, text, 0.0);
701
702         combo = gtk_combo_box_text_new();
703
704         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Primary"));
705         if (option == CLIPBOARD_PRIMARY) current = 0;
706         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Clipboard"));
707         if (option == CLIPBOARD_CLIPBOARD) current = 1;
708         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Both"));
709         if (option == CLIPBOARD_BOTH) current = 2;
710
711         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
712
713         g_signal_connect(G_OBJECT(combo), "changed",
714                          G_CALLBACK(clipboard_selection_menu_cb), option_c);
715
716         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
717         gtk_widget_show(combo);
718 }
719
720 static void zoom_style_selection_menu_cb(GtkWidget *combo, gpointer data)
721 {
722         gint *option = data;
723
724         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
725                 {
726                 case 0:
727                         *option = ZOOM_GEOMETRIC;
728                         break;
729                 case 1:
730                         *option = ZOOM_ARITHMETIC;
731                         break;
732                 default:
733                         *option = ZOOM_GEOMETRIC;
734                 }
735 }
736
737 static void add_zoom_style_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, ZoomStyle option, ZoomStyle *option_c)
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), _("Geometric"));
749         if (option == ZOOM_GEOMETRIC) current = 0;
750         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Arithmetic"));
751         if (option == ZOOM_ARITHMETIC) current = 1;
752
753         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
754
755         g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(zoom_style_selection_menu_cb), option_c);
756
757         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
758         gtk_widget_show(combo);
759 }
760
761 typedef struct _UseableMouseItems UseableMouseItems;
762 struct _UseableMouseItems
763 {
764         gchar *name; /* GtkActionEntry terminology */
765         gchar *label;
766         gchar *stock_id;
767 };
768
769 static const UseableMouseItems useable_mouse_items[] = {
770         {"", "", NULL},
771         {"FirstImage",  N_("First Image"), GTK_STOCK_GOTO_TOP},
772         {"PrevImage",   N_("Previous Image"), GTK_STOCK_GO_UP},
773         {"NextImage",   N_("Next Image"), GTK_STOCK_GO_DOWN},
774         {"LastImage",   N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
775         {"Back",        N_("Back"), GTK_STOCK_GO_BACK},
776         {"Forward",     N_("Forward"), GTK_STOCK_GO_FORWARD},
777         {"Home",        N_("Home"), GTK_STOCK_HOME},
778         {"Up",  N_("Up"), GTK_STOCK_GO_UP},
779         {"FirstPage",   N_("First page"), GTK_STOCK_MEDIA_PREVIOUS},
780         {"LastPage",    N_("Last Page"), GTK_STOCK_MEDIA_NEXT},
781         {"NextPage",    N_("Next page"), GTK_STOCK_MEDIA_FORWARD},
782         {"PrevPage",    N_("Previous Page"), GTK_STOCK_MEDIA_REWIND},
783         {"NewWindow",   N_("New _window"), GTK_STOCK_NEW},
784         {"NewCollection",       N_("New collection"), GTK_STOCK_INDEX},
785         {"OpenCollection",      N_("Open collection"), GTK_STOCK_OPEN},
786         {"Search",      N_("Search"), GTK_STOCK_FIND},
787         {"FindDupes",   N_("Find duplicates"), GTK_STOCK_FIND},
788         {"NewFolder",   N_("New folder"),GTK_STOCK_DIRECTORY},
789         {"Copy",        N_("Copy"), GTK_STOCK_COPY},
790         {"Move",        N_("Move"), PIXBUF_INLINE_ICON_MOVE},
791         {"Rename",      N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
792         {"Delete",      N_("Delete"), GTK_STOCK_DELETE},
793         {"CloseWindow", N_("Close Window"), GTK_STOCK_CLOSE},
794         {"PanView",     N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
795         {"SelectAll",   N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
796         {"SelectNone",  N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
797         {"SelectInvert",        N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
798         {"ShowFileFilter",      N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
799         {"RectangularSelection",        N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
800         {"Print",       N_("Print"), GTK_STOCK_PRINT},
801         {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
802         {"LayoutConfig",        N_("Configure this window"), GTK_STOCK_PREFERENCES},
803         {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
804         {"RotateCW",    N_("Rotate clockwise 90°"), PIXBUF_INLINE_ICON_CW},
805         {"RotateCCW",   N_("Rotate counterclockwise 90°"), PIXBUF_INLINE_ICON_CCW},
806         {"Rotate180",   N_("Rotate 180°"), PIXBUF_INLINE_ICON_180},
807         {"Mirror",      N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
808         {"Flip",        N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
809         {"AlterNone",   N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
810         {"ZoomIn",      N_("Zoom in"), GTK_STOCK_ZOOM_IN},
811         {"ZoomOut",     N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
812         {"Zoom100",     N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
813         {"ZoomFit",     N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
814         {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
815         {"ZoomFillVert",        N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
816         {"Zoom200",     N_("Zoom 2:1"), GTK_STOCK_FILE},
817         {"Zoom300",     N_("Zoom 3:1"), GTK_STOCK_FILE},
818         {"Zoom400",     N_("Zoom 4:1"), GTK_STOCK_FILE},
819         {"Zoom50",      N_("Zoom 1:2"), GTK_STOCK_FILE},
820         {"Zoom33",      N_("Zoom1:3"), GTK_STOCK_FILE},
821         {"Zoom25",      N_("Zoom 1:4"), GTK_STOCK_FILE},
822         {"ConnectZoomIn",       N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
823         {"SplitPaneSync",       N_("Split Pane Sync"), PIXBUF_INLINE_SPLIT_PANE_SYNC},
824         {"Grayscale",   N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
825         {"OverUnderExposed",    N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
826         {"HideTools",   N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
827         {"SlideShowPause",      N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
828         {"SlideShowFaster",     N_("Slideshow Faster"), GTK_STOCK_FILE},
829         {"SlideShowSlower",     N_("Slideshow Slower"), GTK_STOCK_FILE},
830         {"Refresh",     N_("Refresh"), GTK_STOCK_REFRESH},
831         {"HelpContents",        N_("Help"), GTK_STOCK_HELP},
832         {"ExifWin",     N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
833         {"Thumbnails",  N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
834         {"ShowMarks",   N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
835         {"DrawRectangle",       N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
836         {"FloatTools",  N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
837         {"SBar",        N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
838         {"SBarSort",    N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
839         {"Quit",        N_("Quit"), GTK_STOCK_QUIT},
840         {NULL,          NULL, NULL}
841 };
842
843 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
844 {
845         gchar **option = data;
846         gchar *label;
847
848         label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
849
850         const UseableMouseItems *list = useable_mouse_items;
851
852         while (list->name)
853                 {
854                 if (g_strcmp0(list->label, label) == 0)
855                         {
856                         break;
857                         }
858                 list++;
859                 }
860
861         g_free(*option);
862         *option = g_strdup(list->name);
863         g_free(label);
864 }
865
866 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
867                              gchar *option, gchar **option_c)
868 {
869         GtkWidget *combo;
870         gint current = 0;
871         gint i = 0;
872
873         *option_c = option;
874
875         pref_table_label(table, column, row, text, 0.0);
876
877         combo = gtk_combo_box_text_new();
878
879         const UseableMouseItems *list = useable_mouse_items;
880
881         while (list->name)
882                 {
883                 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
884                 if (g_strcmp0(list->name, option) == 0)
885                         {
886                         current = i;
887                         }
888                 i++;
889                 list++;
890                 }
891
892         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
893
894         g_signal_connect(G_OBJECT(combo), "changed",
895                          G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
896
897         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
898         gtk_widget_show(combo);
899 }
900
901 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
902 {
903         gint n;
904
905         n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
906         if (n < 0) return;
907
908         if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
909                 {
910                 c_options->thumbnails.max_width = thumb_size_list[n].w;
911                 c_options->thumbnails.max_height = thumb_size_list[n].h;
912                 }
913         else
914                 {
915                 c_options->thumbnails.max_width = options->thumbnails.max_width;
916                 c_options->thumbnails.max_height = options->thumbnails.max_height;
917                 }
918 }
919
920 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
921 {
922         GtkWidget *combo;
923         gint current;
924         gint i;
925
926         c_options->thumbnails.max_width = options->thumbnails.max_width;
927         c_options->thumbnails.max_height = options->thumbnails.max_height;
928
929         pref_table_label(table, column, row, text, 0.0);
930
931         combo = gtk_combo_box_text_new();
932
933         current = -1;
934         for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
935                 {
936                 gint w, h;
937                 gchar *buf;
938
939                 w = thumb_size_list[i].w;
940                 h = thumb_size_list[i].h;
941
942                 buf = g_strdup_printf("%d x %d", w, h);
943                 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
944                 g_free(buf);
945
946                 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
947                 }
948
949         if (current == -1)
950                 {
951                 gchar *buf;
952
953                 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
954                 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
955                 g_free(buf);
956
957                 current = i;
958                 }
959
960         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
961         g_signal_connect(G_OBJECT(combo), "changed",
962                          G_CALLBACK(thumb_size_menu_cb), NULL);
963
964         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
965         gtk_widget_show(combo);
966 }
967
968 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
969 {
970         gint *option = data;
971
972         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
973                 {
974                 case 0:
975                 default:
976                         *option = PR_STEREO_NONE;
977                         break;
978                 case 1:
979                         *option = PR_STEREO_ANAGLYPH_RC;
980                         break;
981                 case 2:
982                         *option = PR_STEREO_ANAGLYPH_GM;
983                         break;
984                 case 3:
985                         *option = PR_STEREO_ANAGLYPH_YB;
986                         break;
987                 case 4:
988                         *option = PR_STEREO_ANAGLYPH_GRAY_RC;
989                         break;
990                 case 5:
991                         *option = PR_STEREO_ANAGLYPH_GRAY_GM;
992                         break;
993                 case 6:
994                         *option = PR_STEREO_ANAGLYPH_GRAY_YB;
995                         break;
996                 case 7:
997                         *option = PR_STEREO_ANAGLYPH_DB_RC;
998                         break;
999                 case 8:
1000                         *option = PR_STEREO_ANAGLYPH_DB_GM;
1001                         break;
1002                 case 9:
1003                         *option = PR_STEREO_ANAGLYPH_DB_YB;
1004                         break;
1005                 case 10:
1006                         *option = PR_STEREO_HORIZ;
1007                         break;
1008                 case 11:
1009                         *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
1010                         break;
1011                 case 12:
1012                         *option = PR_STEREO_VERT;
1013                         break;
1014                 case 13:
1015                         *option = PR_STEREO_VERT | PR_STEREO_HALF;
1016                         break;
1017                 case 14:
1018                         *option = PR_STEREO_FIXED;
1019                         break;
1020                 }
1021 }
1022
1023 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1024                              gint option, gint *option_c, gboolean add_fixed)
1025 {
1026         GtkWidget *combo;
1027         gint current = 0;
1028
1029         *option_c = option;
1030
1031         pref_table_label(table, column, row, text, 0.0);
1032
1033         combo = gtk_combo_box_text_new();
1034
1035         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
1036
1037         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
1038         if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
1039         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
1040         if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
1041         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
1042         if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
1043         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
1044         if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
1045         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
1046         if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
1047         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
1048         if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
1049         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
1050         if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
1051         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
1052         if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
1053         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
1054         if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
1055
1056         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
1057         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
1058         if (option & PR_STEREO_HORIZ)
1059                 {
1060                 current = 10;
1061                 if (option & PR_STEREO_HALF) current = 11;
1062                 }
1063
1064         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
1065         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
1066         if (option & PR_STEREO_VERT)
1067                 {
1068                 current = 12;
1069                 if (option & PR_STEREO_HALF) current = 13;
1070                 }
1071
1072         if (add_fixed)
1073                 {
1074                 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
1075                 if (option & PR_STEREO_FIXED) current = 14;
1076                 }
1077
1078         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1079
1080         g_signal_connect(G_OBJECT(combo), "changed",
1081                          G_CALLBACK(stereo_mode_menu_cb), option_c);
1082
1083         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1084         gtk_widget_show(combo);
1085 }
1086
1087 static void video_menu_cb(GtkWidget *combo, gpointer data)
1088 {
1089         gchar **option = data;
1090
1091         EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
1092         *option = ed->key;
1093 }
1094
1095 static void video_menu_populate(gpointer data, gpointer user_data)
1096 {
1097         GtkWidget *combo = user_data;
1098         EditorDescription *ed = data;
1099
1100         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1101 }
1102
1103 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1104                              gchar *option, gchar **option_c)
1105 {
1106         GtkWidget *combo;
1107         gint current;
1108 /* use lists since they are sorted */
1109         GList *eds = editor_list_get();
1110
1111         *option_c = option;
1112
1113         pref_table_label(table, column, row, text, 0.0);
1114
1115         combo = gtk_combo_box_text_new();
1116         g_list_foreach(eds,video_menu_populate,(gpointer)combo);
1117         current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1118
1119         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1120
1121         g_signal_connect(G_OBJECT(combo), "changed",
1122                          G_CALLBACK(video_menu_cb), option_c);
1123
1124         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1125         gtk_widget_show(combo);
1126 }
1127
1128 static void filter_store_populate(void)
1129 {
1130         GList *work;
1131
1132         if (!filter_store) return;
1133
1134         gtk_list_store_clear(filter_store);
1135
1136         work = filter_get_list();
1137         while (work)
1138                 {
1139                 FilterEntry *fe;
1140                 GtkTreeIter iter;
1141
1142                 fe = work->data;
1143                 work = work->next;
1144
1145                 gtk_list_store_append(filter_store, &iter);
1146                 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1147                 }
1148 }
1149
1150 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1151                                      gchar *new_text, gpointer data)
1152 {
1153         GtkWidget *model = data;
1154         FilterEntry *fe = data;
1155         GtkTreePath *tpath;
1156         GtkTreeIter iter;
1157
1158         if (!new_text || strlen(new_text) < 1) return;
1159
1160         tpath = gtk_tree_path_new_from_string(path_str);
1161         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1162         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1163
1164         g_free(fe->extensions);
1165         fe->extensions = g_strdup(new_text);
1166
1167         gtk_tree_path_free(tpath);
1168         filter_rebuild();
1169 }
1170
1171 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1172                                        gchar *new_text, gpointer data)
1173 {
1174         GtkWidget *model = data;
1175         FilterEntry *fe = data;
1176         GtkTreePath *tpath;
1177         GtkTreeIter iter;
1178         gint i;
1179
1180         if (!new_text || !new_text[0]) return;
1181
1182         tpath = gtk_tree_path_new_from_string(path_str);
1183         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1184         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1185
1186         for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1187                 {
1188                 if (strcmp(new_text, _(format_class_list[i])) == 0)
1189                         {
1190                         fe->file_class = i;
1191                         break;
1192                         }
1193                 }
1194
1195         gtk_tree_path_free(tpath);
1196         filter_rebuild();
1197 }
1198
1199 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1200                                       gchar *new_text, gpointer data)
1201 {
1202         GtkWidget *model = data;
1203         FilterEntry *fe;
1204         GtkTreePath *tpath;
1205         GtkTreeIter iter;
1206
1207         if (!new_text || !new_text[0]) return;
1208
1209         tpath = gtk_tree_path_new_from_string(path_str);
1210         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1211         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1212
1213         g_free(fe->description);
1214         fe->description = g_strdup(new_text);
1215
1216         gtk_tree_path_free(tpath);
1217 }
1218
1219 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
1220                                    gchar *path_str, gpointer data)
1221 {
1222         GtkWidget *model = data;
1223         FilterEntry *fe;
1224         GtkTreePath *tpath;
1225         GtkTreeIter iter;
1226
1227         tpath = gtk_tree_path_new_from_string(path_str);
1228         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1229         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1230
1231         fe->enabled = !fe->enabled;
1232
1233         gtk_tree_path_free(tpath);
1234         filter_rebuild();
1235 }
1236
1237 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
1238                                      gchar *path_str, gpointer data)
1239 {
1240         GtkWidget *model = data;
1241         FilterEntry *fe;
1242         GtkTreePath *tpath;
1243         GtkTreeIter iter;
1244
1245         tpath = gtk_tree_path_new_from_string(path_str);
1246         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1247         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1248
1249         fe->writable = !fe->writable;
1250         if (fe->writable) fe->allow_sidecar = FALSE;
1251
1252         gtk_tree_path_free(tpath);
1253         filter_rebuild();
1254 }
1255
1256 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
1257                                     gchar *path_str, gpointer data)
1258 {
1259         GtkWidget *model = data;
1260         FilterEntry *fe;
1261         GtkTreePath *tpath;
1262         GtkTreeIter iter;
1263
1264         tpath = gtk_tree_path_new_from_string(path_str);
1265         gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1266         gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1267
1268         fe->allow_sidecar = !fe->allow_sidecar;
1269         if (fe->allow_sidecar) fe->writable = FALSE;
1270
1271         gtk_tree_path_free(tpath);
1272         filter_rebuild();
1273 }
1274
1275 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1276                             GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1277 {
1278         FilterEntry *fe;
1279
1280         gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1281
1282         switch (GPOINTER_TO_INT(data))
1283                 {
1284                 case FE_ENABLE:
1285                         g_object_set(GTK_CELL_RENDERER(cell),
1286                                      "active", fe->enabled, NULL);
1287                         break;
1288                 case FE_EXTENSION:
1289                         g_object_set(GTK_CELL_RENDERER(cell),
1290                                      "text", fe->extensions, NULL);
1291                         break;
1292                 case FE_DESCRIPTION:
1293                         g_object_set(GTK_CELL_RENDERER(cell),
1294                                      "text", fe->description, NULL);
1295                         break;
1296                 case FE_CLASS:
1297                         g_object_set(GTK_CELL_RENDERER(cell),
1298                                      "text", _(format_class_list[fe->file_class]), NULL);
1299                         break;
1300                 case FE_WRITABLE:
1301                         g_object_set(GTK_CELL_RENDERER(cell),
1302                                      "active", fe->writable, NULL);
1303                         break;
1304                 case FE_ALLOW_SIDECAR:
1305                         g_object_set(GTK_CELL_RENDERER(cell),
1306                                      "active", fe->allow_sidecar, NULL);
1307                         break;
1308                 }
1309 }
1310
1311 static gboolean filter_add_scroll(gpointer data)
1312 {
1313         GtkTreePath *path;
1314         GList *list_cells;
1315         GtkCellRenderer *cell;
1316         GtkTreeViewColumn *column;
1317         gint rows;
1318
1319         rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1320         path = gtk_tree_path_new_from_indices(rows-1, -1);
1321
1322         column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1323
1324         list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1325         cell = g_list_last(list_cells)->data;
1326
1327         gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1328                                                                 path, column, FALSE, 0.0, 0.0 );
1329         gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1330                                                                 path, column, cell, TRUE);
1331
1332         gtk_tree_path_free(path);
1333         g_list_free(list_cells);
1334
1335         return(FALSE);
1336 }
1337
1338 static void filter_add_cb(GtkWidget *widget, gpointer data)
1339 {
1340         filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1341         filter_store_populate();
1342
1343         g_idle_add((GSourceFunc)filter_add_scroll, data);
1344 }
1345
1346 static void filter_remove_cb(GtkWidget *widget, gpointer data)
1347 {
1348         GtkWidget *filter_view = data;
1349         GtkTreeSelection *selection;
1350         GtkTreeIter iter;
1351         FilterEntry *fe;
1352
1353         if (!filter_store) return;
1354         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1355         if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1356         gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1357         if (!fe) return;
1358
1359         filter_remove_entry(fe);
1360         filter_rebuild();
1361         filter_store_populate();
1362 }
1363
1364 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1365 {
1366         GtkTreeIter iter;
1367         GtkTreePath *path;
1368         GtkTreeViewColumn *column;
1369
1370         gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1371         path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1372         column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1373
1374         gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1375                                      path, column,
1376                                      FALSE, 0.0, 0.0);
1377
1378         gtk_tree_path_free(path);
1379
1380         return(FALSE);
1381 }
1382
1383 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
1384 {
1385         filter_reset();
1386         filter_add_defaults();
1387         filter_rebuild();
1388         filter_store_populate();
1389
1390         g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1391 }
1392
1393 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1394 {
1395         /* no op, only so cancel button appears */
1396 }
1397
1398 static void filter_default_cb(GtkWidget *widget, gpointer data)
1399 {
1400         GenericDialog *gd;
1401
1402         gd = generic_dialog_new(_("Reset filters"),
1403                                 "reset_filter", widget, TRUE,
1404                                 dummy_cancel_cb, data);
1405         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1406                                    _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1407         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1408         gtk_widget_show(gd->dialog);
1409 }
1410
1411 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1412 {
1413         GtkWidget *frame = data;
1414
1415         gtk_widget_set_sensitive(frame,
1416                                  !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1417 }
1418
1419 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
1420 {
1421         layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1422 }
1423
1424 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
1425 {
1426         file_util_trash_clear();
1427 }
1428
1429 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
1430 {
1431         GenericDialog *gd;
1432         GtkWidget *entry;
1433         gd = generic_dialog_new(_("Clear trash"),
1434                                 "clear_trash", widget, TRUE,
1435                                 dummy_cancel_cb, NULL);
1436         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1437                                     _("This will remove the trash contents."), FALSE);
1438         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1439         entry = gtk_entry_new();
1440         gtk_widget_set_can_focus(entry, FALSE);
1441         gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1442         if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1443         gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1444         gtk_widget_show(entry);
1445         gtk_widget_show(gd->dialog);
1446 }
1447
1448 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
1449 {
1450         GtkWidget *pTextView;
1451         GtkTextBuffer *pTextBuffer;
1452         GtkTextIter iStart;
1453         GtkTextIter iEnd;
1454
1455         pTextView = GTK_WIDGET(data);
1456
1457         pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1458         gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1459         gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1460
1461         set_image_overlay_template_string(&c_options->image_overlay.template_string,
1462                                           gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1463 }
1464
1465 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
1466 {
1467         GtkTextView *text_view = data;
1468         GtkTextBuffer *buffer;
1469
1470         set_default_image_overlay_template_string(&options->image_overlay.template_string);
1471         if (!configwindow) return;
1472
1473         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1474         gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1475 }
1476
1477 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1478 {
1479         GenericDialog *gd;
1480
1481         gd = generic_dialog_new(_("Reset image overlay template string"),
1482                                 "reset_image_overlay_template_string", widget, TRUE,
1483                                 dummy_cancel_cb, data);
1484         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1485                                    _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1486         generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1487         gtk_widget_show(gd->dialog);
1488 }
1489
1490 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
1491 {
1492         help_window_show("GuideOptionsOSD.html");
1493 }
1494
1495 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer data)
1496 {
1497 #if GTK_CHECK_VERSION(3,4,0)
1498         GtkWidget *dialog;
1499         char *font;
1500         PangoFontDescription *font_desc;
1501
1502         dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1503         gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1504
1505         if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1506                 {
1507                 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1508                 font = pango_font_description_to_string(font_desc);
1509                 g_free(c_options->image_overlay.font);
1510                 c_options->image_overlay.font = g_strdup(font);
1511                 g_free(font);
1512                 }
1513
1514         gtk_widget_destroy(dialog);
1515 #else
1516         const char *font;
1517
1518         font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
1519         c_options->image_overlay.font = g_strdup(font);
1520 #endif
1521 }
1522
1523 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer data)
1524 {
1525         GtkWidget *dialog;
1526 #if GTK_CHECK_VERSION(3,4,0)
1527         GdkRGBA colour;
1528
1529         dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1530         colour.red = options->image_overlay.text_red;
1531         colour.green = options->image_overlay.text_green;
1532         colour.blue = options->image_overlay.text_blue;
1533         colour.alpha = options->image_overlay.text_alpha;
1534         gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1535         gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1536
1537         if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1538                 {
1539                 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1540                 c_options->image_overlay.text_red = colour.red*255;
1541                 c_options->image_overlay.text_green = colour.green*255;
1542                 c_options->image_overlay.text_blue = colour.blue*255;
1543                 c_options->image_overlay.text_alpha = colour.alpha*255;
1544                 }
1545         gtk_widget_destroy(dialog);
1546 #else
1547         GdkColor colour;
1548         GtkColorSelection *colorsel;
1549
1550         dialog = gtk_color_selection_dialog_new("Image Overlay Text Colour");
1551         gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1552         colour.red = options->image_overlay.text_red*257;
1553         colour.green = options->image_overlay.text_green*257;
1554         colour.blue = options->image_overlay.text_blue*257;
1555         colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1556         gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1557         gtk_color_selection_set_current_color(colorsel, &colour);
1558         gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.text_alpha*257);
1559
1560         if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1561                 {
1562                 gtk_color_selection_get_current_color(colorsel, &colour);
1563                 c_options->image_overlay.text_red = colour.red/257;
1564                 c_options->image_overlay.text_green = colour.green/257;
1565                 c_options->image_overlay.text_blue = colour.blue/257;
1566                 c_options->image_overlay.text_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1567                 }
1568         gtk_widget_destroy (dialog);
1569 #endif
1570 }
1571
1572
1573 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer data)
1574 {
1575         GtkWidget *dialog;
1576 #if GTK_CHECK_VERSION(3,4,0)
1577         GdkRGBA colour;
1578
1579         dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1580         colour.red = options->image_overlay.background_red;
1581         colour.green = options->image_overlay.background_green;
1582         colour.blue = options->image_overlay.background_blue;
1583         colour.alpha = options->image_overlay.background_alpha;
1584         gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1585         gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1586
1587         if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1588                 {
1589                 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1590                 c_options->image_overlay.background_red = colour.red*255;
1591                 c_options->image_overlay.background_green = colour.green*255;
1592                 c_options->image_overlay.background_blue = colour.blue*255;
1593                 c_options->image_overlay.background_alpha = colour.alpha*255;
1594                 }
1595         gtk_widget_destroy(dialog);
1596 #else
1597         GdkColor colour;
1598         GtkColorSelection *colorsel;
1599
1600         dialog = gtk_color_selection_dialog_new("Image Overlay Background Colour");
1601         gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1602         colour.red = options->image_overlay.background_red*257;
1603         colour.green = options->image_overlay.background_green*257;
1604         colour.blue = options->image_overlay.background_blue*257;
1605         colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1606         gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1607         gtk_color_selection_set_current_color(colorsel, &colour);
1608         gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.background_alpha*257);
1609
1610         if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1611                 {
1612                 gtk_color_selection_get_current_color(colorsel, &colour);
1613                 c_options->image_overlay.background_red = colour.red/257;
1614                 c_options->image_overlay.background_green = colour.green/257;
1615                 c_options->image_overlay.background_blue = colour.blue/257;
1616                 c_options->image_overlay.background_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1617                 }
1618         gtk_widget_destroy(dialog);
1619 #endif
1620 }
1621
1622 static void accel_store_populate(void)
1623 {
1624         LayoutWindow *lw;
1625         GList *groups, *actions;
1626         GtkAction *action;
1627         const gchar *accel_path;
1628         GtkAccelKey key;
1629         GtkTreeIter iter;
1630
1631         if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1632
1633         gtk_tree_store_clear(accel_store);
1634         lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
1635
1636         g_assert(lw && lw->ui_manager);
1637         groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1638         while (groups)
1639                 {
1640                 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1641                 while (actions)
1642                         {
1643                         action = GTK_ACTION(actions->data);
1644                         accel_path = gtk_action_get_accel_path(action);
1645                         if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1646                                 {
1647                                 gchar *label, *label2, *tooltip, *accel;
1648                                 g_object_get(action,
1649                                              "tooltip", &tooltip,
1650                                              "label", &label,
1651                                              NULL);
1652
1653                                 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1654                                         {
1655                                         g_free(label);
1656                                         label = label2;
1657                                         }
1658
1659                                 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1660
1661                                 if (tooltip)
1662                                         {
1663                                         gtk_tree_store_append(accel_store, &iter, NULL);
1664                                         gtk_tree_store_set(accel_store, &iter,
1665                                                            AE_ACTION, label,
1666                                                            AE_KEY, accel,
1667                                                            AE_TOOLTIP, tooltip ? tooltip : "",
1668                                                            AE_ACCEL, accel_path,
1669                                                            -1);
1670                                         }
1671
1672                                 g_free(accel);
1673                                 g_free(label);
1674                                 g_free(tooltip);
1675                                 }
1676                         actions = actions->next;
1677                         }
1678
1679                 groups = groups->next;
1680                 }
1681 }
1682
1683 static void accel_store_cleared_cb(GtkCellRendererAccel *accel, gchar *path_string, gpointer user_data)
1684 {
1685
1686 }
1687
1688 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1689 {
1690         gchar *accel1 = data;
1691         gchar *accel2;
1692         GtkAccelKey key1;
1693         GtkAccelKey key2;
1694
1695         gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1696
1697         gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1698         gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1699
1700         if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1701                 {
1702                 gtk_tree_store_set(accel_store, iter, AE_KEY, "",  -1);
1703                 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1704                 }
1705
1706         g_free(accel2);
1707
1708         return FALSE;
1709 }
1710
1711
1712 static void accel_store_edited_cb(GtkCellRendererAccel *accel, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode, gpointer user_data)
1713 {
1714         GtkTreeModel *model = (GtkTreeModel *)accel_store;
1715         GtkTreeIter iter;
1716         gchar *acc;
1717         gchar *accel_path;
1718         GtkAccelKey old_key, key;
1719         GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1720
1721         gtk_tree_model_get_iter(model, &iter, path);
1722         gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1723
1724         /* test if the accelerator can be stored without conflicts*/
1725         gtk_accel_map_lookup_entry(accel_path, &old_key);
1726
1727         /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1728         gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1729         gtk_accel_map_lookup_entry(accel_path, &key);
1730
1731         /* restore the original for now, the key will be really changed when the changes are confirmed */
1732         gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1733
1734         acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1735         gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1736
1737         gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1738         gtk_tree_path_free(path);
1739         g_free(acc);
1740 }
1741
1742 static gboolean accel_default_scroll(GtkTreeView *data)
1743 {
1744         GtkTreeIter iter;
1745         GtkTreePath *path;
1746         GtkTreeViewColumn *column;
1747
1748         gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1749         path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1750         column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1751
1752         gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1753                                      path, column,
1754                                      FALSE, 0.0, 0.0);
1755
1756         gtk_tree_path_free(path);
1757
1758         return(FALSE);
1759 }
1760
1761 static void accel_default_cb(GtkWidget *widget, gpointer data)
1762 {
1763         accel_store_populate();
1764
1765         g_idle_add((GSourceFunc)accel_default_scroll, data);
1766 }
1767
1768 void accel_remove_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1769 {
1770         gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1771 }
1772
1773 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1774 {
1775         GtkAccelKey key;
1776         gchar *accel_path, *accel;
1777
1778         gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1779         gtk_accel_map_lookup_entry(accel_path, &key);
1780         accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1781
1782         gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1783
1784         gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1785         g_free(accel_path);
1786         g_free(accel);
1787 }
1788
1789 static void accel_reset_cb(GtkWidget *widget, gpointer data)
1790 {
1791         GtkTreeSelection *selection;
1792
1793         if (!accel_store) return;
1794         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1795         gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1796 }
1797
1798
1799
1800 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1801 {
1802         GtkWidget *label;
1803         GtkWidget *vbox;
1804         GtkWidget *scrolled;
1805         GtkWidget *viewport;
1806
1807         scrolled = gtk_scrolled_window_new(NULL, NULL);
1808         gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1809         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1810                                        GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1811         label = gtk_label_new(title);
1812         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1813         gtk_widget_show(scrolled);
1814
1815         viewport = gtk_viewport_new(NULL, NULL);
1816         gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1817         gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1818         gtk_widget_show(viewport);
1819
1820         vbox = gtk_vbox_new(FALSE, 0);
1821         gtk_container_add(GTK_CONTAINER(viewport), vbox);
1822         gtk_widget_show(vbox);
1823
1824         return vbox;
1825 }
1826
1827 static void cache_standard_cb(GtkWidget *widget, gpointer data)
1828 {
1829         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1830                 {
1831                 c_options->thumbnails.spec_standard =TRUE;
1832                 c_options->thumbnails.cache_into_dirs = FALSE;
1833                 }
1834 }
1835
1836 static void cache_geeqie_cb(GtkWidget *widget, gpointer data)
1837 {
1838         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1839                 {
1840                 c_options->thumbnails.spec_standard =FALSE;
1841                 c_options->thumbnails.cache_into_dirs = FALSE;
1842                 }
1843 }
1844
1845 static void cache_local_cb(GtkWidget *widget, gpointer data)
1846 {
1847         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1848                 {
1849                 c_options->thumbnails.cache_into_dirs = TRUE;
1850                 c_options->thumbnails.spec_standard =FALSE;
1851                 }
1852 }
1853
1854 static void help_search_engine_entry_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1855                                                                         GdkEvent *event, gpointer userdata)
1856 {
1857         if (pos == GTK_ENTRY_ICON_PRIMARY)
1858                 {
1859                 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1860                 }
1861         else
1862                 {
1863                 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1864                 }
1865 }
1866
1867 static void star_rating_star_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1868                                                                         GdkEvent *event, gpointer userdata)
1869 {
1870         gchar *rating_symbol;
1871
1872         if (pos == GTK_ENTRY_ICON_PRIMARY)
1873                 {
1874                 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1875                 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1876                 g_free(rating_symbol);
1877                 }
1878         else
1879                 {
1880                 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1881                 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1882                 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1883                 }
1884 }
1885
1886 static void star_rating_rejected_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1887                                                                         GdkEvent *event, gpointer userdata)
1888 {
1889         gchar *rating_symbol;
1890
1891         if (pos == GTK_ENTRY_ICON_PRIMARY)
1892                 {
1893                 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1894                 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1895                 g_free(rating_symbol);
1896                 }
1897         else
1898                 {
1899                 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1900                 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1901                 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1902                 }
1903 }
1904
1905 static guint star_rating_symbol_test(GtkWidget *widget, gpointer data)
1906 {
1907         GtkContainer *hbox = data;
1908         GString *str = g_string_new(NULL);
1909         GtkEntry *hex_code_entry;
1910         gchar *hex_code_full;
1911         gchar **hex_code;
1912         GList *list;
1913         guint64 hex_value = 0;
1914
1915         list = gtk_container_get_children(hbox);
1916
1917         hex_code_entry = g_list_nth_data(list, 2);
1918         hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1919
1920         hex_code = g_strsplit(hex_code_full, "+", 2);
1921         if (hex_code[0] && hex_code[1])
1922                 {
1923                 hex_value = strtoull(hex_code[1], NULL, 16);
1924                 }
1925         if (!hex_value || hex_value > 0x10FFFF)
1926                 {
1927                 hex_value = 0x003F; // Unicode 'Question Mark'
1928                 }
1929         str = g_string_append_unichar(str, (gunichar)hex_value);
1930         gtk_label_set_text(g_list_nth_data(list, 1), str->str);
1931
1932         g_strfreev(hex_code);
1933         g_string_free(str, TRUE);
1934         g_free(hex_code_full);
1935
1936         return hex_value;
1937 }
1938
1939 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1940 {
1941         guint64 star_symbol;
1942
1943         star_symbol = star_rating_symbol_test(widget, data);
1944         c_options->star_rating.star = star_symbol;
1945 }
1946
1947 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1948 {
1949         guint64 rejected_symbol;
1950
1951         rejected_symbol = star_rating_symbol_test(widget, data);
1952         c_options->star_rating.rejected = rejected_symbol;
1953 }
1954
1955 /* general options tab */
1956 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1957 typedef struct _TZData TZData;
1958 struct _TZData
1959 {
1960         GenericDialog *gd;
1961         GCancellable *cancellable;
1962
1963         GtkWidget *progress;
1964         GFile *tmp_g_file;
1965         GFile *timezone_database_gq;
1966         gchar *timezone_database_user;
1967 };
1968
1969 static void config_tab_general(GtkWidget *notebook)
1970 {
1971         GtkWidget *vbox;
1972         GtkWidget *hbox;
1973         GtkWidget *group;
1974         GtkWidget *group_frame;
1975         GtkWidget *subgroup;
1976         GtkWidget *button;
1977         GtkWidget *ct_button;
1978         GtkWidget *table;
1979         GtkWidget *spin;
1980         gint hours, minutes, remainder;
1981         gdouble seconds;
1982         GtkWidget *star_rating_entry;
1983         GString *str;
1984         gchar *rating_symbol;
1985         gchar *path;
1986         gchar *basename;
1987         GNetworkMonitor *net_mon;
1988         GSocketConnectable *geeqie_org;
1989         gboolean internet_available;
1990         TZData *tz;
1991
1992         vbox = scrolled_notebook_page(notebook, _("General"));
1993
1994         group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1995
1996         table = pref_table_new(group, 2, 2, FALSE, FALSE);
1997         add_thumb_size_menu(table, 0, 0, _("Size:"));
1998         add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1999
2000         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2001         pref_label_new(hbox, _("Custom size: "));
2002         pref_spin_new_int(hbox, _("Width:"), NULL, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
2003         pref_spin_new_int(hbox, _("Height:"), NULL, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
2004
2005         ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
2006                                           options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
2007
2008         subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2009         pref_checkbox_link_sensitivity(ct_button, subgroup);
2010
2011         c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
2012         c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
2013         group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
2014                                                                                 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2015         button = pref_radiobutton_new(group_frame, NULL,  get_thumbnails_cache_dir(),
2016                                                         !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2017                                                         G_CALLBACK(cache_geeqie_cb), NULL);
2018
2019         group_frame = pref_frame_new(subgroup, TRUE,
2020                                                         _("Store thumbnails local to image folder (non-standard)"),
2021                                                         GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2022         pref_radiobutton_new(group_frame, button, "*/.thumbnails",
2023                                                         !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
2024                                                         G_CALLBACK(cache_local_cb), NULL);
2025
2026         group_frame = pref_frame_new(subgroup, TRUE,
2027                                                         _("Use standard thumbnail style and cache, shared with other applications"),
2028                                                         GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2029         pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
2030                                                         options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2031                                                         G_CALLBACK(cache_standard_cb), NULL);
2032
2033         pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
2034                               options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
2035
2036         pref_checkbox_new_int(group, _("Thumbnail color management"),
2037                                 options->thumbnails.use_color_management, &c_options->thumbnails.use_color_management);
2038
2039         spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
2040                                  1, 999, 1,
2041                                  options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
2042         gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
2043
2044 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
2045         pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
2046                               options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
2047
2048 //      pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
2049 //                            options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
2050 #endif
2051
2052         pref_spacer(group, PREF_PAD_GROUP);
2053
2054         group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
2055
2056         c_options->star_rating.star = options->star_rating.star;
2057         c_options->star_rating.rejected = options->star_rating.rejected;
2058
2059         str = g_string_new(NULL);
2060         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2061         pref_label_new(hbox, _("Star character: "));
2062         str = g_string_append_unichar(str, options->star_rating.star);
2063         pref_label_new(hbox, g_strdup(str->str));
2064         rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
2065         star_rating_entry = gtk_entry_new();
2066         gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2067         gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2068         gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2069         gtk_widget_show(star_rating_entry);
2070         button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2071                                         G_CALLBACK(star_rating_star_test_cb), hbox);
2072         gtk_widget_set_tooltip_text(button, _("Display selected character"));
2073         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2074         gtk_widget_show(button);
2075         gtk_widget_set_tooltip_text(star_rating_entry, _("Hexadecimal representation of a Unicode character. A list of all Unicode characters may be found on the Internet."));
2076         gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2077                                                 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2078         gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2079                                                 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2080         gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2081                                                 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2082         gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2083                                                 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2084         g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2085                                                 G_CALLBACK(star_rating_star_icon_cb),
2086                                                 star_rating_entry);
2087
2088         g_string_free(str, TRUE);
2089         g_free(rating_symbol);
2090
2091         str = g_string_new(NULL);
2092         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2093         pref_label_new(hbox, _("Rejected character: "));
2094         str = g_string_append_unichar(str, options->star_rating.rejected);
2095         pref_label_new(hbox, g_strdup(str->str));
2096         rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2097         star_rating_entry = gtk_entry_new();
2098         gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2099         gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2100         gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2101         gtk_widget_show(star_rating_entry);
2102         button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2103                                         G_CALLBACK(star_rating_rejected_test_cb), hbox);
2104         gtk_widget_set_tooltip_text(button, _("Display selected character"));
2105         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2106         gtk_widget_show(button);
2107         gtk_widget_set_tooltip_text(star_rating_entry, _("Hexadecimal representation of a Unicode character. A list of all Unicode characters may be found on the Internet."));
2108         gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2109                                                 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2110         gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2111                                                 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2112         gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2113                                                 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2114         gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2115                                                 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2116         g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2117                                                 G_CALLBACK(star_rating_rejected_icon_cb),
2118                                                 star_rating_entry);
2119
2120         g_string_free(str, TRUE);
2121         g_free(rating_symbol);
2122
2123         pref_spacer(group, PREF_PAD_GROUP);
2124
2125         group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2126
2127         c_options->slideshow.delay = options->slideshow.delay;
2128         hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2129         remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2130         minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2131         seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2132                                                                                         SLIDESHOW_SUBSECOND_PRECISION;
2133
2134         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2135
2136         spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2137                                                                                 0, 23, 1.0, 0,
2138                                                                                 options->slideshow.delay ? hours : 0.0,
2139                                                                                 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2140         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2141         spin = pref_spin_new(hbox, ":" , NULL,
2142                                                                                 0, 59, 1.0, 0,
2143                                                                                 options->slideshow.delay ? minutes: 0.0,
2144                                                                                 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2145         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2146         spin = pref_spin_new(hbox, ":", NULL,
2147                                                                                 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2148                                                                                 options->slideshow.delay ? seconds : 10.0,
2149                                                                                 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2150         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2151
2152         pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2153         pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2154
2155         pref_spacer(group, PREF_PAD_GROUP);
2156
2157         group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2158
2159         pref_spin_new_int(group, _("Decoded image cache size (MiB):"), NULL,
2160                           0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2161         pref_checkbox_new_int(group, _("Preload next image"),
2162                               options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2163
2164         pref_checkbox_new_int(group, _("Refresh on file change"),
2165                               options->update_on_time_change, &c_options->update_on_time_change);
2166
2167
2168         pref_spacer(group, PREF_PAD_GROUP);
2169
2170         group = pref_group_new(vbox, FALSE, _("Expand menu and toolbar"), GTK_ORIENTATION_VERTICAL);
2171
2172         pref_checkbox_new_int(group, _("Expand menu and toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2173                                 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2174         gtk_widget_set_tooltip_text(group, _("Expand the menu and toolbar to the full width of the window"));
2175
2176         pref_spacer(group, PREF_PAD_GROUP);
2177
2178         net_mon = g_network_monitor_get_default();
2179         geeqie_org = g_network_address_parse_uri(GQ_WEBSITE, 80, NULL);
2180         internet_available = g_network_monitor_can_reach(net_mon, geeqie_org, NULL, NULL);
2181         g_object_unref(geeqie_org);
2182
2183         group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2184         hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2185
2186         if (!internet_available)
2187                 {
2188                 gtk_widget_set_sensitive(group, FALSE);
2189                 }
2190
2191         tz = g_new0(TZData, 1);
2192
2193         path = path_from_utf8(TIMEZONE_DATABASE);
2194         basename = g_path_get_basename(path);
2195         tz->timezone_database_user = g_build_filename(get_rc_dir(), basename, NULL);
2196         g_free(path);
2197         g_free(basename);
2198
2199         if (isfile(tz->timezone_database_user))
2200                 {
2201                 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2202                 }
2203         else
2204                 {
2205                 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2206                 }
2207
2208         if (!internet_available)
2209                 {
2210                 gtk_widget_set_tooltip_text(button, _("No Internet connection!\nThe timezone database is used to display exif time and date\ncorrected for UTC offset and Daylight Saving Time"));
2211                 }
2212         else
2213                 {
2214                 gtk_widget_set_tooltip_text(button, _("The timezone database is used to display exif time and date\ncorrected for UTC offset and Daylight Saving Time"));
2215                 }
2216         gtk_widget_show(button);
2217
2218         pref_spacer(group, PREF_PAD_GROUP);
2219
2220         group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2221
2222         help_search_engine_entry = gtk_entry_new();
2223         gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2224         gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2225         gtk_widget_show(help_search_engine_entry);
2226
2227         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"));
2228
2229         gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2230                                                 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2231         gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2232                                                 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2233         gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2234                                                 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2235         gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2236                                                 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2237         g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2238                                                 G_CALLBACK(help_search_engine_entry_icon_cb),
2239                                                 help_search_engine_entry);
2240 }
2241
2242 /* image tab */
2243 static void config_tab_image(GtkWidget *notebook)
2244 {
2245         GtkWidget *hbox;
2246         GtkWidget *vbox;
2247         GtkWidget *group;
2248         GtkWidget *ct_button;
2249         GtkWidget *enlargement_button;
2250         GtkWidget *table;
2251         GtkWidget *spin;
2252         GtkWidget *two_pass;
2253 #ifdef HAVE_CLUTTER
2254         GtkWidget *gpu_accel;
2255 #endif
2256
2257         vbox = scrolled_notebook_page(notebook, _("Image"));
2258
2259         group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2260
2261         table = pref_table_new(group, 2, 1, FALSE, FALSE);
2262         add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2263         if (options->image.use_clutter_renderer && !options->disable_gpu)
2264                 {
2265                 gtk_widget_set_sensitive(table, FALSE);
2266                 }
2267
2268 #ifdef HAVE_CLUTTER
2269         gpu_accel = pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library (Requires restart)"),
2270                               options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2271         if (options->disable_gpu && !options->override_disable_gpu)
2272                 {
2273                 gtk_widget_set_sensitive(gpu_accel, FALSE);
2274                 }
2275 #endif
2276
2277         two_pass = pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2278                               options->image.zoom_2pass, &c_options->image.zoom_2pass);
2279         if (options->image.use_clutter_renderer && !options->disable_gpu)
2280                 {
2281                 gtk_widget_set_sensitive(two_pass, FALSE);
2282                 }
2283
2284         c_options->image.zoom_increment = options->image.zoom_increment;
2285         spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2286                              0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2287                              G_CALLBACK(zoom_increment_cb), NULL);
2288         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2289
2290         c_options->image.zoom_style = options->image.zoom_style;
2291         table = pref_table_new(group, 2, 1, FALSE, FALSE);
2292         add_zoom_style_selection_menu(table, 0, 0, _("Zoom style:"), options->image.zoom_style, &c_options->image.zoom_style);
2293
2294         group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2295
2296         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2297         enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2298                               options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2299         spin = pref_spin_new_int(hbox, NULL, NULL,
2300                                  100, 999, 1,
2301                                  options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2302         pref_checkbox_link_sensitivity(enlargement_button, spin);
2303         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."));
2304
2305         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2306         ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2307                                           options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2308         spin = pref_spin_new_int(hbox, NULL, NULL,
2309                                  10, 150, 1,
2310                                  options->image.max_autofit_size, &c_options->image.max_autofit_size);
2311         pref_checkbox_link_sensitivity(ct_button, spin);
2312         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."));
2313
2314         group = pref_group_new(vbox, FALSE, _("Tile size"), GTK_ORIENTATION_VERTICAL);
2315         gtk_widget_set_sensitive(group, !options->image.use_clutter_renderer);
2316
2317         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2318         spin = pref_spin_new_int(hbox, _("Pixels"), _("(Requires restart)"),
2319                                  128, 4096, 128,
2320                                  options->image.tile_size, &c_options->image.tile_size);
2321         gtk_widget_set_tooltip_text(GTK_WIDGET(hbox), _("This value changes the size of the tiles large images are split into. Increasing the size of the tiles will reduce the tiling effect seen on image changes, but will also slightly increase the delay before the first part of a large image is seen."));
2322
2323         group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2324
2325         pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2326                               options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2327
2328         pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2329                               options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2330
2331         pref_color_button_new(group, _("Border color"), &options->image.border_color,
2332                               G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2333
2334         c_options->image.border_color = options->image.border_color;
2335
2336         pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2337                               G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2338
2339         pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2340                               G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2341
2342         c_options->image.alpha_color_1 = options->image.alpha_color_1;
2343         c_options->image.alpha_color_2 = options->image.alpha_color_2;
2344
2345         group = pref_group_new(vbox, FALSE, _("Convenience"), GTK_ORIENTATION_VERTICAL);
2346
2347         pref_checkbox_new_int(group, _("Auto rotate proofs using Exif information"),
2348                               options->image.exif_proof_rotate_enable, &c_options->image.exif_proof_rotate_enable);
2349 }
2350
2351 /* windows tab */
2352
2353 static void save_default_window_layout_cb(GtkWidget *widget, gpointer data)
2354 {
2355         LayoutWindow *lw = NULL;
2356         gchar *default_path;
2357         gchar *tmp_id;
2358
2359         /* Get current lw */
2360         layout_valid(&lw);
2361
2362         tmp_id = lw->options.id;
2363         lw->options.id = g_strdup("lw_default");
2364
2365         default_path = g_build_filename(get_rc_dir(), DEFAULT_WINDOW_LAYOUT, NULL);
2366         save_default_layout_options_to_file(default_path, options, lw);
2367         g_free(lw->options.id);
2368         lw->options.id = tmp_id;
2369         g_free(default_path);
2370 }
2371
2372 #if GTK_CHECK_VERSION(3,22,0)
2373 static gboolean popover_cb(gpointer data)
2374 {
2375         GtkPopover *popover = data;
2376
2377         gtk_popover_popdown(popover);
2378
2379         return FALSE;
2380 }
2381
2382 static void default_layout_changed_cb(GtkWidget *button, GtkPopover *popover)
2383 {
2384         gtk_popover_popup(popover);
2385
2386         g_timeout_add(2000, popover_cb, popover);
2387 }
2388
2389 static GtkWidget *create_popover(GtkWidget *parent, GtkWidget *child, GtkPositionType pos)
2390 {
2391         GtkWidget *popover;
2392
2393         popover = gtk_popover_new(parent);
2394         gtk_popover_set_position(GTK_POPOVER (popover), pos);
2395         gtk_container_add (GTK_CONTAINER(popover), child);
2396         gtk_container_set_border_width(GTK_CONTAINER (popover), 6);
2397         gtk_widget_show (child);
2398
2399         return popover;
2400 }
2401 #endif
2402
2403 static void config_tab_windows(GtkWidget *notebook)
2404 {
2405         GtkWidget *hbox;
2406         GtkWidget *vbox;
2407         GtkWidget *group;
2408         GtkWidget *subgroup;
2409         GtkWidget *button;
2410         GtkWidget *ct_button;
2411         GtkWidget *spin;
2412
2413         vbox = scrolled_notebook_page(notebook, _("Windows"));
2414
2415         group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2416
2417         ct_button = pref_checkbox_new_int(group, _("Remember session"),
2418                                           options->save_window_positions, &c_options->save_window_positions);
2419
2420         button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2421                                        options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2422         pref_checkbox_link_sensitivity(ct_button, button);
2423
2424         button = pref_checkbox_new_int(group, _("Remember window workspace"),
2425                               options->save_window_workspace, &c_options->save_window_workspace);
2426         pref_checkbox_link_sensitivity(ct_button, button);
2427
2428         pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2429                               options->tools_restore_state, &c_options->tools_restore_state);
2430
2431         pref_checkbox_new_int(group, _("Remember dialog window positions"),
2432                               options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2433
2434         pref_checkbox_new_int(group, _("Show window IDs"),
2435                               options->show_window_ids, &c_options->show_window_ids);
2436
2437         subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2438         pref_label_new(subgroup, _("Use current layout for default: "));
2439         button = pref_button_new(subgroup, NULL, _("Set"), FALSE, G_CALLBACK(save_default_window_layout_cb), NULL);
2440
2441 #if GTK_CHECK_VERSION(3,22,0)
2442         GtkWidget *popover;
2443
2444         popover = create_popover(button, gtk_label_new(_("Current window layout\nhas been set as default")), GTK_POS_TOP);
2445         gtk_popover_set_modal(GTK_POPOVER (popover), FALSE);
2446         g_signal_connect(button, "clicked", G_CALLBACK(default_layout_changed_cb), popover);
2447 #endif
2448
2449         group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2450
2451         pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2452                               options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2453
2454         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2455         ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2456                                           options->image.limit_window_size, &c_options->image.limit_window_size);
2457         spin = pref_spin_new_int(hbox, NULL, NULL,
2458                                  10, 150, 1,
2459                                  options->image.max_window_size, &c_options->image.max_window_size);
2460         pref_checkbox_link_sensitivity(ct_button, spin);
2461
2462         group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2463
2464         c_options->fullscreen.screen = options->fullscreen.screen;
2465         c_options->fullscreen.above = options->fullscreen.above;
2466         hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2467         gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2468         gtk_widget_show(hbox);
2469
2470         pref_checkbox_new_int(group, _("Smooth image flip"),
2471                               options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2472         pref_checkbox_new_int(group, _("Disable screen saver"),
2473                               options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2474 }
2475
2476 #define PRE_FORMATTED_COLUMNS 5
2477 static void config_tab_osd(GtkWidget *notebook)
2478 {
2479         GtkWidget *hbox;
2480         GtkWidget *vbox;
2481         GtkWidget *group;
2482         GtkWidget *button;
2483         GtkWidget *image_overlay_template_view;
2484         GtkWidget *scrolled;
2485         GtkWidget *scrolled_pre_formatted;
2486         GtkTextBuffer *buffer;
2487         GtkWidget *label;
2488         GtkWidget *subgroup;
2489
2490         vbox = scrolled_notebook_page(notebook, _("OSD"));
2491
2492         image_overlay_template_view = gtk_text_view_new();
2493
2494         group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2495
2496         subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2497
2498         scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2499         gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2500         gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2501         gtk_widget_show(scrolled_pre_formatted);
2502         gtk_widget_show(subgroup);
2503
2504         pref_line(group, PREF_PAD_GAP);
2505
2506         pref_label_new(group, _("Image overlay template"));
2507
2508         scrolled = gtk_scrolled_window_new(NULL, NULL);
2509         gtk_widget_set_size_request(scrolled, 200, 150);
2510         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2511         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2512                                                                         GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2513         gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2514         gtk_widget_show(scrolled);
2515
2516         gtk_widget_set_tooltip_markup(image_overlay_template_view,
2517                                         _("Extensive formatting options are shown in the Help file"));
2518
2519         gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2520         gtk_widget_show(image_overlay_template_view);
2521
2522         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2523
2524 #if GTK_CHECK_VERSION(3,4,0)
2525         button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2526                                  G_CALLBACK(image_overlay_set_font_cb), notebook);
2527 #else
2528         button = gtk_font_button_new();
2529         gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
2530         gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
2531         g_signal_connect(G_OBJECT(button), "font-set",
2532                                  G_CALLBACK(image_overlay_set_font_cb),NULL);
2533 #endif
2534         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2535         gtk_widget_show(button);
2536
2537         button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2538                                  G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2539         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2540         gtk_widget_show(button);
2541
2542         button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2543                                  G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2544         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2545         gtk_widget_show(button);
2546         image_overlay_set_text_colours();
2547
2548         button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2549                                  G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2550         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2551         gtk_widget_show(button);
2552
2553         button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2554                                  G_CALLBACK(image_overlay_help_cb), NULL);
2555         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2556         gtk_widget_show(button);
2557
2558         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2559         if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2560         g_signal_connect(G_OBJECT(buffer), "changed",
2561                          G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2562
2563         pref_line(group, PREF_PAD_GAP);
2564
2565         group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2566         hbox = gtk_hbox_new(FALSE, 0);
2567         gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2568         gtk_widget_show(hbox);
2569         label = gtk_label_new(_("%Exif.Image.Orientation%"));
2570         gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2571         gtk_widget_show(label);
2572         pref_spacer(group,TRUE);
2573
2574         group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2575         hbox = gtk_hbox_new(FALSE, 0);
2576         gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2577         gtk_widget_show(hbox);
2578         label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2579         gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2580         gtk_widget_show(label);
2581         pref_spacer(group,TRUE);
2582
2583         group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2584         hbox = gtk_hbox_new(FALSE, 0);
2585         gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2586         gtk_widget_show(hbox);
2587         label = gtk_label_new(_("%path:39%"));
2588         gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2589         gtk_widget_show(label);
2590         pref_spacer(group,TRUE);
2591
2592         group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2593         hbox = gtk_hbox_new(FALSE, 0);
2594         gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2595         gtk_widget_show(hbox);
2596         label = gtk_label_new(_("Text shown only if the field is non-null:\n%formatted.Aperture:F no. * setting%\n %formatted.Aperture:10:F no. * setting%"));
2597         gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2598         gtk_widget_show(label);
2599         pref_spacer(group,TRUE);
2600
2601         group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2602         hbox = gtk_hbox_new(FALSE, 0);
2603         gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2604         gtk_widget_show(hbox);
2605         label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2606         gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2607         gtk_widget_show(label);
2608 }
2609
2610 static GtkTreeModel *create_class_model(void)
2611 {
2612         GtkListStore *model;
2613         GtkTreeIter iter;
2614         gint i;
2615
2616         /* create list store */
2617         model = gtk_list_store_new(1, G_TYPE_STRING);
2618         for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2619                 {
2620                 gtk_list_store_append(model, &iter);
2621                 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2622                 }
2623         return GTK_TREE_MODEL (model);
2624 }
2625
2626
2627 /* filtering tab */
2628 static void config_tab_files(GtkWidget *notebook)
2629 {
2630         GtkWidget *hbox;
2631         GtkWidget *frame;
2632         GtkWidget *vbox;
2633         GtkWidget *group;
2634         GtkWidget *button;
2635         GtkWidget *ct_button;
2636         GtkWidget *scrolled;
2637         GtkWidget *filter_view;
2638         GtkCellRenderer *renderer;
2639         GtkTreeSelection *selection;
2640         GtkTreeViewColumn *column;
2641
2642         vbox = scrolled_notebook_page(notebook, _("Files"));
2643
2644         group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2645
2646         pref_checkbox_new_int(group, _("Show hidden files or folders"),
2647                               options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2648         pref_checkbox_new_int(group, _("Show parent folder (..)"),
2649                               options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2650         pref_checkbox_new_int(group, _("Case sensitive sort"),
2651                               options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2652         pref_checkbox_new_int(group, _("Natural sort order"),
2653                                           options->file_sort.natural, &c_options->file_sort.natural);
2654         pref_checkbox_new_int(group, _("Disable file extension checks"),
2655                               options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2656
2657         ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2658                                           options->file_filter.disable, &c_options->file_filter.disable);
2659
2660
2661         group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2662
2663         sidecar_ext_entry = gtk_entry_new();
2664         gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2665         gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2666         gtk_widget_show(sidecar_ext_entry);
2667
2668         group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2669
2670         frame = pref_group_parent(group);
2671         g_signal_connect(G_OBJECT(ct_button), "toggled",
2672                          G_CALLBACK(filter_disable_cb), frame);
2673         gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2674
2675         scrolled = gtk_scrolled_window_new(NULL, NULL);
2676         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2677         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2678         gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2679         gtk_widget_show(scrolled);
2680
2681         filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2682         filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2683         g_object_unref(filter_store);
2684         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2685         gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2686
2687         gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2688
2689         column = gtk_tree_view_column_new();
2690         gtk_tree_view_column_set_title(column, _("Filter"));
2691         gtk_tree_view_column_set_resizable(column, TRUE);
2692
2693         renderer = gtk_cell_renderer_toggle_new();
2694         g_signal_connect(G_OBJECT(renderer), "toggled",
2695                          G_CALLBACK(filter_store_enable_cb), filter_store);
2696         gtk_tree_view_column_pack_start(column, renderer, FALSE);
2697         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2698                                                 GINT_TO_POINTER(FE_ENABLE), NULL);
2699
2700         renderer = gtk_cell_renderer_text_new();
2701         g_signal_connect(G_OBJECT(renderer), "edited",
2702                          G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2703         gtk_tree_view_column_pack_start(column, renderer, TRUE);
2704         g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2705         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2706                                                 GINT_TO_POINTER(FE_EXTENSION), NULL);
2707         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2708
2709         column = gtk_tree_view_column_new();
2710         gtk_tree_view_column_set_title(column, _("Description"));
2711         gtk_tree_view_column_set_resizable(column, TRUE);
2712         gtk_tree_view_column_set_fixed_width(column, 200);
2713         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2714
2715         renderer = gtk_cell_renderer_text_new();
2716         g_signal_connect(G_OBJECT(renderer), "edited",
2717                          G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2718         g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2719         gtk_tree_view_column_pack_start(column, renderer, FALSE);
2720         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2721                                                 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2722         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2723
2724         column = gtk_tree_view_column_new();
2725         gtk_tree_view_column_set_title(column, _("Class"));
2726         gtk_tree_view_column_set_resizable(column, TRUE);
2727         renderer = gtk_cell_renderer_combo_new();
2728         g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2729                                          "model", create_class_model(),
2730                                          "text-column", 0,
2731                                          "has-entry", FALSE,
2732                                          NULL);
2733
2734         g_signal_connect(G_OBJECT(renderer), "edited",
2735                          G_CALLBACK(filter_store_class_edit_cb), filter_store);
2736         gtk_tree_view_column_pack_start(column, renderer, TRUE);
2737         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2738                                                 GINT_TO_POINTER(FE_CLASS), NULL);
2739         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2740
2741         column = gtk_tree_view_column_new();
2742         gtk_tree_view_column_set_title(column, _("Writable"));
2743         gtk_tree_view_column_set_resizable(column, FALSE);
2744         renderer = gtk_cell_renderer_toggle_new();
2745         g_signal_connect(G_OBJECT(renderer), "toggled",
2746                          G_CALLBACK(filter_store_writable_cb), filter_store);
2747         gtk_tree_view_column_pack_start(column, renderer, FALSE);
2748         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2749                                                 GINT_TO_POINTER(FE_WRITABLE), NULL);
2750         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2751
2752         column = gtk_tree_view_column_new();
2753         gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2754         gtk_tree_view_column_set_resizable(column, FALSE);
2755         renderer = gtk_cell_renderer_toggle_new();
2756         g_signal_connect(G_OBJECT(renderer), "toggled",
2757                          G_CALLBACK(filter_store_sidecar_cb), filter_store);
2758         gtk_tree_view_column_pack_start(column, renderer, FALSE);
2759         gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2760                                                 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2761         gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2762
2763
2764         filter_store_populate();
2765         gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2766         gtk_widget_show(filter_view);
2767
2768         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2769
2770         button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2771                                  G_CALLBACK(filter_default_cb), filter_view);
2772         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2773         gtk_widget_show(button);
2774
2775         button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2776                                  G_CALLBACK(filter_remove_cb), filter_view);
2777         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2778         gtk_widget_show(button);
2779
2780         button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2781                                  G_CALLBACK(filter_add_cb), filter_view);
2782         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2783         gtk_widget_show(button);
2784 }
2785
2786 /* metadata tab */
2787 static void config_tab_metadata(GtkWidget *notebook)
2788 {
2789         GtkWidget *vbox;
2790         GtkWidget *hbox;
2791         GtkWidget *group;
2792         GtkWidget *ct_button;
2793         GtkWidget *label;
2794         gchar *text;
2795
2796         vbox = scrolled_notebook_page(notebook, _("Metadata"));
2797
2798
2799         group = pref_group_new(vbox, FALSE, _("Metadata writing process"), GTK_ORIENTATION_VERTICAL);
2800 #ifndef HAVE_EXIV2
2801         label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2802 #endif
2803         label = pref_label_new(group, _("Metadata are written in the following order. The process ends after first success."));
2804 #if GTK_CHECK_VERSION(3,16,0)
2805         gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2806         gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2807 #else
2808         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2809 #endif
2810
2811         ct_button = pref_checkbox_new_int(group, _("1) Save metadata in image files, or sidecar files, according to the XMP standard"),
2812                               options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2813 #ifndef HAVE_EXIV2
2814         gtk_widget_set_sensitive(ct_button, FALSE);
2815 #endif
2816
2817         pref_checkbox_new_int(group, _("2) Save metadata in '.metadata' folder, local to image folder (non-standard)"),
2818                               options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2819
2820         text = g_strdup_printf(_("3) Save metadata in Geeqie private directory '%s'"), get_metadata_cache_dir());
2821         label = pref_label_new(group, text);
2822 #if GTK_CHECK_VERSION(3,16,0)
2823         gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2824         gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2825 #else
2826         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2827 #endif
2828         gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2829         g_free(text);
2830
2831         group = pref_group_new(vbox, FALSE, _("Step 1: Write to image files"), GTK_ORIENTATION_VERTICAL);
2832 #ifndef HAVE_EXIV2
2833         gtk_widget_set_sensitive(group, FALSE);
2834 #endif
2835
2836         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2837         pref_checkbox_link_sensitivity(ct_button, hbox);
2838
2839         pref_checkbox_new_int(hbox, _("Store metadata also in legacy IPTC tags (converted according to IPTC4XMP standard)"),
2840                               options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2841
2842         pref_checkbox_new_int(hbox, _("Warn if the image files are unwritable"),
2843                               options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2844
2845         pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
2846                               options->metadata.confirm_write, &c_options->metadata.confirm_write);
2847
2848         pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
2849                               options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2850
2851         group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
2852 #ifndef HAVE_EXIV2
2853         gtk_widget_set_sensitive(group, FALSE);
2854 #endif
2855
2856         pref_checkbox_new_int(group, _("Use GQview legacy metadata format (supports only keywords and comments) instead of XMP"),
2857                               options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2858
2859
2860         group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2861         pref_checkbox_new_int(group, _("Write the same description tags (keywords, comment, etc.) to all grouped sidecars"),
2862                               options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2863
2864         pref_checkbox_new_int(group, _("Allow keywords to differ only in case"),
2865                               options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2866
2867         ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"),
2868                               options->metadata.write_orientation, &c_options->metadata.write_orientation);
2869 #ifndef HAVE_EXIV2
2870         gtk_widget_set_sensitive(ct_button, FALSE);
2871 #endif
2872
2873         group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2874
2875         ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"),
2876                               options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2877
2878         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2879         pref_checkbox_link_sensitivity(ct_button, hbox);
2880
2881         pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1,
2882                               options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2883
2884         pref_checkbox_new_int(group, _("Write metadata on image change"),
2885                               options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2886
2887         pref_checkbox_new_int(group, _("Write metadata on directory change"),
2888                               options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2889
2890         group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2891
2892         ct_button = pref_checkbox_new_int(group, _("Read metadata in background"),
2893                                           options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2894         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");
2895 }
2896
2897 /* keywords tab */
2898
2899 typedef struct _KeywordFindData KeywordFindData;
2900 struct _KeywordFindData
2901 {
2902         GenericDialog *gd;
2903
2904         GList *list;
2905         GList *list_dir;
2906
2907         GtkWidget *button_close;
2908         GtkWidget *button_stop;
2909         GtkWidget *button_start;
2910         GtkWidget *progress;
2911         GtkWidget *spinner;
2912
2913         GtkWidget *group;
2914         GtkWidget *entry;
2915
2916         gboolean recurse;
2917
2918         guint idle_id; /* event source id */
2919 };
2920
2921 #define KEYWORD_DIALOG_WIDTH 400
2922
2923 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
2924 {
2925         GList *list_d = NULL;
2926         GList *list_f = NULL;
2927
2928         if (kfd->recurse)
2929                 {
2930                 filelist_read(dir_fd, &list_f, &list_d);
2931                 }
2932         else
2933                 {
2934                 filelist_read(dir_fd, &list_f, NULL);
2935                 }
2936
2937         list_f = filelist_filter(list_f, FALSE);
2938         list_d = filelist_filter(list_d, TRUE);
2939
2940         kfd->list = g_list_concat(list_f, kfd->list);
2941         kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
2942 }
2943
2944 static void keywords_find_reset(KeywordFindData *kfd)
2945 {
2946         filelist_free(kfd->list);
2947         kfd->list = NULL;
2948
2949         filelist_free(kfd->list_dir);
2950         kfd->list_dir = NULL;
2951 }
2952
2953 static void keywords_find_close_cb(GenericDialog *fd, gpointer data)
2954 {
2955         KeywordFindData *kfd = data;
2956
2957         if (!gtk_widget_get_sensitive(kfd->button_close)) return;
2958
2959         keywords_find_reset(kfd);
2960         generic_dialog_close(kfd->gd);
2961         g_free(kfd);
2962 }
2963
2964 static void keywords_find_finish(KeywordFindData *kfd)
2965 {
2966         keywords_find_reset(kfd);
2967
2968         gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
2969         spinner_set_interval(kfd->spinner, -1);
2970
2971         gtk_widget_set_sensitive(kfd->group, TRUE);
2972         gtk_widget_set_sensitive(kfd->button_start, TRUE);
2973         gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2974         gtk_widget_set_sensitive(kfd->button_close, TRUE);
2975 }
2976
2977 static void keywords_find_stop_cb(GenericDialog *fd, gpointer data)
2978 {
2979         KeywordFindData *kfd = data;
2980
2981         g_idle_remove_by_data(kfd);
2982
2983         keywords_find_finish(kfd);
2984 }
2985
2986 static gboolean keywords_find_file(gpointer data)
2987 {
2988         KeywordFindData *kfd = data;
2989         GtkTextIter iter;
2990         GtkTextBuffer *buffer;
2991         gchar *tmp;
2992         GList *keywords;
2993
2994         if (kfd->list)
2995                 {
2996                 FileData *fd;
2997
2998                 fd = kfd->list->data;
2999                 kfd->list = g_list_remove(kfd->list, fd);
3000
3001                 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
3002                 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3003
3004                 while (keywords)
3005                         {
3006                         gtk_text_buffer_get_end_iter(buffer, &iter);
3007                         tmp = g_strconcat(keywords->data, "\n", NULL);
3008                         gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3009                         g_free(tmp);
3010                         keywords = keywords->next;
3011                         }
3012
3013                 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
3014                 file_data_unref(fd);
3015                 string_list_free(keywords);
3016
3017                 return (TRUE);
3018                 }
3019         else if (kfd->list_dir)
3020                 {
3021                 FileData *fd;
3022
3023                 fd = kfd->list_dir->data;
3024                 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
3025
3026                 keywords_find_folder(kfd, fd);
3027
3028                 file_data_unref(fd);
3029
3030                 return TRUE;
3031                 }
3032
3033         keywords_find_finish(kfd);
3034
3035         return FALSE;
3036 }
3037
3038 static void keywords_find_start_cb(GenericDialog *fd, gpointer data)
3039 {
3040         KeywordFindData *kfd = data;
3041         gchar *path;
3042
3043         if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
3044
3045         path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
3046         parse_out_relatives(path);
3047
3048         if (!isdir(path))
3049                 {
3050                 warning_dialog(_("Invalid folder"),
3051                                 _("The specified folder can not be found."),
3052                                 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
3053                 }
3054         else
3055                 {
3056                 FileData *dir_fd;
3057
3058                 gtk_widget_set_sensitive(kfd->group, FALSE);
3059                 gtk_widget_set_sensitive(kfd->button_start, FALSE);
3060                 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
3061                 gtk_widget_set_sensitive(kfd->button_close, FALSE);
3062                 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
3063
3064                 dir_fd = file_data_new_dir(path);
3065                 keywords_find_folder(kfd, dir_fd);
3066                 file_data_unref(dir_fd);
3067                 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
3068                 }
3069
3070         g_free(path);
3071 }
3072
3073 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
3074 {
3075         KeywordFindData *kfd;
3076         GtkWidget *hbox;
3077         GtkWidget *label;
3078
3079         kfd = g_new0(KeywordFindData, 1);
3080
3081         kfd->gd = generic_dialog_new(_("Search for keywords"),
3082                                                                         "search_for_keywords",
3083                                                                         widget, FALSE,
3084                                                                         NULL, kfd);
3085         gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
3086         kfd->gd->cancel_cb = keywords_find_close_cb;
3087         kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
3088                                                      keywords_find_close_cb, FALSE);
3089         kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
3090                                                      keywords_find_start_cb, FALSE);
3091         kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
3092                                                     keywords_find_stop_cb, FALSE);
3093         gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3094
3095         generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
3096
3097         hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
3098         pref_spacer(hbox, PREF_PAD_INDENT);
3099         kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
3100
3101         hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3102         pref_label_new(hbox, _("Folder:"));
3103
3104         label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
3105         tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
3106         gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
3107         gtk_widget_show(label);
3108
3109         pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
3110
3111         pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
3112         hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3113
3114         kfd->progress = gtk_entry_new();
3115         gtk_widget_set_can_focus(kfd->progress, FALSE);
3116         gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
3117         gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
3118         gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
3119         gtk_widget_show(kfd->progress);
3120
3121         kfd->spinner = spinner_new(NULL, -1);
3122         gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
3123         gtk_widget_show(kfd->spinner);
3124
3125         kfd->list = NULL;
3126
3127         gtk_widget_show(kfd->gd->dialog);
3128 }
3129
3130 static void keywords_find_cb(GtkWidget *widget, gpointer data)
3131 {
3132         const gchar *path = layout_get_path(NULL);
3133
3134         if (!path || !*path) path = homedir();
3135         keywords_find_dialog(widget, path);
3136 }
3137
3138 static void config_tab_keywords_save()
3139 {
3140         GtkTextIter start, end;
3141         GtkTextBuffer *buffer;
3142         GList *kw_list = NULL;
3143         GList *work;
3144         gchar *buffer_text;
3145         gchar *kw_split;
3146         gboolean found;
3147
3148         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3149         gtk_text_buffer_get_bounds(buffer, &start, &end);
3150
3151         buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3152
3153         kw_split = strtok(buffer_text, "\n");
3154         while (kw_split != NULL)
3155                 {
3156                 work = kw_list;
3157                 found = FALSE;
3158                 while (work)
3159                         {
3160                         if (g_strcmp0(work->data, kw_split) == 0)
3161                                 {
3162                                 found = TRUE;
3163                                 break;
3164                                 }
3165                         work = work->next;
3166                         }
3167                 if (!found)
3168                         {
3169                         kw_list = g_list_append(kw_list, g_strdup(kw_split));
3170                         }
3171                 kw_split = strtok(NULL, "\n");
3172                 }
3173
3174         keyword_list_set(kw_list);
3175
3176         string_list_free(kw_list);
3177         g_free(buffer_text);
3178 }
3179
3180 static void config_tab_keywords(GtkWidget *notebook)
3181 {
3182         GtkWidget *hbox;
3183         GtkWidget *vbox;
3184         GtkWidget *group;
3185         GtkWidget *button;
3186         GtkWidget *scrolled;
3187         GtkTextIter iter;
3188         GtkTextBuffer *buffer;
3189         gchar *tmp;
3190
3191         vbox = scrolled_notebook_page(notebook, _("Keywords"));
3192
3193         group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3194
3195         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3196
3197         button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
3198                                    G_CALLBACK(keywords_find_cb), keyword_text);
3199         gtk_widget_set_tooltip_text(button, "Search for existing keywords");
3200
3201
3202         keyword_text = gtk_text_view_new();
3203         gtk_widget_set_size_request(keyword_text, 20, 20);
3204         scrolled = gtk_scrolled_window_new(NULL, NULL);
3205         gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3206         gtk_widget_show(scrolled);
3207
3208         gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
3209         gtk_widget_show(keyword_text);
3210
3211         gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3212
3213         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3214         gtk_text_buffer_create_tag(buffer, "monospace",
3215                                 "family", "monospace", NULL);
3216
3217         gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3218         gtk_text_buffer_get_start_iter(buffer, &iter);
3219         gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3220         gchar *path;
3221
3222         path = g_build_filename(get_rc_dir(), "keywords", NULL);
3223
3224         GList *kwl = keyword_list_get();
3225         kwl = g_list_first(kwl);
3226         while (kwl)
3227         {
3228                 gtk_text_buffer_get_end_iter (buffer, &iter);
3229             tmp = g_strconcat(kwl->data, "\n", NULL);
3230                 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3231                 kwl = kwl->next;
3232                 g_free(tmp);
3233         }
3234
3235         gtk_text_buffer_set_modified(buffer, FALSE);
3236
3237         g_free(path);
3238 }
3239
3240 /* metadata tab */
3241 #ifdef HAVE_LCMS
3242 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3243 {
3244         gint *option = data;
3245
3246         switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3247                 {
3248                 case 0:
3249                 default:
3250                         *option = INTENT_PERCEPTUAL;
3251                         break;
3252                 case 1:
3253                         *option = INTENT_RELATIVE_COLORIMETRIC;
3254                         break;
3255                 case 2:
3256                         *option = INTENT_SATURATION;
3257                         break;
3258                 case 3:
3259                         *option = INTENT_ABSOLUTE_COLORIMETRIC;
3260                         break;
3261                 }
3262 }
3263
3264 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3265                              gint option, gint *option_c)
3266 {
3267         GtkWidget *combo;
3268         gint current = 0;
3269
3270         *option_c = option;
3271
3272         pref_table_label(table, column, row, text, 0.0);
3273
3274         combo = gtk_combo_box_text_new();
3275
3276         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3277         if (option == INTENT_PERCEPTUAL) current = 0;
3278         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3279         if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3280         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3281         if (option == INTENT_SATURATION) current = 2;
3282         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3283         if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3284
3285         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3286
3287         gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3288
3289         g_signal_connect(G_OBJECT(combo), "changed",
3290                          G_CALLBACK(intent_menu_cb), option_c);
3291
3292         gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
3293         gtk_widget_show(combo);
3294 }
3295 #endif
3296
3297 static void config_tab_color(GtkWidget *notebook)
3298 {
3299         GtkWidget *label;
3300         GtkWidget *vbox;
3301         GtkWidget *group;
3302         GtkWidget *tabcomp;
3303         GtkWidget *table;
3304         gint i;
3305
3306         vbox = scrolled_notebook_page(notebook, _("Color management"));
3307
3308         group =  pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3309 #ifndef HAVE_LCMS
3310         gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3311 #endif
3312
3313         table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3314         gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3315
3316         label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3317         pref_label_bold(label, TRUE, FALSE);
3318
3319         label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3320         pref_label_bold(label, TRUE, FALSE);
3321
3322         label = pref_table_label(table, 2, 0, _("File"), 0.0);
3323         pref_label_bold(label, TRUE, FALSE);
3324
3325         for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3326                 {
3327                 GtkWidget *entry;
3328                 gchar *buf;
3329
3330                 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3331                 pref_table_label(table, 0, i + 1, buf, 1.0);
3332                 g_free(buf);
3333
3334                 entry = gtk_entry_new();
3335                 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3336                 if (options->color_profile.input_name[i])
3337                         {
3338                         gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3339                         }
3340                 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3341                                  GTK_FILL | GTK_EXPAND, 0, 0, 0);
3342                 gtk_widget_show(entry);
3343                 color_profile_input_name_entry[i] = entry;
3344
3345                 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3346                 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3347                 gtk_widget_set_size_request(entry, 160, -1);
3348                 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3349                                  GTK_FILL | GTK_EXPAND, 0, 0, 0);
3350                 gtk_widget_show(tabcomp);
3351                 color_profile_input_file_entry[i] = entry;
3352                 }
3353
3354         group =  pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3355 #ifndef HAVE_LCMS
3356         gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3357 #endif
3358         pref_checkbox_new_int(group, _("Use system screen profile if available"),
3359                               options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3360
3361         table = pref_table_new(group, 2, 1, FALSE, FALSE);
3362
3363         pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3364         tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3365                                      options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3366         tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3367         gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3368 #ifdef HAVE_LCMS
3369         add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3370 #endif
3371         gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3372                          0, 1,
3373                          GTK_FILL | GTK_EXPAND, 0, 0, 0);
3374
3375         gtk_widget_show(tabcomp);
3376 }
3377
3378 /* advanced entry tab */
3379 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer data)
3380 {
3381         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3382                 {
3383                 c_options->file_ops.use_system_trash = FALSE;
3384                 c_options->file_ops.no_trash = FALSE;
3385                 }
3386 }
3387
3388 static void use_system_trash_cb(GtkWidget *widget, gpointer data)
3389 {
3390         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3391                 {
3392                 c_options->file_ops.use_system_trash = TRUE;
3393                 c_options->file_ops.no_trash = FALSE;
3394                 }
3395 }
3396
3397 static void use_no_cache_cb(GtkWidget *widget, gpointer data)
3398 {
3399         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3400                 {
3401                 c_options->file_ops.no_trash = TRUE;
3402                 }
3403 }
3404
3405 static void config_tab_behavior(GtkWidget *notebook)
3406 {
3407         GtkWidget *hbox;
3408         GtkWidget *vbox;
3409         GtkWidget *group;
3410         GtkWidget *button;
3411         GtkWidget *tabcomp;
3412         GtkWidget *ct_button;
3413         GtkWidget *spin;
3414         GtkWidget *table;
3415         GtkWidget *marks;
3416         GtkWidget *with_rename;
3417         GtkWidget *collections_on_top;
3418         GtkWidget *hide_window_in_fullscreen;
3419         GtkWidget *checkbox;
3420         GtkWidget *tmp;
3421
3422         vbox = scrolled_notebook_page(notebook, _("Behavior"));
3423
3424         group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3425
3426         pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3427                               options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3428         pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3429                               options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3430         pref_checkbox_new_int(group, _("Enable Delete key"),
3431                               options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3432
3433         ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3434                                         !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3435
3436         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3437         pref_checkbox_link_sensitivity(ct_button, hbox);
3438
3439         pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3440         pref_label_new(hbox, _("Folder:"));
3441
3442         tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3443         tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3444         gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3445         gtk_widget_show(tabcomp);
3446
3447         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3448         pref_checkbox_link_sensitivity(ct_button, hbox);
3449
3450         pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3451         spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MiB"),
3452                                  0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3453         gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3454         button = pref_button_new(NULL, NULL, _("View"), FALSE,
3455                                  G_CALLBACK(safe_delete_view_cb), NULL);
3456         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3457         gtk_widget_show(button);
3458
3459         button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3460                                  G_CALLBACK(safe_delete_clear_cb), NULL);
3461         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3462         pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3463                                         options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3464
3465         pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3466                         options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3467
3468         gtk_widget_show(button);
3469
3470         pref_spacer(group, PREF_PAD_GROUP);
3471
3472
3473         group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3474
3475         pref_checkbox_new_int(group, _("Descend folders in tree view"),
3476                               options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3477
3478         pref_checkbox_new_int(group, _("In place renaming"),
3479                               options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3480
3481         pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3482                               options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3483
3484         tmp = pref_checkbox_new_int(group, _("Circular selection lists"),
3485                               options->circular_selection_lists, &c_options->circular_selection_lists);
3486         gtk_widget_set_tooltip_text(tmp, _("Traverse selection lists in a circular manner"));
3487
3488         marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3489                                 options->marks_save, &c_options->marks_save);
3490         gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3491
3492         with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3493                                 options->with_rename, &c_options->with_rename);
3494         gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3495
3496         collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3497                                 options->collections_on_top, &c_options->collections_on_top);
3498         gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3499
3500         hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3501                                 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3502         gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice");
3503
3504         pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3505                           1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3506
3507         pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3508                           16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3509
3510         table = pref_table_new(group, 2, 1, FALSE, FALSE);
3511         add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3512
3513         table = pref_table_new(group, 2, 1, FALSE, FALSE);
3514         add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3515
3516         pref_spacer(group, PREF_PAD_GROUP);
3517
3518         group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3519
3520         pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3521                               options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3522         pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3523                           1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3524         pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3525                               options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3526         pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3527                               options->image_lm_click_nav, &c_options->image_lm_click_nav);
3528         pref_checkbox_new_int(group, _("Open archive by left click on image"),
3529                               options->image_l_click_archive, &c_options->image_l_click_archive);
3530         pref_checkbox_new_int(group, _("Play video by left click on image"),
3531                               options->image_l_click_video, &c_options->image_l_click_video);
3532         table = pref_table_new(group, 2, 1, FALSE, FALSE);
3533         add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3534
3535         table = pref_table_new(group, 2, 1, FALSE, FALSE);
3536         table = pref_table_new(group, 2, 1, FALSE, FALSE);
3537         add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3538         table = pref_table_new(group, 2, 1, FALSE, FALSE);
3539         add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3540
3541         pref_spacer(group, PREF_PAD_GROUP);
3542
3543         group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3544
3545         checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3546                                 options->override_disable_gpu, &c_options->override_disable_gpu);
3547         gtk_widget_set_tooltip_text(checkbox, "Contact the developers for usage");
3548
3549 #ifdef DEBUG
3550         pref_spacer(group, PREF_PAD_GROUP);
3551
3552         group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3553
3554         pref_spin_new_int(group, _("Debug level:"), NULL,
3555                           DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3556
3557         pref_checkbox_new_int(group, _("Timer data"),
3558                         options->log_window.timer_data, &c_options->log_window.timer_data);
3559
3560         pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3561                           1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3562 #endif
3563 }
3564
3565 /* accelerators tab */
3566 static void config_tab_accelerators(GtkWidget *notebook)
3567 {
3568         GtkWidget *hbox;
3569         GtkWidget *vbox;
3570         GtkWidget *group;
3571         GtkWidget *button;
3572         GtkWidget *scrolled;
3573         GtkWidget *accel_view;
3574         GtkCellRenderer *renderer;
3575         GtkTreeSelection *selection;
3576         GtkTreeViewColumn *column;
3577
3578         vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3579
3580         group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3581
3582         scrolled = gtk_scrolled_window_new(NULL, NULL);
3583         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3584         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3585         gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3586         gtk_widget_show(scrolled);
3587
3588         accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3589
3590         accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3591         g_object_unref(accel_store);
3592         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3593         gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3594
3595         gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3596
3597         renderer = gtk_cell_renderer_text_new();
3598
3599         column = gtk_tree_view_column_new_with_attributes(_("Action"),
3600                                                           renderer,
3601                                                           "text", AE_ACTION,
3602                                                           NULL);
3603
3604         gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3605         gtk_tree_view_column_set_resizable(column, TRUE);
3606         gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3607
3608
3609         renderer = gtk_cell_renderer_accel_new();
3610         g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3611                          G_CALLBACK(accel_store_cleared_cb), accel_store);
3612         g_signal_connect(G_OBJECT(renderer), "accel-edited",
3613                          G_CALLBACK(accel_store_edited_cb), accel_store);
3614
3615
3616         g_object_set (renderer,
3617                       "editable", TRUE,
3618                       "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3619                       NULL);
3620
3621         column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3622                                                           renderer,
3623                                                           "text", AE_KEY,
3624                                                           NULL);
3625
3626         gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3627         gtk_tree_view_column_set_resizable(column, TRUE);
3628         gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3629
3630         renderer = gtk_cell_renderer_text_new();
3631
3632         column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3633                                                           renderer,
3634                                                           "text", AE_TOOLTIP,
3635                                                           NULL);
3636
3637         gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3638         gtk_tree_view_column_set_resizable(column, TRUE);
3639         gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3640
3641         renderer = gtk_cell_renderer_text_new();
3642
3643         column = gtk_tree_view_column_new_with_attributes("Accel",
3644                                                           renderer,
3645                                                           "text", AE_ACCEL,
3646                                                           NULL);
3647
3648         gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3649         gtk_tree_view_column_set_resizable(column, TRUE);
3650         gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3651
3652         accel_store_populate();
3653         gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3654         gtk_widget_show(accel_view);
3655
3656         hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3657
3658         button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3659                                  G_CALLBACK(accel_default_cb), accel_view);
3660         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3661         gtk_widget_show(button);
3662
3663         button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3664                                  G_CALLBACK(accel_reset_cb), accel_view);
3665         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3666         gtk_widget_show(button);
3667 }
3668
3669 /* toolbar main tab */
3670 static void config_tab_toolbar_main(GtkWidget *notebook)
3671 {
3672         GtkWidget *vbox;
3673         GtkWidget *toolbardata;
3674         LayoutWindow *lw;
3675
3676         lw = layout_window_list->data;
3677
3678         vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3679
3680         toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3681         gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3682         gtk_widget_show(vbox);
3683 }
3684
3685 /* toolbar status tab */
3686 static void config_tab_toolbar_status(GtkWidget *notebook)
3687 {
3688         GtkWidget *vbox;
3689         GtkWidget *toolbardata;
3690         LayoutWindow *lw;
3691
3692         lw = layout_window_list->data;
3693
3694         vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3695
3696         toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3697         gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3698         gtk_widget_show(vbox);
3699 }
3700
3701 /* advanced tab */
3702 static gint extension_sort_cb(gconstpointer a, gconstpointer b)
3703 {
3704         return g_strcmp0((gchar *)a, (gchar *)b);
3705 }
3706
3707 static void config_tab_advanced(GtkWidget *notebook)
3708 {
3709         GtkWidget *vbox;
3710         GtkWidget *group;
3711         GSList *formats_list;
3712         GList *extensions_list = NULL;
3713         gchar **extensions;
3714         GtkWidget *tabcomp;
3715         GdkPixbufFormat *fm;
3716         gint i;
3717         GString *types_string = g_string_new(NULL);
3718         GtkWidget *types_string_label;
3719         GtkWidget *threads_string_label;
3720         GtkWidget *dupes_threads_spin;
3721
3722         vbox = scrolled_notebook_page(notebook, _("Advanced"));
3723         group = pref_group_new(vbox, FALSE, _("External preview extraction"), GTK_ORIENTATION_VERTICAL);
3724
3725         pref_checkbox_new_int(group, _("Use external preview extraction -  Requires restart"), options->external_preview.enable, &c_options->external_preview.enable);
3726
3727         pref_spacer(group, PREF_PAD_GROUP);
3728
3729         formats_list = gdk_pixbuf_get_formats();
3730
3731         while (formats_list)
3732                 {
3733                 fm = formats_list->data;
3734                 extensions = gdk_pixbuf_format_get_extensions(fm);
3735
3736                 i = 0;
3737                 while (extensions[i])
3738                         {
3739                         extensions_list = g_list_insert_sorted(extensions_list, g_strdup(extensions[i]), extension_sort_cb);
3740                         i++;
3741                         }
3742
3743                 g_strfreev(extensions);
3744                 formats_list = formats_list->next;
3745                 }
3746
3747         while (extensions_list)
3748                 {
3749                 if (types_string->len == 0)
3750                         {
3751                         types_string = g_string_append(types_string, extensions_list->data);
3752                         }
3753                 else
3754                         {
3755                         types_string = g_string_append(types_string, ", ");
3756                         types_string = g_string_append(types_string, extensions_list->data);
3757                         }
3758
3759                 extensions_list = extensions_list->next;
3760                 }
3761
3762         types_string = g_string_prepend(types_string, _("Usable file types:\n"));
3763         types_string_label = pref_label_new(group, types_string->str);
3764         gtk_label_set_line_wrap(GTK_LABEL(types_string_label), TRUE);
3765
3766         pref_spacer(group, PREF_PAD_GROUP);
3767
3768         group = pref_group_new(vbox, FALSE, _("File identification tool"), GTK_ORIENTATION_VERTICAL);
3769         external_preview_select_entry = gtk_entry_new();
3770         tabcomp = tab_completion_new(&external_preview_select_entry, options->external_preview.select, NULL, NULL, NULL, NULL);
3771         tab_completion_add_select_button(external_preview_select_entry, _("Select file identification tool"), FALSE);
3772         gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3773         gtk_widget_show(tabcomp);
3774
3775         group = pref_group_new(vbox, FALSE, _("Preview extraction tool"), GTK_ORIENTATION_VERTICAL);
3776         external_preview_extract_entry = gtk_entry_new();
3777         tabcomp = tab_completion_new(&external_preview_extract_entry, options->external_preview.extract, NULL, NULL, NULL, NULL);
3778         tab_completion_add_select_button(external_preview_extract_entry, _("Select preview extraction tool"), FALSE);
3779         gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3780         gtk_widget_show(tabcomp);
3781
3782         gtk_widget_show(vbox);
3783
3784         g_slist_free(formats_list);
3785         string_list_free(extensions_list);
3786         g_string_free(types_string, TRUE);
3787
3788         pref_spacer(group, PREF_PAD_GROUP);
3789
3790         pref_line(vbox, PREF_PAD_SPACE);
3791         group = pref_group_new(vbox, FALSE, _("Thread pool limits"), GTK_ORIENTATION_VERTICAL);
3792
3793         threads_string_label = pref_label_new(group, "This option limits the number of threads (or cpu cores)\nthat Geeqie will use when running duplicate checks. The default value is 0, which means all available cores will be used.");
3794         gtk_label_set_line_wrap(GTK_LABEL(threads_string_label), TRUE);
3795
3796         pref_spacer(vbox, PREF_PAD_GROUP);
3797
3798         dupes_threads_spin = pref_spin_new_int(vbox, _("Duplicate check:"), _("max. threads"), 0, get_cpu_cores(), 1, options->threads.duplicates, &c_options->threads.duplicates);
3799         gtk_widget_set_tooltip_markup(dupes_threads_spin, _("Set to 0 for unlimited"));
3800 }
3801
3802 /* stereo tab */
3803 static void config_tab_stereo(GtkWidget *notebook)
3804 {
3805         GtkWidget *vbox;
3806         GtkWidget *group;
3807         GtkWidget *group2;
3808         GtkWidget *table;
3809         GtkWidget *box;
3810         GtkWidget *box2;
3811         GtkWidget *fs_button;
3812         vbox = scrolled_notebook_page(notebook, _("Stereo"));
3813
3814         group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3815
3816         table = pref_table_new(group, 2, 1, FALSE, FALSE);
3817         add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3818
3819         table = pref_table_new(group, 2, 2, TRUE, FALSE);
3820         box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3821         pref_checkbox_new_int(box, _("Mirror left image"),
3822                               options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3823         box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3824         pref_checkbox_new_int(box, _("Flip left image"),
3825                               options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3826         box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3827         pref_checkbox_new_int(box, _("Mirror right image"),
3828                               options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3829         box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3830         pref_checkbox_new_int(box, _("Flip right image"),
3831                               options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3832         pref_checkbox_new_int(group, _("Swap left and right images"),
3833                               options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3834         pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3835                               options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3836
3837         group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3838         fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3839                               options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3840         box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3841         pref_checkbox_link_sensitivity(fs_button, box2);
3842         table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3843         add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3844         table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3845         box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3846         pref_checkbox_new_int(box, _("Mirror left image"),
3847                               options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3848         box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3849         pref_checkbox_new_int(box, _("Flip left image"),
3850                               options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3851         box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3852         pref_checkbox_new_int(box, _("Mirror right image"),
3853                               options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3854         box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3855         pref_checkbox_new_int(box, _("Flip right image"),
3856                               options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3857         pref_checkbox_new_int(box2, _("Swap left and right images"),
3858                               options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3859         pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3860                               options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3861
3862         group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3863         table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3864         pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3865                           1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3866         pref_table_spin_new_int(table, 3, 0,  _("Height"), NULL,
3867                           1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3868         pref_table_spin_new_int(table, 0, 1,  _("Left X"), NULL,
3869                           0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3870         pref_table_spin_new_int(table, 3, 1,  _("Left Y"), NULL,
3871                           0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3872         pref_table_spin_new_int(table, 0, 2,  _("Right X"), NULL,
3873                           0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3874         pref_table_spin_new_int(table, 3, 2,  _("Right Y"), NULL,
3875                           0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3876
3877 }
3878
3879 /* Main preferences window */
3880 static void config_window_create(LayoutWindow *lw)
3881 {
3882         GtkWidget *win_vbox;
3883         GtkWidget *hbox;
3884         GtkWidget *notebook;
3885         GtkWidget *button;
3886         GtkWidget *ct_button;
3887
3888         if (!c_options) c_options = init_options(NULL);
3889
3890         configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3891         DEBUG_NAME(configwindow);
3892         gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3893         g_signal_connect(G_OBJECT(configwindow), "delete_event",
3894                          G_CALLBACK(config_window_delete), NULL);
3895         if (options->save_dialog_window_positions)
3896                 {
3897                 gtk_window_resize(GTK_WINDOW(configwindow), lw->options.preferences_window.w, lw->options.preferences_window.h);
3898                 gtk_window_move(GTK_WINDOW(configwindow), lw->options.preferences_window.x, lw->options.preferences_window.y);
3899                 }
3900         else
3901                 {
3902                 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
3903                 }
3904         gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
3905         gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
3906
3907         win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
3908         gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
3909         gtk_widget_show(win_vbox);
3910
3911         notebook = gtk_notebook_new();
3912         gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
3913         gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
3914         gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
3915
3916         config_tab_general(notebook);
3917         config_tab_image(notebook);
3918         config_tab_osd(notebook);
3919         config_tab_windows(notebook);
3920         config_tab_accelerators(notebook);
3921         config_tab_files(notebook);
3922         config_tab_metadata(notebook);
3923         config_tab_keywords(notebook);
3924         config_tab_color(notebook);
3925         config_tab_stereo(notebook);
3926         config_tab_behavior(notebook);
3927         config_tab_toolbar_main(notebook);
3928         config_tab_toolbar_status(notebook);
3929         config_tab_advanced(notebook);
3930
3931         gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), lw->options.preferences_window.page_number);
3932
3933         hbox = gtk_hbutton_box_new();
3934         gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
3935         gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
3936         gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
3937         gtk_widget_show(hbox);
3938
3939         button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
3940                                  G_CALLBACK(config_window_help_cb), notebook);
3941         gtk_container_add(GTK_CONTAINER(hbox), button);
3942         gtk_widget_set_can_default(button, TRUE);
3943         gtk_widget_show(button);
3944
3945         button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
3946                                  G_CALLBACK(config_window_ok_cb), notebook);
3947         gtk_container_add(GTK_CONTAINER(hbox), button);
3948         gtk_widget_set_can_default(button, TRUE);
3949         gtk_widget_grab_default(button);
3950         gtk_widget_show(button);
3951
3952         ct_button = button;
3953
3954         button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
3955                                  G_CALLBACK(config_window_close_cb), NULL);
3956         gtk_container_add(GTK_CONTAINER(hbox), button);
3957         gtk_widget_set_can_default(button, TRUE);
3958         gtk_widget_show(button);
3959
3960         if (!generic_dialog_get_alternative_button_order(configwindow))
3961                 {
3962                 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
3963                 }
3964
3965         gtk_widget_show(notebook);
3966
3967         gtk_widget_show(configwindow);
3968 }
3969
3970 /*
3971  *-----------------------------------------------------------------------------
3972  * config window show (public)
3973  *-----------------------------------------------------------------------------
3974  */
3975
3976 void show_config_window(LayoutWindow *lw)
3977 {
3978         if (configwindow)
3979                 {
3980                 gtk_window_present(GTK_WINDOW(configwindow));
3981                 return;
3982                 }
3983
3984         config_window_create(lw);
3985 }
3986
3987 /*
3988  *-----------------
3989  * about window
3990  *-----------------
3991  */
3992
3993 void show_about_window(LayoutWindow *lw)
3994 {
3995         GdkPixbuf *pixbuf_logo;
3996         GdkPixbuf *pixbuf_icon;
3997         gchar *authors[1000];
3998         gchar *comment;
3999         gint i_authors = 0;
4000         gchar *path;
4001         GString *copyright;
4002         gchar *timezone_path;
4003         gchar *basename;
4004         ZoneDetect *cd;
4005         FILE *fp = NULL;
4006 #define LINE_LENGTH 1000
4007         gchar line[LINE_LENGTH];
4008
4009         copyright = g_string_new(NULL);
4010         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");
4011
4012         path = path_from_utf8(TIMEZONE_DATABASE);
4013         basename = g_path_get_basename(path);
4014         timezone_path = g_build_filename(get_rc_dir(), basename, NULL);
4015         if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
4016                 {
4017                 cd = ZDOpenDatabase(timezone_path);
4018                 if (cd)
4019                         {
4020                         copyright = g_string_append(copyright, ZDGetNotice(cd));
4021                         ZDCloseDatabase(cd);
4022                         }
4023                 }
4024         g_free(path);
4025         g_free(timezone_path);
4026         g_free(basename);
4027
4028         authors[0] = NULL;
4029         path = g_build_filename(gq_helpdir, "AUTHORS", NULL);
4030         fp = fopen(path, "r");
4031         if (fp)
4032                 {
4033                 while(fgets(line, LINE_LENGTH, fp))
4034                         {
4035                         /* get rid of ending \n from fgets */
4036                         line[strlen(line) - 1] = '\0';
4037                         authors[i_authors] = g_strdup(line);
4038                         i_authors++;
4039                         }
4040                 authors[i_authors] = NULL;
4041                 fclose(fp);
4042                 }
4043         g_free(path);
4044
4045         comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
4046                                                 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
4047
4048         pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
4049         pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
4050         gtk_show_about_dialog(GTK_WINDOW(lw->window),
4051                 "title", _("About Geeqie"),
4052                 "resizable", TRUE,
4053                 "program-name", GQ_APPNAME,
4054                 "version", VERSION,
4055                 "logo", pixbuf_logo,
4056                 "icon", pixbuf_icon,
4057                 "website", GQ_WEBSITE,
4058                 "website-label", "Website",
4059                 "comments", comment,
4060                 "authors", authors,
4061                 "translator-credits", _("translator-credits"),
4062                 "wrap-license", TRUE,
4063                 "license", copyright->str,
4064                 NULL);
4065
4066         g_string_free(copyright, TRUE);
4067
4068         gint n = 0;
4069         while(n < i_authors)
4070                 {
4071                 g_free(authors[n]);
4072                 n++;
4073                 }
4074         g_free(comment);
4075
4076         return;
4077 }
4078
4079 static void image_overlay_set_text_colours()
4080 {
4081         c_options->image_overlay.text_red = options->image_overlay.text_red;
4082         c_options->image_overlay.text_green = options->image_overlay.text_green;
4083         c_options->image_overlay.text_blue = options->image_overlay.text_blue;
4084         c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
4085         c_options->image_overlay.background_red = options->image_overlay.background_red;
4086         c_options->image_overlay.background_green = options->image_overlay.background_green;
4087         c_options->image_overlay.background_blue = options->image_overlay.background_blue;
4088         c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
4089 }
4090
4091 /*
4092  *-----------------------------------------------------------------------------
4093  * timezone database routines
4094  *-----------------------------------------------------------------------------
4095  */
4096
4097 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
4098 {
4099         GError *error = NULL;
4100         TZData *tz = data;
4101         gchar *tmp_filename;
4102
4103         if (!g_cancellable_is_cancelled(tz->cancellable))
4104                 {
4105                 generic_dialog_close(tz->gd);
4106                 }
4107
4108
4109         if (g_file_copy_finish(G_FILE(source_object), res, &error))
4110                 {
4111                 tmp_filename = g_file_get_parse_name(tz->tmp_g_file);
4112                 move_file(tmp_filename, tz->timezone_database_user);
4113                 g_free(tmp_filename);
4114                 }
4115         else
4116                 {
4117                 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4118                 }
4119
4120         g_file_delete(tz->tmp_g_file, NULL, &error);
4121         g_object_unref(tz->tmp_g_file);
4122         tz->tmp_g_file = NULL;
4123         g_object_unref(tz->cancellable);
4124         g_object_unref(tz->timezone_database_gq);
4125 }
4126
4127 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
4128 {
4129         TZData *tz = data;
4130
4131         if (!g_cancellable_is_cancelled(tz->cancellable))
4132                 {
4133                 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
4134                 }
4135 }
4136
4137 static void timezone_cancel_button_cb(GenericDialog *gd, gpointer data)
4138 {
4139         TZData *tz = data;
4140
4141         g_cancellable_cancel(tz->cancellable);
4142 }
4143
4144 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
4145 {
4146         TZData *tz = data;
4147         GError *error = NULL;
4148         GFileIOStream *io_stream;
4149
4150         if (tz->tmp_g_file)
4151                 {
4152                 return;
4153                 }
4154
4155         tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
4156
4157         if (error)
4158                 {
4159                 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4160                 log_printf("Error: Download timezone database failed:\n%s", error->message);
4161                 g_error_free(error);
4162                 g_object_unref(tz->tmp_g_file);
4163                 }
4164         else
4165                 {
4166                 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE);
4167
4168                 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
4169
4170                 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
4171
4172                 tz->progress = gtk_progress_bar_new();
4173                 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
4174                 gtk_widget_show(tz->progress);
4175
4176                 gtk_widget_show(tz->gd->dialog);
4177                 tz->cancellable = g_cancellable_new();
4178                 g_file_copy_async(tz->timezone_database_gq, tz->tmp_g_file, G_FILE_COPY_OVERWRITE, G_PRIORITY_LOW, tz->cancellable, timezone_progress_cb, tz, timezone_async_ready_cb, tz);
4179
4180                 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
4181                 }
4182 }
4183 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */