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