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