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