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