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