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