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