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