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