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