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