2 * Copyright (C) 2006 John Ellis
3 * Copyright (C) 2008 - 2016 The Geeqie Team
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.
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.
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.
23 #include "preferences.h"
26 #include "bar_keywords.h"
28 #include "cache_maint.h"
33 #include "filefilter.h"
34 #include "fullscreen.h"
36 #include "image-overlay.h"
37 #include "color-man.h"
39 #include "layout_config.h"
40 #include "layout_util.h"
43 #include "pixbuf_util.h"
44 #include "slideshow.h"
48 #include "ui_fileops.h"
50 #include "ui_spinner.h"
51 #include "ui_tabcomp.h"
52 #include "ui_utildlg.h"
54 #include "zonedetect.h"
64 #define EDITOR_NAME_MAX_LENGTH 32
65 #define EDITOR_COMMAND_MAX_LENGTH 1024
67 static void image_overlay_set_text_colours();
69 GtkWidget *keyword_text;
70 static void config_tab_keywords_save();
72 typedef struct _ThumbSize ThumbSize;
79 static ThumbSize thumb_size_list[] =
113 gchar *format_class_list[] = {
123 /* config memory values */
124 static ConfOptions *c_options = NULL;
131 static GtkWidget *configwindow = NULL;
132 static GtkListStore *filter_store = NULL;
133 static GtkTreeStore *accel_store = NULL;
135 static GtkWidget *safe_delete_path_entry;
137 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
138 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
139 static GtkWidget *color_profile_screen_file_entry;
141 static GtkWidget *sidecar_ext_entry;
142 static GtkWidget *help_search_engine_entry;
145 #define CONFIG_WINDOW_DEF_WIDTH 700
146 #define CONFIG_WINDOW_DEF_HEIGHT 600
149 *-----------------------------------------------------------------------------
150 * option widget callbacks (private)
151 *-----------------------------------------------------------------------------
154 static void zoom_increment_cb(GtkWidget *spin, gpointer data)
156 c_options->image.zoom_increment = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
159 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer data)
161 gint mins_secs_tenths, delay;
163 mins_secs_tenths = c_options->slideshow.delay %
164 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
166 delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
167 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
170 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
171 SLIDESHOW_SUBSECOND_PRECISION;
174 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer data)
176 gint hours, secs_tenths, delay;
178 hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
179 secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
181 delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
182 (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
183 (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
185 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
186 SLIDESHOW_SUBSECOND_PRECISION;
189 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer data)
191 gint hours_mins, delay;
193 hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
195 delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
196 (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
197 (gdouble)(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
199 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
200 SLIDESHOW_SUBSECOND_PRECISION;
204 *-----------------------------------------------------------------------------
205 * sync progam to config window routine (private)
206 *-----------------------------------------------------------------------------
209 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
215 buf = gtk_entry_get_text(GTK_ENTRY(entry));
216 if (buf && strlen(buf) > 0)
221 *option = g_strdup(buf);
226 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
228 gchar *accel_path, *accel;
230 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
232 if (accel_path && accel_path[0])
235 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
236 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
246 static void config_window_apply(void)
248 gboolean refresh = FALSE;
253 config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
255 if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
256 if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
257 if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
258 if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
259 if (options->file_sort.natural != c_options->file_sort.natural) refresh = TRUE;
260 if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
261 if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
263 options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
264 options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
265 options->file_ops.confirm_move_to_trash = c_options->file_ops.confirm_move_to_trash;
266 options->file_ops.use_system_trash = c_options->file_ops.use_system_trash;
267 options->file_ops.no_trash = c_options->file_ops.no_trash;
268 options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
269 options->tools_restore_state = c_options->tools_restore_state;
270 options->save_window_positions = c_options->save_window_positions;
271 options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
272 options->save_window_workspace = c_options->save_window_workspace;
273 options->save_dialog_window_positions = c_options->save_dialog_window_positions;
274 options->show_window_ids = c_options->show_window_ids;
275 options->image.scroll_reset_method = c_options->image.scroll_reset_method;
276 options->image.zoom_2pass = c_options->image.zoom_2pass;
277 options->image.fit_window_to_image = c_options->image.fit_window_to_image;
278 options->image.limit_window_size = c_options->image.limit_window_size;
279 options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
280 options->image.max_window_size = c_options->image.max_window_size;
281 options->image.limit_autofit_size = c_options->image.limit_autofit_size;
282 options->image.max_autofit_size = c_options->image.max_autofit_size;
283 options->image.max_enlargement_size = c_options->image.max_enlargement_size;
284 options->image.use_clutter_renderer = c_options->image.use_clutter_renderer;
285 options->progressive_key_scrolling = c_options->progressive_key_scrolling;
286 options->keyboard_scroll_step = c_options->keyboard_scroll_step;
288 if (options->thumbnails.max_width != c_options->thumbnails.max_width
289 || options->thumbnails.max_height != c_options->thumbnails.max_height
290 || options->thumbnails.quality != c_options->thumbnails.quality)
292 thumb_format_changed = TRUE;
294 options->thumbnails.max_width = c_options->thumbnails.max_width;
295 options->thumbnails.max_height = c_options->thumbnails.max_height;
296 options->thumbnails.quality = c_options->thumbnails.quality;
298 options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
299 options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
300 options->thumbnails.use_exif = c_options->thumbnails.use_exif;
301 options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
302 options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
303 // options->thumbnails.use_ft_metadata_small = c_options->thumbnails.use_ft_metadata_small;
304 options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
305 options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
306 options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
307 options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
308 options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
309 options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
311 options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
312 options->file_sort.natural = c_options->file_sort.natural;
313 options->file_filter.disable = c_options->file_filter.disable;
315 config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, NULL);
316 sidecar_ext_parse(options->sidecar.ext);
318 options->slideshow.random = c_options->slideshow.random;
319 options->slideshow.repeat = c_options->slideshow.repeat;
320 options->slideshow.delay = c_options->slideshow.delay;
322 options->mousewheel_scrolls = c_options->mousewheel_scrolls;
323 options->image_lm_click_nav = c_options->image_lm_click_nav;
324 options->image_l_click_video = c_options->image_l_click_video;
325 options->image_l_click_video_editor = c_options->image_l_click_video_editor;
327 options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
329 options->image.tile_cache_max = c_options->image.tile_cache_max;
330 options->image.image_cache_max = c_options->image.image_cache_max;
332 options->image.zoom_quality = c_options->image.zoom_quality;
334 options->image.zoom_increment = c_options->image.zoom_increment;
336 options->image.enable_read_ahead = c_options->image.enable_read_ahead;
339 if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
340 || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
341 || !gdk_color_equal(&options->image.border_color, &c_options->image.border_color))
343 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
344 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
345 options->image.border_color = c_options->image.border_color;
346 layout_colors_update();
347 view_window_colors_update();
350 options->image.alpha_color_1 = c_options->image.alpha_color_1;
351 options->image.alpha_color_2 = c_options->image.alpha_color_2;
353 options->fullscreen.screen = c_options->fullscreen.screen;
354 options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
355 options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
356 options->fullscreen.above = c_options->fullscreen.above;
357 if (c_options->image_overlay.template_string)
358 set_image_overlay_template_string(&options->image_overlay.template_string,
359 c_options->image_overlay.template_string);
360 if (c_options->image_overlay.font)
361 set_image_overlay_font_string(&options->image_overlay.font,
362 c_options->image_overlay.font);
363 options->image_overlay.text_red = c_options->image_overlay.text_red;
364 options->image_overlay.text_green = c_options->image_overlay.text_green;
365 options->image_overlay.text_blue = c_options->image_overlay.text_blue;
366 options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
367 options->image_overlay.background_red = c_options->image_overlay.background_red;
368 options->image_overlay.background_green = c_options->image_overlay.background_green;
369 options->image_overlay.background_blue = c_options->image_overlay.background_blue;
370 options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
371 options->update_on_time_change = c_options->update_on_time_change;
372 options->image.exif_proof_rotate_enable = c_options->image.exif_proof_rotate_enable;
374 options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
375 options->rot_invariant_sim = c_options->rot_invariant_sim;
377 options->tree_descend_subdirs = c_options->tree_descend_subdirs;
379 options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
381 options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
382 options->dnd_icon_size = c_options->dnd_icon_size;
383 options->clipboard_selection = c_options->clipboard_selection;
384 options->dnd_default_action = c_options->dnd_default_action;
386 options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
387 options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
388 options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
389 options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
390 options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
391 options->metadata.confirm_write = c_options->metadata.confirm_write;
392 options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
393 options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
394 options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
395 options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
396 options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
397 options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
398 options->metadata.write_orientation = c_options->metadata.write_orientation;
399 options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
400 (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
401 (c_options->stereo.tmp.flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
402 (c_options->stereo.tmp.mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
403 (c_options->stereo.tmp.flip_left ? PR_STEREO_FLIP_LEFT : 0) |
404 (c_options->stereo.tmp.swap ? PR_STEREO_SWAP : 0) |
405 (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
406 options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
407 (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
408 (c_options->stereo.tmp.fs_flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
409 (c_options->stereo.tmp.fs_mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
410 (c_options->stereo.tmp.fs_flip_left ? PR_STEREO_FLIP_LEFT : 0) |
411 (c_options->stereo.tmp.fs_swap ? PR_STEREO_SWAP : 0) |
412 (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
413 options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
414 options->stereo.fixed_w = c_options->stereo.fixed_w;
415 options->stereo.fixed_h = c_options->stereo.fixed_h;
416 options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
417 options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
418 options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
419 options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
421 options->info_keywords.height = c_options->info_keywords.height;
422 options->info_title.height = c_options->info_title.height;
423 options->info_comment.height = c_options->info_comment.height;
424 options->info_rating.height = c_options->info_rating.height;
426 options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
427 options->expand_menu_toolbar = c_options->expand_menu_toolbar;
429 options->marks_save = c_options->marks_save;
430 options->with_rename = c_options->with_rename;
431 options->collections_on_top = c_options->collections_on_top;
432 options->hide_window_in_fullscreen = c_options->hide_window_in_fullscreen;
433 config_entry_to_option(help_search_engine_entry, &options->help_search_engine, NULL);
435 options->read_metadata_in_idle = c_options->read_metadata_in_idle;
437 options->star_rating.star = c_options->star_rating.star;
438 options->star_rating.rejected = c_options->star_rating.rejected;
440 set_debug_level(debug_c);
444 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
446 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
447 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
449 config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
450 options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
451 if (options->color_profile.render_intent != c_options->color_profile.render_intent)
453 options->color_profile.render_intent = c_options->color_profile.render_intent;
458 options->mouse_button_8 = c_options->mouse_button_8;
459 options->mouse_button_9 = c_options->mouse_button_9;
461 options->override_disable_gpu = c_options->override_disable_gpu;
463 config_tab_keywords_save();
465 image_options_sync();
470 layout_refresh(NULL);
473 if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, NULL);
475 toolbar_apply(TOOLBAR_MAIN);
476 toolbar_apply(TOOLBAR_STATUS);
480 *-----------------------------------------------------------------------------
481 * config window main button callbacks (private)
482 *-----------------------------------------------------------------------------
485 static void config_window_close_cb(GtkWidget *widget, gpointer data)
487 gtk_widget_destroy(configwindow);
492 static void config_window_help_cb(GtkWidget *widget, gpointer data)
494 GtkWidget *notebook = data;
497 static gchar *html_section[] =
499 "GuideOptionsGeneral.html",
500 "GuideOptionsImage.html",
501 "GuideOptionsOSD.html",
502 "GuideOptionsWindow.html",
503 "GuideOptionsKeyboard.html",
504 "GuideOptionsFiltering.html",
505 "GuideOptionsMetadata.html",
506 "GuideOptionsKeywords.html",
507 "GuideOptionsColor.html",
508 "GuideOptionsStereo.html",
509 "GuideOptionsBehavior.html",
510 "GuideOptionsToolbar.html",
511 "GuideOptionsToolbar.html"
514 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
515 help_window_show(html_section[i]);
518 static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpointer data)
520 config_window_close_cb(NULL, NULL);
524 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
527 lw = layout_window_list->data;
529 config_window_apply();
530 layout_util_sync(lw);
531 save_options(options);
532 config_window_close_cb(NULL, NULL);
536 *-----------------------------------------------------------------------------
537 * config window setup (private)
538 *-----------------------------------------------------------------------------
541 static void quality_menu_cb(GtkWidget *combo, gpointer data)
545 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
549 *option = GDK_INTERP_NEAREST;
552 *option = GDK_INTERP_TILES;
555 *option = GDK_INTERP_BILINEAR;
560 static void dnd_default_action_selection_menu_cb(GtkWidget *combo, gpointer data)
564 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
568 *option = DND_ACTION_ASK;
571 *option = DND_ACTION_COPY;
574 *option = DND_ACTION_MOVE;
578 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
582 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
585 *option = CLIPBOARD_PRIMARY;
588 *option = CLIPBOARD_CLIPBOARD;
591 *option = CLIPBOARD_BOTH;
594 *option = CLIPBOARD_BOTH;
598 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
599 guint option, guint *option_c)
606 pref_table_label(table, column, row, text, 0.0);
608 combo = gtk_combo_box_text_new();
610 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
611 if (option == GDK_INTERP_NEAREST) current = 0;
612 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
613 if (option == GDK_INTERP_TILES) current = 1;
614 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear (best, but slowest)"));
615 if (option == GDK_INTERP_BILINEAR) current = 2;
617 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
619 g_signal_connect(G_OBJECT(combo), "changed",
620 G_CALLBACK(quality_menu_cb), option_c);
622 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
623 gtk_widget_show(combo);
626 static void add_dnd_default_action_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, DnDAction option, DnDAction *option_c)
633 pref_table_label(table, column, row, text, 0.0);
635 combo = gtk_combo_box_text_new();
637 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Ask"));
638 if (option == DND_ACTION_ASK) current = 0;
639 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Copy"));
640 if (option == DND_ACTION_COPY) current = 1;
641 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Move"));
642 if (option == DND_ACTION_MOVE) current = 2;
644 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
646 g_signal_connect(G_OBJECT(combo), "changed",
647 G_CALLBACK(dnd_default_action_selection_menu_cb), option_c);
649 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
650 gtk_widget_show(combo);
653 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
654 gint option, gint *option_c)
661 pref_table_label(table, column, row, text, 0.0);
663 combo = gtk_combo_box_text_new();
665 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Primary"));
666 if (option == CLIPBOARD_PRIMARY) current = 0;
667 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Clipboard"));
668 if (option == CLIPBOARD_CLIPBOARD) current = 1;
669 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Both"));
670 if (option == CLIPBOARD_BOTH) current = 2;
672 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
674 g_signal_connect(G_OBJECT(combo), "changed",
675 G_CALLBACK(clipboard_selection_menu_cb), option_c);
677 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
678 gtk_widget_show(combo);
681 typedef struct _UseableMouseItems UseableMouseItems;
682 struct _UseableMouseItems
684 gchar *name; /* GtkActionEntry terminology */
689 static const UseableMouseItems useable_mouse_items[] = {
691 {"FirstImage", N_("First Image"), GTK_STOCK_GOTO_TOP},
692 {"PrevImage", N_("Previous Image"), GTK_STOCK_GO_UP},
693 {"NextImage", N_("Next Image"), GTK_STOCK_GO_DOWN},
694 {"LastImage", N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
695 {"Back", N_("Back"), GTK_STOCK_GO_BACK},
696 {"Forward", N_("Forward"), GTK_STOCK_GO_FORWARD},
697 {"Home", N_("Home"), GTK_STOCK_HOME},
698 {"Up", N_("Up"), GTK_STOCK_GO_UP},
699 {"FirstPage", N_("First page"), GTK_STOCK_MEDIA_PREVIOUS},
700 {"LastPage", N_("Last Page"), GTK_STOCK_MEDIA_NEXT},
701 {"NextPage", N_("Next page"), GTK_STOCK_MEDIA_FORWARD},
702 {"PrevPage", N_("Previous Page"), GTK_STOCK_MEDIA_REWIND},
703 {"NewWindow", N_("New _window"), GTK_STOCK_NEW},
704 {"NewCollection", N_("New collection"), GTK_STOCK_INDEX},
705 {"OpenCollection", N_("Open collection"), GTK_STOCK_OPEN},
706 {"Search", N_("Search"), GTK_STOCK_FIND},
707 {"FindDupes", N_("Find duplicates"), GTK_STOCK_FIND},
708 {"NewFolder", N_("New folder"),GTK_STOCK_DIRECTORY},
709 {"Copy", N_("Copy"), GTK_STOCK_COPY},
710 {"Move", N_("Move"), PIXBUF_INLINE_ICON_MOVE},
711 {"Rename", N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
712 {"Delete", N_("Delete"), GTK_STOCK_DELETE},
713 {"CloseWindow", N_("Close Window"), GTK_STOCK_CLOSE},
714 {"PanView", N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
715 {"SelectAll", N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
716 {"SelectNone", N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
717 {"SelectInvert", N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
718 {"ShowFileFilter", N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
719 {"RectangularSelection", N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
720 {"Print", N_("Print"), GTK_STOCK_PRINT},
721 {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
722 {"LayoutConfig", N_("Configure this window"), GTK_STOCK_PREFERENCES},
723 {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
724 {"RotateCW", N_("Rotate clockwise 90°"), PIXBUF_INLINE_ICON_CW},
725 {"RotateCCW", N_("Rotate counterclockwise 90°"), PIXBUF_INLINE_ICON_CCW},
726 {"Rotate180", N_("Rotate 180°"), PIXBUF_INLINE_ICON_180},
727 {"Mirror", N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
728 {"Flip", N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
729 {"AlterNone", N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
730 {"ZoomIn", N_("Zoom in"), GTK_STOCK_ZOOM_IN},
731 {"ZoomOut", N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
732 {"Zoom100", N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
733 {"ZoomFit", N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
734 {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
735 {"ZoomFillVert", N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
736 {"Zoom200", N_("Zoom 2:1"), GTK_STOCK_FILE},
737 {"Zoom300", N_("Zoom 3:1"), GTK_STOCK_FILE},
738 {"Zoom400", N_("Zoom 4:1"), GTK_STOCK_FILE},
739 {"Zoom50", N_("Zoom 1:2"), GTK_STOCK_FILE},
740 {"Zoom33", N_("Zoom1:3"), GTK_STOCK_FILE},
741 {"Zoom25", N_("Zoom 1:4"), GTK_STOCK_FILE},
742 {"ConnectZoomIn", N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
743 {"SplitPaneSync", N_("Split Pane Sync"), PIXBUF_INLINE_SPLIT_PANE_SYNC},
744 {"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
745 {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
746 {"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
747 {"SlideShowPause", N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
748 {"SlideShowFaster", N_("Slideshow Faster"), GTK_STOCK_FILE},
749 {"SlideShowSlower", N_("Slideshow Slower"), GTK_STOCK_FILE},
750 {"Refresh", N_("Refresh"), GTK_STOCK_REFRESH},
751 {"HelpContents", N_("Help"), GTK_STOCK_HELP},
752 {"ExifWin", N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
753 {"Thumbnails", N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
754 {"ShowMarks", N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
755 {"ImageGuidelines", N_("Show guidelines"), PIXBUF_INLINE_ICON_GUIDELINES},
756 {"DrawRectangle", N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
757 {"FloatTools", N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
758 {"SBar", N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
759 {"SBarSort", N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
760 {"Quit", N_("Quit"), GTK_STOCK_QUIT},
764 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
766 gchar **option = data;
769 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
771 const UseableMouseItems *list = useable_mouse_items;
775 if (g_strcmp0(list->label, label) == 0)
783 *option = g_strdup(list->name);
787 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
788 gchar *option, gchar **option_c)
796 pref_table_label(table, column, row, text, 0.0);
798 combo = gtk_combo_box_text_new();
800 const UseableMouseItems *list = useable_mouse_items;
804 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
805 if (g_strcmp0(list->name, option) == 0)
813 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
815 g_signal_connect(G_OBJECT(combo), "changed",
816 G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
818 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
819 gtk_widget_show(combo);
822 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
826 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
829 if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
831 c_options->thumbnails.max_width = thumb_size_list[n].w;
832 c_options->thumbnails.max_height = thumb_size_list[n].h;
836 c_options->thumbnails.max_width = options->thumbnails.max_width;
837 c_options->thumbnails.max_height = options->thumbnails.max_height;
841 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
847 c_options->thumbnails.max_width = options->thumbnails.max_width;
848 c_options->thumbnails.max_height = options->thumbnails.max_height;
850 pref_table_label(table, column, row, text, 0.0);
852 combo = gtk_combo_box_text_new();
855 for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
860 w = thumb_size_list[i].w;
861 h = thumb_size_list[i].h;
863 buf = g_strdup_printf("%d x %d", w, h);
864 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
867 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
874 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
875 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
881 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
882 g_signal_connect(G_OBJECT(combo), "changed",
883 G_CALLBACK(thumb_size_menu_cb), NULL);
885 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
886 gtk_widget_show(combo);
889 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
893 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
897 *option = PR_STEREO_NONE;
900 *option = PR_STEREO_ANAGLYPH_RC;
903 *option = PR_STEREO_ANAGLYPH_GM;
906 *option = PR_STEREO_ANAGLYPH_YB;
909 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
912 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
915 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
918 *option = PR_STEREO_ANAGLYPH_DB_RC;
921 *option = PR_STEREO_ANAGLYPH_DB_GM;
924 *option = PR_STEREO_ANAGLYPH_DB_YB;
927 *option = PR_STEREO_HORIZ;
930 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
933 *option = PR_STEREO_VERT;
936 *option = PR_STEREO_VERT | PR_STEREO_HALF;
939 *option = PR_STEREO_FIXED;
944 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
945 gint option, gint *option_c, gboolean add_fixed)
952 pref_table_label(table, column, row, text, 0.0);
954 combo = gtk_combo_box_text_new();
956 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
958 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
959 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
960 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
961 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
962 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
963 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
964 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
965 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
966 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
967 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
968 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
969 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
970 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
971 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
972 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
973 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
974 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
975 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
977 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
978 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
979 if (option & PR_STEREO_HORIZ)
982 if (option & PR_STEREO_HALF) current = 11;
985 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
986 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
987 if (option & PR_STEREO_VERT)
990 if (option & PR_STEREO_HALF) current = 13;
995 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
996 if (option & PR_STEREO_FIXED) current = 14;
999 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1001 g_signal_connect(G_OBJECT(combo), "changed",
1002 G_CALLBACK(stereo_mode_menu_cb), option_c);
1004 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1005 gtk_widget_show(combo);
1008 static void video_menu_cb(GtkWidget *combo, gpointer data)
1010 gchar **option = data;
1012 EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
1016 static void video_menu_populate(gpointer data, gpointer user_data)
1018 GtkWidget *combo = user_data;
1019 EditorDescription *ed = data;
1021 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1024 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1025 gchar *option, gchar **option_c)
1029 /* use lists since they are sorted */
1030 GList *eds = editor_list_get();
1034 pref_table_label(table, column, row, text, 0.0);
1036 combo = gtk_combo_box_text_new();
1037 g_list_foreach(eds,video_menu_populate,(gpointer)combo);
1038 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1040 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1042 g_signal_connect(G_OBJECT(combo), "changed",
1043 G_CALLBACK(video_menu_cb), option_c);
1045 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1046 gtk_widget_show(combo);
1049 static void filter_store_populate(void)
1053 if (!filter_store) return;
1055 gtk_list_store_clear(filter_store);
1057 work = filter_get_list();
1066 gtk_list_store_append(filter_store, &iter);
1067 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1071 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1072 gchar *new_text, gpointer data)
1074 GtkWidget *model = data;
1075 FilterEntry *fe = data;
1079 if (!new_text || strlen(new_text) < 1) return;
1081 tpath = gtk_tree_path_new_from_string(path_str);
1082 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1083 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1085 g_free(fe->extensions);
1086 fe->extensions = g_strdup(new_text);
1088 gtk_tree_path_free(tpath);
1092 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1093 gchar *new_text, gpointer data)
1095 GtkWidget *model = data;
1096 FilterEntry *fe = data;
1101 if (!new_text || !new_text[0]) return;
1103 tpath = gtk_tree_path_new_from_string(path_str);
1104 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1105 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1107 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1109 if (strcmp(new_text, _(format_class_list[i])) == 0)
1116 gtk_tree_path_free(tpath);
1120 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1121 gchar *new_text, gpointer data)
1123 GtkWidget *model = data;
1128 if (!new_text || !new_text[0]) return;
1130 tpath = gtk_tree_path_new_from_string(path_str);
1131 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1132 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1134 g_free(fe->description);
1135 fe->description = g_strdup(new_text);
1137 gtk_tree_path_free(tpath);
1140 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
1141 gchar *path_str, gpointer data)
1143 GtkWidget *model = data;
1148 tpath = gtk_tree_path_new_from_string(path_str);
1149 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1150 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1152 fe->enabled = !fe->enabled;
1154 gtk_tree_path_free(tpath);
1158 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
1159 gchar *path_str, gpointer data)
1161 GtkWidget *model = data;
1166 tpath = gtk_tree_path_new_from_string(path_str);
1167 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1168 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1170 fe->writable = !fe->writable;
1171 if (fe->writable) fe->allow_sidecar = FALSE;
1173 gtk_tree_path_free(tpath);
1177 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
1178 gchar *path_str, gpointer data)
1180 GtkWidget *model = data;
1185 tpath = gtk_tree_path_new_from_string(path_str);
1186 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1187 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1189 fe->allow_sidecar = !fe->allow_sidecar;
1190 if (fe->allow_sidecar) fe->writable = FALSE;
1192 gtk_tree_path_free(tpath);
1196 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1197 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1201 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1203 switch (GPOINTER_TO_INT(data))
1206 g_object_set(GTK_CELL_RENDERER(cell),
1207 "active", fe->enabled, NULL);
1210 g_object_set(GTK_CELL_RENDERER(cell),
1211 "text", fe->extensions, NULL);
1213 case FE_DESCRIPTION:
1214 g_object_set(GTK_CELL_RENDERER(cell),
1215 "text", fe->description, NULL);
1218 g_object_set(GTK_CELL_RENDERER(cell),
1219 "text", _(format_class_list[fe->file_class]), NULL);
1222 g_object_set(GTK_CELL_RENDERER(cell),
1223 "active", fe->writable, NULL);
1225 case FE_ALLOW_SIDECAR:
1226 g_object_set(GTK_CELL_RENDERER(cell),
1227 "active", fe->allow_sidecar, NULL);
1232 static gboolean filter_add_scroll(gpointer data)
1236 GtkCellRenderer *cell;
1237 GtkTreeViewColumn *column;
1240 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1241 path = gtk_tree_path_new_from_indices(rows-1, -1);
1243 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1245 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1246 cell = g_list_last(list_cells)->data;
1248 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1249 path, column, FALSE, 0.0, 0.0 );
1250 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1251 path, column, cell, TRUE);
1253 gtk_tree_path_free(path);
1254 g_list_free(list_cells);
1259 static void filter_add_cb(GtkWidget *widget, gpointer data)
1261 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1262 filter_store_populate();
1264 g_idle_add((GSourceFunc)filter_add_scroll, data);
1267 static void filter_remove_cb(GtkWidget *widget, gpointer data)
1269 GtkWidget *filter_view = data;
1270 GtkTreeSelection *selection;
1274 if (!filter_store) return;
1275 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1276 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1277 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1280 filter_remove_entry(fe);
1282 filter_store_populate();
1285 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1289 GtkTreeViewColumn *column;
1291 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1292 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1293 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1295 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1299 gtk_tree_path_free(path);
1304 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
1307 filter_add_defaults();
1309 filter_store_populate();
1311 g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1314 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1316 /* no op, only so cancel button appears */
1319 static void filter_default_cb(GtkWidget *widget, gpointer data)
1323 gd = generic_dialog_new(_("Reset filters"),
1324 "reset_filter", widget, TRUE,
1325 dummy_cancel_cb, data);
1326 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1327 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1328 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1329 gtk_widget_show(gd->dialog);
1332 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1334 GtkWidget *frame = data;
1336 gtk_widget_set_sensitive(frame,
1337 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1340 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
1342 layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1345 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
1347 file_util_trash_clear();
1350 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
1354 gd = generic_dialog_new(_("Clear trash"),
1355 "clear_trash", widget, TRUE,
1356 dummy_cancel_cb, NULL);
1357 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1358 _("This will remove the trash contents."), FALSE);
1359 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1360 entry = gtk_entry_new();
1361 gtk_widget_set_can_focus(entry, FALSE);
1362 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1363 if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1364 gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1365 gtk_widget_show(entry);
1366 gtk_widget_show(gd->dialog);
1369 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
1371 GtkWidget *pTextView;
1372 GtkTextBuffer *pTextBuffer;
1376 pTextView = GTK_WIDGET(data);
1378 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1379 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1380 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1382 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1383 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1386 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
1388 GtkTextView *text_view = data;
1389 GtkTextBuffer *buffer;
1391 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1392 if (!configwindow) return;
1394 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1395 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1398 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1402 gd = generic_dialog_new(_("Reset image overlay template string"),
1403 "reset_image_overlay_template_string", widget, TRUE,
1404 dummy_cancel_cb, data);
1405 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1406 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1407 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1408 gtk_widget_show(gd->dialog);
1411 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
1413 help_window_show("GuideOptionsOSD.html");
1416 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer data)
1418 #if GTK_CHECK_VERSION(3,4,0)
1421 PangoFontDescription *font_desc;
1423 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1424 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1426 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1428 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1429 font = pango_font_description_to_string(font_desc);
1430 g_free(c_options->image_overlay.font);
1431 c_options->image_overlay.font = g_strdup(font);
1435 gtk_widget_destroy(dialog);
1439 font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
1440 c_options->image_overlay.font = g_strdup(font);
1444 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer data)
1447 #if GTK_CHECK_VERSION(3,4,0)
1450 dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1451 colour.red = options->image_overlay.text_red;
1452 colour.green = options->image_overlay.text_green;
1453 colour.blue = options->image_overlay.text_blue;
1454 colour.alpha = options->image_overlay.text_alpha;
1455 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1456 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1458 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1460 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1461 c_options->image_overlay.text_red = colour.red*255;
1462 c_options->image_overlay.text_green = colour.green*255;
1463 c_options->image_overlay.text_blue = colour.blue*255;
1464 c_options->image_overlay.text_alpha = colour.alpha*255;
1466 gtk_widget_destroy(dialog);
1469 GtkColorSelection *colorsel;
1471 dialog = gtk_color_selection_dialog_new("Image Overlay Text Colour");
1472 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1473 colour.red = options->image_overlay.text_red*257;
1474 colour.green = options->image_overlay.text_green*257;
1475 colour.blue = options->image_overlay.text_blue*257;
1476 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1477 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1478 gtk_color_selection_set_current_color(colorsel, &colour);
1479 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.text_alpha*257);
1481 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1483 gtk_color_selection_get_current_color(colorsel, &colour);
1484 c_options->image_overlay.text_red = colour.red/257;
1485 c_options->image_overlay.text_green = colour.green/257;
1486 c_options->image_overlay.text_blue = colour.blue/257;
1487 c_options->image_overlay.text_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1489 gtk_widget_destroy (dialog);
1494 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer data)
1497 #if GTK_CHECK_VERSION(3,4,0)
1500 dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1501 colour.red = options->image_overlay.background_red;
1502 colour.green = options->image_overlay.background_green;
1503 colour.blue = options->image_overlay.background_blue;
1504 colour.alpha = options->image_overlay.background_alpha;
1505 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1506 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1508 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1510 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1511 c_options->image_overlay.background_red = colour.red*255;
1512 c_options->image_overlay.background_green = colour.green*255;
1513 c_options->image_overlay.background_blue = colour.blue*255;
1514 c_options->image_overlay.background_alpha = colour.alpha*255;
1516 gtk_widget_destroy(dialog);
1519 GtkColorSelection *colorsel;
1521 dialog = gtk_color_selection_dialog_new("Image Overlay Background Colour");
1522 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1523 colour.red = options->image_overlay.background_red*257;
1524 colour.green = options->image_overlay.background_green*257;
1525 colour.blue = options->image_overlay.background_blue*257;
1526 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1527 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1528 gtk_color_selection_set_current_color(colorsel, &colour);
1529 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.background_alpha*257);
1531 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1533 gtk_color_selection_get_current_color(colorsel, &colour);
1534 c_options->image_overlay.background_red = colour.red/257;
1535 c_options->image_overlay.background_green = colour.green/257;
1536 c_options->image_overlay.background_blue = colour.blue/257;
1537 c_options->image_overlay.background_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1539 gtk_widget_destroy(dialog);
1543 static void accel_store_populate(void)
1546 GList *groups, *actions;
1548 const gchar *accel_path;
1552 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1554 gtk_tree_store_clear(accel_store);
1555 lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
1557 g_assert(lw && lw->ui_manager);
1558 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1561 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1564 action = GTK_ACTION(actions->data);
1565 accel_path = gtk_action_get_accel_path(action);
1566 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1568 gchar *label, *label2, *tooltip, *accel;
1569 g_object_get(action,
1570 "tooltip", &tooltip,
1574 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1580 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1584 gtk_tree_store_append(accel_store, &iter, NULL);
1585 gtk_tree_store_set(accel_store, &iter,
1588 AE_TOOLTIP, tooltip ? tooltip : "",
1589 AE_ACCEL, accel_path,
1597 actions = actions->next;
1600 groups = groups->next;
1604 static void accel_store_cleared_cb(GtkCellRendererAccel *accel, gchar *path_string, gpointer user_data)
1609 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1611 gchar *accel1 = data;
1616 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1618 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1619 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1621 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1623 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1624 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1633 static void accel_store_edited_cb(GtkCellRendererAccel *accel, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode, gpointer user_data)
1635 GtkTreeModel *model = (GtkTreeModel *)accel_store;
1639 GtkAccelKey old_key, key;
1640 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1642 gtk_tree_model_get_iter(model, &iter, path);
1643 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1645 /* test if the accelerator can be stored without conflicts*/
1646 gtk_accel_map_lookup_entry(accel_path, &old_key);
1648 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1649 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1650 gtk_accel_map_lookup_entry(accel_path, &key);
1652 /* restore the original for now, the key will be really changed when the changes are confirmed */
1653 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1655 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1656 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1658 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1659 gtk_tree_path_free(path);
1663 static gboolean accel_default_scroll(GtkTreeView *data)
1667 GtkTreeViewColumn *column;
1669 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1670 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1671 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1673 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1677 gtk_tree_path_free(path);
1682 static void accel_default_cb(GtkWidget *widget, gpointer data)
1684 accel_store_populate();
1686 g_idle_add((GSourceFunc)accel_default_scroll, data);
1689 void accel_remove_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1691 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1694 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1697 gchar *accel_path, *accel;
1699 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1700 gtk_accel_map_lookup_entry(accel_path, &key);
1701 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1703 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1705 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1710 static void accel_reset_cb(GtkWidget *widget, gpointer data)
1712 GtkTreeSelection *selection;
1714 if (!accel_store) return;
1715 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1716 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1721 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1725 GtkWidget *scrolled;
1726 GtkWidget *viewport;
1728 scrolled = gtk_scrolled_window_new(NULL, NULL);
1729 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1730 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1731 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1732 label = gtk_label_new(title);
1733 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1734 gtk_widget_show(scrolled);
1736 viewport = gtk_viewport_new(NULL, NULL);
1737 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1738 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1739 gtk_widget_show(viewport);
1741 vbox = gtk_vbox_new(FALSE, 0);
1742 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1743 gtk_widget_show(vbox);
1748 static void cache_standard_cb(GtkWidget *widget, gpointer data)
1750 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1752 c_options->thumbnails.spec_standard =TRUE;
1753 c_options->thumbnails.cache_into_dirs = FALSE;
1757 static void cache_geeqie_cb(GtkWidget *widget, gpointer data)
1759 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1761 c_options->thumbnails.spec_standard =FALSE;
1762 c_options->thumbnails.cache_into_dirs = FALSE;
1766 static void cache_local_cb(GtkWidget *widget, gpointer data)
1768 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1770 c_options->thumbnails.cache_into_dirs = TRUE;
1771 c_options->thumbnails.spec_standard =FALSE;
1775 static void help_search_engine_entry_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1776 GdkEvent *event, gpointer userdata)
1778 if (pos == GTK_ENTRY_ICON_PRIMARY)
1780 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1784 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1788 static void star_rating_star_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1789 GdkEvent *event, gpointer userdata)
1791 gchar *rating_symbol;
1793 if (pos == GTK_ENTRY_ICON_PRIMARY)
1795 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1796 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1797 g_free(rating_symbol);
1801 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1802 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1803 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1807 static void star_rating_rejected_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1808 GdkEvent *event, gpointer userdata)
1810 gchar *rating_symbol;
1812 if (pos == GTK_ENTRY_ICON_PRIMARY)
1814 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1815 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1816 g_free(rating_symbol);
1820 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1821 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1822 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1826 static guint star_rating_symbol_test(GtkWidget *widget, gpointer data)
1828 GtkContainer *hbox = data;
1829 GString *str = g_string_new(NULL);
1830 GtkEntry *hex_code_entry;
1831 gchar *hex_code_full;
1834 guint64 hex_value = 0;
1836 list = gtk_container_get_children(hbox);
1838 hex_code_entry = g_list_nth_data(list, 2);
1839 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1841 hex_code = g_strsplit(hex_code_full, "+", 2);
1842 if (hex_code[0] && hex_code[1])
1844 hex_value = strtoull(hex_code[1], NULL, 16);
1846 if (!hex_value || hex_value > 0x10FFFF)
1848 hex_value = 0x003F; // Unicode 'Question Mark'
1850 str = g_string_append_unichar(str, (gunichar)hex_value);
1851 gtk_label_set_text(g_list_nth_data(list, 1), str->str);
1853 g_strfreev(hex_code);
1854 g_string_free(str, TRUE);
1855 g_free(hex_code_full);
1860 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1862 guint64 star_symbol;
1864 star_symbol = star_rating_symbol_test(widget, data);
1865 c_options->star_rating.star = star_symbol;
1868 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1870 guint64 rejected_symbol;
1872 rejected_symbol = star_rating_symbol_test(widget, data);
1873 c_options->star_rating.rejected = rejected_symbol;
1876 /* general options tab */
1877 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1878 typedef struct _TZData TZData;
1882 GCancellable *cancellable;
1884 GtkWidget *progress;
1886 GFile *timezone_database_gq;
1887 gchar *timezone_database_user;
1890 static void config_tab_general(GtkWidget *notebook)
1895 GtkWidget *group_frame;
1896 GtkWidget *subgroup;
1898 GtkWidget *ct_button;
1901 gint hours, minutes, remainder;
1903 GtkWidget *star_rating_entry;
1905 gchar *rating_symbol;
1908 GNetworkMonitor *net_mon;
1909 GSocketConnectable *geeqie_org;
1910 gboolean internet_available;
1913 vbox = scrolled_notebook_page(notebook, _("General"));
1915 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1917 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1918 add_thumb_size_menu(table, 0, 0, _("Size:"));
1919 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1921 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1922 pref_label_new(hbox, _("Custom size: "));
1923 pref_spin_new_int(hbox, _("Width:"), NULL, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
1924 pref_spin_new_int(hbox, _("Height:"), NULL, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
1926 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
1927 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1929 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1930 pref_checkbox_link_sensitivity(ct_button, subgroup);
1932 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
1933 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
1934 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
1935 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1936 button = pref_radiobutton_new(group_frame, NULL, get_thumbnails_cache_dir(),
1937 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1938 G_CALLBACK(cache_geeqie_cb), NULL);
1940 group_frame = pref_frame_new(subgroup, TRUE,
1941 _("Store thumbnails local to image folder (non-standard)"),
1942 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1943 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
1944 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
1945 G_CALLBACK(cache_local_cb), NULL);
1947 group_frame = pref_frame_new(subgroup, TRUE,
1948 _("Use standard thumbnail style and cache, shared with other applications"),
1949 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1950 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
1951 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1952 G_CALLBACK(cache_standard_cb), NULL);
1954 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
1955 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
1957 spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
1959 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
1960 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
1962 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
1963 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
1964 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
1966 // pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
1967 // options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
1970 pref_spacer(group, PREF_PAD_GROUP);
1972 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
1974 c_options->star_rating.star = options->star_rating.star;
1975 c_options->star_rating.rejected = options->star_rating.rejected;
1977 str = g_string_new(NULL);
1978 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1979 pref_label_new(hbox, "Star character: ");
1980 str = g_string_append_unichar(str, options->star_rating.star);
1981 pref_label_new(hbox, g_strdup(str->str));
1982 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
1983 star_rating_entry = gtk_entry_new();
1984 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
1985 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
1986 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
1987 gtk_widget_show(star_rating_entry);
1988 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
1989 G_CALLBACK(star_rating_star_test_cb), hbox);
1990 gtk_widget_set_tooltip_text(button, _("Display selected character"));
1991 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1992 gtk_widget_show(button);
1993 gtk_widget_set_tooltip_text(star_rating_entry, _("Hexadecimal representation of a Unicode character. A list of all Unicode characters may be found on the Internet."));
1994 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1995 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
1996 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1997 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
1998 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1999 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2000 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2001 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2002 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2003 G_CALLBACK(star_rating_star_icon_cb),
2006 g_string_free(str, TRUE);
2007 g_free(rating_symbol);
2009 str = g_string_new(NULL);
2010 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2011 pref_label_new(hbox, "Rejected character: ");
2012 str = g_string_append_unichar(str, options->star_rating.rejected);
2013 pref_label_new(hbox, g_strdup(str->str));
2014 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2015 star_rating_entry = gtk_entry_new();
2016 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2017 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2018 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2019 gtk_widget_show(star_rating_entry);
2020 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2021 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2022 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2023 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2024 gtk_widget_show(button);
2025 gtk_widget_set_tooltip_text(star_rating_entry, _("Hexadecimal representation of a Unicode character. A list of all Unicode characters may be found on the Internet."));
2026 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2027 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2028 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2029 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2030 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2031 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2032 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2033 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2034 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2035 G_CALLBACK(star_rating_rejected_icon_cb),
2038 g_string_free(str, TRUE);
2039 g_free(rating_symbol);
2041 pref_spacer(group, PREF_PAD_GROUP);
2043 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2045 c_options->slideshow.delay = options->slideshow.delay;
2046 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2047 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2048 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2049 seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2050 SLIDESHOW_SUBSECOND_PRECISION;
2052 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2054 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2056 options->slideshow.delay ? hours : 0.0,
2057 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2058 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2059 spin = pref_spin_new(hbox, ":" , NULL,
2061 options->slideshow.delay ? minutes: 0.0,
2062 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2063 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2064 spin = pref_spin_new(hbox, ":", NULL,
2065 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2066 options->slideshow.delay ? seconds : 10.0,
2067 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2068 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2070 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2071 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2073 pref_spacer(group, PREF_PAD_GROUP);
2075 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2077 pref_spin_new_int(group, _("Decoded image cache size (Mb):"), NULL,
2078 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2079 pref_checkbox_new_int(group, _("Preload next image"),
2080 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2082 pref_checkbox_new_int(group, _("Refresh on file change"),
2083 options->update_on_time_change, &c_options->update_on_time_change);
2086 pref_spacer(group, PREF_PAD_GROUP);
2088 group = pref_group_new(vbox, FALSE, _("Expand menu and toolbar"), GTK_ORIENTATION_VERTICAL);
2090 pref_checkbox_new_int(group, _("Expand menu and toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2091 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2092 gtk_widget_set_tooltip_text(group, _("Expand the menu and toolbar to the full width of the window"));
2094 pref_spacer(group, PREF_PAD_GROUP);
2096 group = pref_group_new(vbox, FALSE, _("Info sidebar heights"), GTK_ORIENTATION_VERTICAL);
2097 pref_label_new(group, _("NOTE! Geeqie must be restarted for changes to take effect"));
2098 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2099 pref_spin_new_int(hbox, _("Keywords:"), NULL,
2101 options->info_keywords.height, &c_options->info_keywords.height);
2102 pref_spin_new_int(hbox, _("Title:"), NULL,
2104 options->info_title.height, &c_options->info_title.height);
2105 pref_spin_new_int(hbox, _("Comment:"), NULL,
2107 options->info_comment.height, &c_options->info_comment.height);
2108 pref_spin_new_int(hbox, _("Rating:"), NULL,
2110 options->info_rating.height, &c_options->info_rating.height);
2112 pref_spacer(group, PREF_PAD_GROUP);
2114 group = pref_group_new(vbox, FALSE, _("Show predefined keyword tree"), GTK_ORIENTATION_VERTICAL);
2116 pref_checkbox_new_int(group, _("Show predefined keyword tree (NOTE! Geeqie must be restarted for change to take effect)"),
2117 options->show_predefined_keyword_tree, &c_options->show_predefined_keyword_tree);
2119 pref_spacer(group, PREF_PAD_GROUP);
2121 net_mon = g_network_monitor_get_default();
2122 geeqie_org = g_network_address_parse_uri(GQ_WEBSITE, 80, NULL);
2123 internet_available = g_network_monitor_can_reach(net_mon, geeqie_org, NULL, NULL);
2124 g_object_unref(geeqie_org);
2126 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2127 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2129 if (!internet_available)
2131 gtk_widget_set_sensitive(group, FALSE);
2134 tz = g_new0(TZData, 1);
2136 path = path_from_utf8(TIMEZONE_DATABASE);
2137 basename = g_path_get_basename(path);
2138 tz->timezone_database_user = g_build_filename(get_rc_dir(), basename, NULL);
2142 if (isfile(tz->timezone_database_user))
2144 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2148 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2151 if (!internet_available)
2153 gtk_widget_set_tooltip_text(button, _("No Internet connection!\nThe timezone database is used to display exif time and date\ncorrected for UTC offset and Daylight Saving Time"));
2157 gtk_widget_set_tooltip_text(button, _("The timezone database is used to display exif time and date\ncorrected for UTC offset and Daylight Saving Time"));
2159 gtk_widget_show(button);
2161 pref_spacer(group, PREF_PAD_GROUP);
2163 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2165 help_search_engine_entry = gtk_entry_new();
2166 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2167 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2168 gtk_widget_show(help_search_engine_entry);
2170 gtk_widget_set_tooltip_text(help_search_engine_entry, _("The format varies between search engines, e.g the format may be:\nhttps://www.search_engine.com/search?q=site:geeqie.org/help\nhttps://www.search_engine.com/?q=site:geeqie.org/help"));
2172 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2173 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2174 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2175 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2176 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2177 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2178 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2179 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2180 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2181 G_CALLBACK(help_search_engine_entry_icon_cb),
2182 help_search_engine_entry);
2186 static void config_tab_image(GtkWidget *notebook)
2191 GtkWidget *ct_button;
2192 GtkWidget *enlargement_button;
2195 GtkWidget *two_pass;
2197 GtkWidget *gpu_accel;
2200 vbox = scrolled_notebook_page(notebook, _("Image"));
2202 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2204 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2205 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2206 if (options->image.use_clutter_renderer && !options->disable_gpu)
2208 gtk_widget_set_sensitive(table, FALSE);
2212 gpu_accel = pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library (Requires restart)"),
2213 options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2214 if (options->disable_gpu && !options->override_disable_gpu)
2216 gtk_widget_set_sensitive(gpu_accel, FALSE);
2220 two_pass = pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2221 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2222 if (options->image.use_clutter_renderer && !options->disable_gpu)
2224 gtk_widget_set_sensitive(two_pass, FALSE);
2227 c_options->image.zoom_increment = options->image.zoom_increment;
2228 spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2229 0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2230 G_CALLBACK(zoom_increment_cb), NULL);
2231 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2233 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2235 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2236 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2237 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2238 spin = pref_spin_new_int(hbox, NULL, NULL,
2240 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2241 pref_checkbox_link_sensitivity(enlargement_button, spin);
2242 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."));
2244 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2245 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2246 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2247 spin = pref_spin_new_int(hbox, NULL, NULL,
2249 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2250 pref_checkbox_link_sensitivity(ct_button, spin);
2251 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."));
2253 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2255 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2256 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2258 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2259 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2261 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2262 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2264 c_options->image.border_color = options->image.border_color;
2266 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2267 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2269 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2270 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2272 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2273 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2275 group = pref_group_new(vbox, FALSE, _("Convenience"), GTK_ORIENTATION_VERTICAL);
2277 pref_checkbox_new_int(group, _("Auto rotate proofs using Exif information"),
2278 options->image.exif_proof_rotate_enable, &c_options->image.exif_proof_rotate_enable);
2282 static void config_tab_windows(GtkWidget *notebook)
2288 GtkWidget *ct_button;
2291 vbox = scrolled_notebook_page(notebook, _("Windows"));
2293 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2295 ct_button = pref_checkbox_new_int(group, _("Remember window positions"),
2296 options->save_window_positions, &c_options->save_window_positions);
2298 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2299 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2300 pref_checkbox_link_sensitivity(ct_button, button);
2302 button = pref_checkbox_new_int(group, _("Remember window workspace"),
2303 options->save_window_workspace, &c_options->save_window_workspace);
2304 pref_checkbox_link_sensitivity(ct_button, button);
2306 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2307 options->tools_restore_state, &c_options->tools_restore_state);
2309 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2310 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2312 pref_checkbox_new_int(group, _("Show window IDs"),
2313 options->show_window_ids, &c_options->show_window_ids);
2315 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2317 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2318 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2320 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2321 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2322 options->image.limit_window_size, &c_options->image.limit_window_size);
2323 spin = pref_spin_new_int(hbox, NULL, NULL,
2325 options->image.max_window_size, &c_options->image.max_window_size);
2326 pref_checkbox_link_sensitivity(ct_button, spin);
2328 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2330 c_options->fullscreen.screen = options->fullscreen.screen;
2331 c_options->fullscreen.above = options->fullscreen.above;
2332 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2333 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2334 gtk_widget_show(hbox);
2336 pref_checkbox_new_int(group, _("Smooth image flip"),
2337 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2338 pref_checkbox_new_int(group, _("Disable screen saver"),
2339 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2342 #define PRE_FORMATTED_COLUMNS 5
2343 static void config_tab_osd(GtkWidget *notebook)
2349 GtkWidget *image_overlay_template_view;
2350 GtkWidget *scrolled;
2351 GtkWidget *scrolled_pre_formatted;
2352 GtkTextBuffer *buffer;
2354 GtkWidget *subgroup;
2356 vbox = scrolled_notebook_page(notebook, _("OSD"));
2358 image_overlay_template_view = gtk_text_view_new();
2360 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2362 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2364 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2365 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2366 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2367 gtk_widget_show(scrolled_pre_formatted);
2368 gtk_widget_show(subgroup);
2370 pref_line(group, PREF_PAD_GAP);
2372 pref_label_new(group, _("Image overlay template"));
2374 scrolled = gtk_scrolled_window_new(NULL, NULL);
2375 gtk_widget_set_size_request(scrolled, 200, 150);
2376 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2377 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2378 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2379 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2380 gtk_widget_show(scrolled);
2382 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2383 _("Extensive formatting options are shown in the Help file"));
2385 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2386 gtk_widget_show(image_overlay_template_view);
2388 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2390 #if GTK_CHECK_VERSION(3,4,0)
2391 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2392 G_CALLBACK(image_overlay_set_font_cb), notebook);
2394 button = gtk_font_button_new();
2395 gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
2396 gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
2397 g_signal_connect(G_OBJECT(button), "font-set",
2398 G_CALLBACK(image_overlay_set_font_cb),NULL);
2400 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2401 gtk_widget_show(button);
2403 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2404 G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2405 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2406 gtk_widget_show(button);
2408 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2409 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2410 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2411 gtk_widget_show(button);
2412 image_overlay_set_text_colours();
2414 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2415 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2416 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2417 gtk_widget_show(button);
2419 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2420 G_CALLBACK(image_overlay_help_cb), NULL);
2421 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2422 gtk_widget_show(button);
2424 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2425 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2426 g_signal_connect(G_OBJECT(buffer), "changed",
2427 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2429 pref_line(group, PREF_PAD_GAP);
2431 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2432 hbox = gtk_hbox_new(FALSE, 0);
2433 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2434 gtk_widget_show(hbox);
2435 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2436 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2437 gtk_widget_show(label);
2438 pref_spacer(group,TRUE);
2440 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2441 hbox = gtk_hbox_new(FALSE, 0);
2442 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2443 gtk_widget_show(hbox);
2444 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2445 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2446 gtk_widget_show(label);
2447 pref_spacer(group,TRUE);
2449 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2450 hbox = gtk_hbox_new(FALSE, 0);
2451 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2452 gtk_widget_show(hbox);
2453 label = gtk_label_new(_("%path:39%"));
2454 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2455 gtk_widget_show(label);
2456 pref_spacer(group,TRUE);
2458 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2459 hbox = gtk_hbox_new(FALSE, 0);
2460 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2461 gtk_widget_show(hbox);
2462 label = gtk_label_new(_("Text shown only if the field is non-null:\n%formatted.Aperture:F no. * setting%\n %formatted.Aperture:10:F no. * setting%"));
2463 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2464 gtk_widget_show(label);
2465 pref_spacer(group,TRUE);
2467 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2468 hbox = gtk_hbox_new(FALSE, 0);
2469 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2470 gtk_widget_show(hbox);
2471 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2472 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2473 gtk_widget_show(label);
2476 static GtkTreeModel *create_class_model(void)
2478 GtkListStore *model;
2482 /* create list store */
2483 model = gtk_list_store_new(1, G_TYPE_STRING);
2484 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2486 gtk_list_store_append(model, &iter);
2487 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2489 return GTK_TREE_MODEL (model);
2494 static void config_tab_files(GtkWidget *notebook)
2501 GtkWidget *ct_button;
2502 GtkWidget *scrolled;
2503 GtkWidget *filter_view;
2504 GtkCellRenderer *renderer;
2505 GtkTreeSelection *selection;
2506 GtkTreeViewColumn *column;
2508 vbox = scrolled_notebook_page(notebook, _("Files"));
2510 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2512 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2513 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2514 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2515 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2516 pref_checkbox_new_int(group, _("Case sensitive sort"),
2517 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2518 pref_checkbox_new_int(group, _("Natural sort order"),
2519 options->file_sort.natural, &c_options->file_sort.natural);
2520 pref_checkbox_new_int(group, _("Disable file extension checks"),
2521 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2523 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2524 options->file_filter.disable, &c_options->file_filter.disable);
2527 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2529 sidecar_ext_entry = gtk_entry_new();
2530 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2531 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2532 gtk_widget_show(sidecar_ext_entry);
2534 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2536 frame = pref_group_parent(group);
2537 g_signal_connect(G_OBJECT(ct_button), "toggled",
2538 G_CALLBACK(filter_disable_cb), frame);
2539 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2541 scrolled = gtk_scrolled_window_new(NULL, NULL);
2542 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2543 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2544 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2545 gtk_widget_show(scrolled);
2547 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2548 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2549 g_object_unref(filter_store);
2550 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2551 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2553 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2555 column = gtk_tree_view_column_new();
2556 gtk_tree_view_column_set_title(column, _("Filter"));
2557 gtk_tree_view_column_set_resizable(column, TRUE);
2559 renderer = gtk_cell_renderer_toggle_new();
2560 g_signal_connect(G_OBJECT(renderer), "toggled",
2561 G_CALLBACK(filter_store_enable_cb), filter_store);
2562 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2563 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2564 GINT_TO_POINTER(FE_ENABLE), NULL);
2566 renderer = gtk_cell_renderer_text_new();
2567 g_signal_connect(G_OBJECT(renderer), "edited",
2568 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2569 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2570 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2571 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2572 GINT_TO_POINTER(FE_EXTENSION), NULL);
2573 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2575 column = gtk_tree_view_column_new();
2576 gtk_tree_view_column_set_title(column, _("Description"));
2577 gtk_tree_view_column_set_resizable(column, TRUE);
2578 gtk_tree_view_column_set_fixed_width(column, 200);
2579 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2581 renderer = gtk_cell_renderer_text_new();
2582 g_signal_connect(G_OBJECT(renderer), "edited",
2583 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2584 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2585 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2586 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2587 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2588 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2590 column = gtk_tree_view_column_new();
2591 gtk_tree_view_column_set_title(column, _("Class"));
2592 gtk_tree_view_column_set_resizable(column, TRUE);
2593 renderer = gtk_cell_renderer_combo_new();
2594 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2595 "model", create_class_model(),
2600 g_signal_connect(G_OBJECT(renderer), "edited",
2601 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2602 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2603 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2604 GINT_TO_POINTER(FE_CLASS), NULL);
2605 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2607 column = gtk_tree_view_column_new();
2608 gtk_tree_view_column_set_title(column, _("Writable"));
2609 gtk_tree_view_column_set_resizable(column, FALSE);
2610 renderer = gtk_cell_renderer_toggle_new();
2611 g_signal_connect(G_OBJECT(renderer), "toggled",
2612 G_CALLBACK(filter_store_writable_cb), filter_store);
2613 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2614 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2615 GINT_TO_POINTER(FE_WRITABLE), NULL);
2616 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2618 column = gtk_tree_view_column_new();
2619 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2620 gtk_tree_view_column_set_resizable(column, FALSE);
2621 renderer = gtk_cell_renderer_toggle_new();
2622 g_signal_connect(G_OBJECT(renderer), "toggled",
2623 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2624 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2625 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2626 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2627 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2630 filter_store_populate();
2631 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2632 gtk_widget_show(filter_view);
2634 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2636 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2637 G_CALLBACK(filter_default_cb), filter_view);
2638 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2639 gtk_widget_show(button);
2641 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2642 G_CALLBACK(filter_remove_cb), filter_view);
2643 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2644 gtk_widget_show(button);
2646 button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2647 G_CALLBACK(filter_add_cb), filter_view);
2648 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2649 gtk_widget_show(button);
2653 static void config_tab_metadata(GtkWidget *notebook)
2658 GtkWidget *ct_button;
2662 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2665 group = pref_group_new(vbox, FALSE, _("Metadata writing process"), GTK_ORIENTATION_VERTICAL);
2667 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2669 label = pref_label_new(group, _("Metadata are written in the following order. The process ends after first success."));
2670 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2671 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2673 ct_button = pref_checkbox_new_int(group, _("1) Save metadata in image files, or sidecar files, according to the XMP standard"),
2674 options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2676 gtk_widget_set_sensitive(ct_button, FALSE);
2679 pref_checkbox_new_int(group, _("2) Save metadata in '.metadata' folder, local to image folder (non-standard)"),
2680 options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2682 text = g_strdup_printf(_("3) Save metadata in Geeqie private directory '%s'"), get_metadata_cache_dir());
2683 label = pref_label_new(group, text);
2684 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2685 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2686 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2689 group = pref_group_new(vbox, FALSE, _("Step 1: Write to image files"), GTK_ORIENTATION_VERTICAL);
2691 gtk_widget_set_sensitive(group, FALSE);
2694 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2695 pref_checkbox_link_sensitivity(ct_button, hbox);
2697 pref_checkbox_new_int(hbox, _("Store metadata also in legacy IPTC tags (converted according to IPTC4XMP standard)"),
2698 options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2700 pref_checkbox_new_int(hbox, _("Warn if the image files are unwritable"),
2701 options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2703 pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
2704 options->metadata.confirm_write, &c_options->metadata.confirm_write);
2706 pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
2707 options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2709 group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
2711 gtk_widget_set_sensitive(group, FALSE);
2714 pref_checkbox_new_int(group, _("Use GQview legacy metadata format (supports only keywords and comments) instead of XMP"),
2715 options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2718 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2719 pref_checkbox_new_int(group, _("Write the same description tags (keywords, comment, etc.) to all grouped sidecars"),
2720 options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2722 pref_checkbox_new_int(group, _("Allow keywords to differ only in case"),
2723 options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2725 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"),
2726 options->metadata.write_orientation, &c_options->metadata.write_orientation);
2728 gtk_widget_set_sensitive(ct_button, FALSE);
2731 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2733 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"),
2734 options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2736 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2737 pref_checkbox_link_sensitivity(ct_button, hbox);
2739 pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1,
2740 options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2742 pref_checkbox_new_int(group, _("Write metadata on image change"),
2743 options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2745 pref_checkbox_new_int(group, _("Write metadata on directory change"),
2746 options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2748 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2750 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"),
2751 options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2752 gtk_widget_set_tooltip_text(ct_button,"On folder change, read DateTimeOriginal, DateTimeDigitized and Star Rating in the idle loop.\nIf this is not selected, initial loading of the folder will be faster but sorting on these items will be slower");
2757 typedef struct _KeywordFindData KeywordFindData;
2758 struct _KeywordFindData
2765 GtkWidget *button_close;
2766 GtkWidget *button_stop;
2767 GtkWidget *button_start;
2768 GtkWidget *progress;
2776 guint idle_id; /* event source id */
2779 #define KEYWORD_DIALOG_WIDTH 400
2781 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
2783 GList *list_d = NULL;
2784 GList *list_f = NULL;
2788 filelist_read(dir_fd, &list_f, &list_d);
2792 filelist_read(dir_fd, &list_f, NULL);
2795 list_f = filelist_filter(list_f, FALSE);
2796 list_d = filelist_filter(list_d, TRUE);
2798 kfd->list = g_list_concat(list_f, kfd->list);
2799 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
2802 static void keywords_find_reset(KeywordFindData *kfd)
2804 filelist_free(kfd->list);
2807 filelist_free(kfd->list_dir);
2808 kfd->list_dir = NULL;
2811 static void keywords_find_close_cb(GenericDialog *fd, gpointer data)
2813 KeywordFindData *kfd = data;
2815 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
2817 keywords_find_reset(kfd);
2818 generic_dialog_close(kfd->gd);
2822 static void keywords_find_finish(KeywordFindData *kfd)
2824 keywords_find_reset(kfd);
2826 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
2827 spinner_set_interval(kfd->spinner, -1);
2829 gtk_widget_set_sensitive(kfd->group, TRUE);
2830 gtk_widget_set_sensitive(kfd->button_start, TRUE);
2831 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2832 gtk_widget_set_sensitive(kfd->button_close, TRUE);
2835 static void keywords_find_stop_cb(GenericDialog *fd, gpointer data)
2837 KeywordFindData *kfd = data;
2839 g_idle_remove_by_data(kfd);
2841 keywords_find_finish(kfd);
2844 static gboolean keywords_find_file(gpointer data)
2846 KeywordFindData *kfd = data;
2848 GtkTextBuffer *buffer;
2856 fd = kfd->list->data;
2857 kfd->list = g_list_remove(kfd->list, fd);
2859 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
2860 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2864 gtk_text_buffer_get_end_iter(buffer, &iter);
2865 tmp = g_strconcat(keywords->data, "\n", NULL);
2866 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
2868 keywords = keywords->next;
2871 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
2872 file_data_unref(fd);
2873 string_list_free(keywords);
2877 else if (kfd->list_dir)
2881 fd = kfd->list_dir->data;
2882 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
2884 keywords_find_folder(kfd, fd);
2886 file_data_unref(fd);
2891 keywords_find_finish(kfd);
2896 static void keywords_find_start_cb(GenericDialog *fd, gpointer data)
2898 KeywordFindData *kfd = data;
2901 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
2903 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
2904 parse_out_relatives(path);
2908 warning_dialog(_("Invalid folder"),
2909 _("The specified folder can not be found."),
2910 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
2916 gtk_widget_set_sensitive(kfd->group, FALSE);
2917 gtk_widget_set_sensitive(kfd->button_start, FALSE);
2918 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
2919 gtk_widget_set_sensitive(kfd->button_close, FALSE);
2920 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
2922 dir_fd = file_data_new_dir(path);
2923 keywords_find_folder(kfd, dir_fd);
2924 file_data_unref(dir_fd);
2925 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
2931 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
2933 KeywordFindData *kfd;
2937 kfd = g_new0(KeywordFindData, 1);
2939 kfd->gd = generic_dialog_new(_("Search for keywords"),
2940 "search_for_keywords",
2943 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
2944 kfd->gd->cancel_cb = keywords_find_close_cb;
2945 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
2946 keywords_find_close_cb, FALSE);
2947 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
2948 keywords_find_start_cb, FALSE);
2949 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
2950 keywords_find_stop_cb, FALSE);
2951 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2953 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
2955 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
2956 pref_spacer(hbox, PREF_PAD_INDENT);
2957 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2959 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2960 pref_label_new(hbox, _("Folder:"));
2962 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
2963 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
2964 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
2965 gtk_widget_show(label);
2967 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
2969 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
2970 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2972 kfd->progress = gtk_entry_new();
2973 gtk_widget_set_can_focus(kfd->progress, FALSE);
2974 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
2975 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
2976 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
2977 gtk_widget_show(kfd->progress);
2979 kfd->spinner = spinner_new(NULL, -1);
2980 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
2981 gtk_widget_show(kfd->spinner);
2985 gtk_widget_show(kfd->gd->dialog);
2988 static void keywords_find_cb(GtkWidget *widget, gpointer data)
2990 const gchar *path = layout_get_path(NULL);
2992 if (!path || !*path) path = homedir();
2993 keywords_find_dialog(widget, path);
2996 static void config_tab_keywords_save()
2998 GtkTextIter start, end;
2999 GtkTextBuffer *buffer;
3000 GList *kw_list = NULL;
3006 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3007 gtk_text_buffer_get_bounds(buffer, &start, &end);
3009 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3011 kw_split = strtok(buffer_text, "\n");
3012 while (kw_split != NULL)
3018 if (g_strcmp0(work->data, kw_split) == 0)
3027 kw_list = g_list_append(kw_list, g_strdup(kw_split));
3029 kw_split = strtok(NULL, "\n");
3032 keyword_list_set(kw_list);
3034 string_list_free(kw_list);
3035 g_free(buffer_text);
3038 static void config_tab_keywords(GtkWidget *notebook)
3044 GtkWidget *scrolled;
3046 GtkTextBuffer *buffer;
3049 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3051 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3053 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3055 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
3056 G_CALLBACK(keywords_find_cb), keyword_text);
3057 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
3060 keyword_text = gtk_text_view_new();
3061 gtk_widget_set_size_request(keyword_text, 20, 20);
3062 scrolled = gtk_scrolled_window_new(NULL, NULL);
3063 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3064 gtk_widget_show(scrolled);
3066 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
3067 gtk_widget_show(keyword_text);
3069 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3071 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3072 gtk_text_buffer_create_tag(buffer, "monospace",
3073 "family", "monospace", NULL);
3075 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3076 gtk_text_buffer_get_start_iter(buffer, &iter);
3077 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3080 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3082 GList *kwl = keyword_list_get();
3083 kwl = g_list_first(kwl);
3086 gtk_text_buffer_get_end_iter (buffer, &iter);
3087 tmp = g_strconcat(kwl->data, "\n", NULL);
3088 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3093 gtk_text_buffer_set_modified(buffer, FALSE);
3100 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3102 gint *option = data;
3104 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3108 *option = INTENT_PERCEPTUAL;
3111 *option = INTENT_RELATIVE_COLORIMETRIC;
3114 *option = INTENT_SATURATION;
3117 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3122 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3123 gint option, gint *option_c)
3130 pref_table_label(table, column, row, text, 0.0);
3132 combo = gtk_combo_box_text_new();
3134 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3135 if (option == INTENT_PERCEPTUAL) current = 0;
3136 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3137 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3138 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3139 if (option == INTENT_SATURATION) current = 2;
3140 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3141 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3143 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3145 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3147 g_signal_connect(G_OBJECT(combo), "changed",
3148 G_CALLBACK(intent_menu_cb), option_c);
3150 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
3151 gtk_widget_show(combo);
3155 static void config_tab_color(GtkWidget *notebook)
3164 vbox = scrolled_notebook_page(notebook, _("Color management"));
3166 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3168 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3171 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3172 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3174 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3175 pref_label_bold(label, TRUE, FALSE);
3177 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3178 pref_label_bold(label, TRUE, FALSE);
3180 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3181 pref_label_bold(label, TRUE, FALSE);
3183 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3188 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3189 pref_table_label(table, 0, i + 1, buf, 1.0);
3192 entry = gtk_entry_new();
3193 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3194 if (options->color_profile.input_name[i])
3196 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3198 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3199 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3200 gtk_widget_show(entry);
3201 color_profile_input_name_entry[i] = entry;
3203 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3204 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3205 gtk_widget_set_size_request(entry, 160, -1);
3206 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3207 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3208 gtk_widget_show(tabcomp);
3209 color_profile_input_file_entry[i] = entry;
3212 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3214 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3216 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3217 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3219 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3221 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3222 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3223 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3224 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3225 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3227 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3229 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3231 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3233 gtk_widget_show(tabcomp);
3236 /* advanced entry tab */
3237 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer data)
3239 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3241 c_options->file_ops.use_system_trash = FALSE;
3242 c_options->file_ops.no_trash = FALSE;
3246 static void use_system_trash_cb(GtkWidget *widget, gpointer data)
3248 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3250 c_options->file_ops.use_system_trash = TRUE;
3251 c_options->file_ops.no_trash = FALSE;
3255 static void use_no_cache_cb(GtkWidget *widget, gpointer data)
3257 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3259 c_options->file_ops.no_trash = TRUE;
3263 static void config_tab_behavior(GtkWidget *notebook)
3270 GtkWidget *ct_button;
3274 GtkWidget *with_rename;
3275 GtkWidget *collections_on_top;
3276 GtkWidget *hide_window_in_fullscreen;
3277 GtkWidget *checkbox;
3279 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3281 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3283 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3284 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3285 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3286 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3287 pref_checkbox_new_int(group, _("Enable Delete key"),
3288 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3290 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3291 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3293 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3294 pref_checkbox_link_sensitivity(ct_button, hbox);
3296 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3297 pref_label_new(hbox, _("Folder:"));
3299 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3300 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3301 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3302 gtk_widget_show(tabcomp);
3304 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3305 pref_checkbox_link_sensitivity(ct_button, hbox);
3307 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3308 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MB"),
3309 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3310 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3311 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3312 G_CALLBACK(safe_delete_view_cb), NULL);
3313 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3314 gtk_widget_show(button);
3316 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3317 G_CALLBACK(safe_delete_clear_cb), NULL);
3318 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3319 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3320 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3322 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3323 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3325 gtk_widget_show(button);
3327 pref_spacer(group, PREF_PAD_GROUP);
3330 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3332 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3333 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3335 pref_checkbox_new_int(group, _("In place renaming"),
3336 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3338 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3339 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3341 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3342 options->marks_save, &c_options->marks_save);
3343 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3345 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3346 options->with_rename, &c_options->with_rename);
3347 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3349 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3350 options->collections_on_top, &c_options->collections_on_top);
3351 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3353 hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3354 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3355 gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice");
3357 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3358 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3360 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3361 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3363 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3364 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3366 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3367 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3369 pref_spacer(group, PREF_PAD_GROUP);
3371 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3373 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3374 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3375 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3376 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3377 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3378 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3379 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3380 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3381 pref_checkbox_new_int(group, _("Play video by left click on image"),
3382 options->image_l_click_video, &c_options->image_l_click_video);
3383 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3384 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3386 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3387 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3388 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3389 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3390 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3392 pref_spacer(group, PREF_PAD_GROUP);
3394 group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3396 checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3397 options->override_disable_gpu, &c_options->override_disable_gpu);
3398 gtk_widget_set_tooltip_text(checkbox, "Contact the developers for usage");
3401 pref_spacer(group, PREF_PAD_GROUP);
3403 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3405 pref_spin_new_int(group, _("Debug level:"), NULL,
3406 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3408 pref_checkbox_new_int(group, _("Timer data"),
3409 options->log_window.timer_data, &c_options->log_window.timer_data);
3411 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3412 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3416 /* accelerators tab */
3417 static void config_tab_accelerators(GtkWidget *notebook)
3423 GtkWidget *scrolled;
3424 GtkWidget *accel_view;
3425 GtkCellRenderer *renderer;
3426 GtkTreeSelection *selection;
3427 GtkTreeViewColumn *column;
3429 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3431 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3433 scrolled = gtk_scrolled_window_new(NULL, NULL);
3434 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3435 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3436 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3437 gtk_widget_show(scrolled);
3439 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3441 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3442 g_object_unref(accel_store);
3443 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3444 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3446 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3448 renderer = gtk_cell_renderer_text_new();
3450 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3455 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3456 gtk_tree_view_column_set_resizable(column, TRUE);
3457 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3460 renderer = gtk_cell_renderer_accel_new();
3461 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3462 G_CALLBACK(accel_store_cleared_cb), accel_store);
3463 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3464 G_CALLBACK(accel_store_edited_cb), accel_store);
3467 g_object_set (renderer,
3469 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3472 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3477 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3478 gtk_tree_view_column_set_resizable(column, TRUE);
3479 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3481 renderer = gtk_cell_renderer_text_new();
3483 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3488 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3489 gtk_tree_view_column_set_resizable(column, TRUE);
3490 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3492 renderer = gtk_cell_renderer_text_new();
3494 column = gtk_tree_view_column_new_with_attributes("Accel",
3499 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3500 gtk_tree_view_column_set_resizable(column, TRUE);
3501 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3503 accel_store_populate();
3504 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3505 gtk_widget_show(accel_view);
3507 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3509 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3510 G_CALLBACK(accel_default_cb), accel_view);
3511 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3512 gtk_widget_show(button);
3514 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3515 G_CALLBACK(accel_reset_cb), accel_view);
3516 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3517 gtk_widget_show(button);
3520 /* toolbar main tab */
3521 static void config_tab_toolbar_main(GtkWidget *notebook)
3524 GtkWidget *toolbardata;
3527 lw = layout_window_list->data;
3529 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3531 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3532 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3533 gtk_widget_show(vbox);
3536 /* toolbar status tab */
3537 static void config_tab_toolbar_status(GtkWidget *notebook)
3540 GtkWidget *toolbardata;
3543 lw = layout_window_list->data;
3545 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3547 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3548 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3549 gtk_widget_show(vbox);
3553 static void config_tab_stereo(GtkWidget *notebook)
3561 GtkWidget *fs_button;
3562 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3564 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3566 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3567 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3569 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3570 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3571 pref_checkbox_new_int(box, _("Mirror left image"),
3572 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3573 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3574 pref_checkbox_new_int(box, _("Flip left image"),
3575 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3576 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3577 pref_checkbox_new_int(box, _("Mirror right image"),
3578 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3579 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3580 pref_checkbox_new_int(box, _("Flip right image"),
3581 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3582 pref_checkbox_new_int(group, _("Swap left and right images"),
3583 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3584 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3585 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3587 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3588 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3589 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3590 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3591 pref_checkbox_link_sensitivity(fs_button, box2);
3592 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3593 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3594 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3595 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3596 pref_checkbox_new_int(box, _("Mirror left image"),
3597 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3598 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3599 pref_checkbox_new_int(box, _("Flip left image"),
3600 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3601 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3602 pref_checkbox_new_int(box, _("Mirror right image"),
3603 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3604 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3605 pref_checkbox_new_int(box, _("Flip right image"),
3606 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3607 pref_checkbox_new_int(box2, _("Swap left and right images"),
3608 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3609 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3610 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3612 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3613 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3614 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3615 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3616 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
3617 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3618 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
3619 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3620 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
3621 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3622 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
3623 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3624 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
3625 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3629 /* Main preferences window */
3630 static void config_window_create(void)
3632 GtkWidget *win_vbox;
3634 GtkWidget *notebook;
3636 GtkWidget *ct_button;
3638 if (!c_options) c_options = init_options(NULL);
3640 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3641 DEBUG_NAME(configwindow);
3642 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3643 g_signal_connect(G_OBJECT(configwindow), "delete_event",
3644 G_CALLBACK(config_window_delete), NULL);
3645 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
3646 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
3647 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
3649 win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
3650 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
3651 gtk_widget_show(win_vbox);
3653 notebook = gtk_notebook_new();
3654 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
3655 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
3656 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
3658 config_tab_general(notebook);
3659 config_tab_image(notebook);
3660 config_tab_osd(notebook);
3661 config_tab_windows(notebook);
3662 config_tab_accelerators(notebook);
3663 config_tab_files(notebook);
3664 config_tab_metadata(notebook);
3665 config_tab_keywords(notebook);
3666 config_tab_color(notebook);
3667 config_tab_stereo(notebook);
3668 config_tab_behavior(notebook);
3669 config_tab_toolbar_main(notebook);
3670 config_tab_toolbar_status(notebook);
3672 hbox = gtk_hbutton_box_new();
3673 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
3674 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
3675 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
3676 gtk_widget_show(hbox);
3678 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
3679 G_CALLBACK(config_window_help_cb), notebook);
3680 gtk_container_add(GTK_CONTAINER(hbox), button);
3681 gtk_widget_set_can_default(button, TRUE);
3682 gtk_widget_show(button);
3684 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
3685 G_CALLBACK(config_window_ok_cb), NULL);
3686 gtk_container_add(GTK_CONTAINER(hbox), button);
3687 gtk_widget_set_can_default(button, TRUE);
3688 gtk_widget_grab_default(button);
3689 gtk_widget_show(button);
3693 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
3694 G_CALLBACK(config_window_close_cb), NULL);
3695 gtk_container_add(GTK_CONTAINER(hbox), button);
3696 gtk_widget_set_can_default(button, TRUE);
3697 gtk_widget_show(button);
3699 if (!generic_dialog_get_alternative_button_order(configwindow))
3701 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
3704 gtk_widget_show(notebook);
3706 gtk_widget_show(configwindow);
3710 *-----------------------------------------------------------------------------
3711 * config window show (public)
3712 *-----------------------------------------------------------------------------
3715 void show_config_window(void)
3719 gtk_window_present(GTK_WINDOW(configwindow));
3723 config_window_create();
3732 void show_about_window(LayoutWindow *lw)
3734 GdkPixbuf *pixbuf_logo;
3735 GdkPixbuf *pixbuf_icon;
3736 gchar *authors[1000];
3741 gchar *timezone_path;
3745 #define LINE_LENGTH 1000
3746 gchar line[LINE_LENGTH];
3748 copyright = g_string_new(NULL);
3749 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");
3751 path = path_from_utf8(TIMEZONE_DATABASE);
3752 basename = g_path_get_basename(path);
3753 timezone_path = g_build_filename(get_rc_dir(), basename, NULL);
3754 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
3756 cd = ZDOpenDatabase(timezone_path);
3759 copyright = g_string_append(copyright, ZDGetNotice(cd));
3760 ZDCloseDatabase(cd);
3764 g_free(timezone_path);
3768 path = g_build_filename(GQ_HELPDIR, "AUTHORS", NULL);
3769 fp = fopen(path, "r");
3772 while(fgets(line, LINE_LENGTH, fp))
3774 /* get rid of ending \n from fgets */
3775 line[strlen(line) - 1] = '\0';
3776 authors[i_authors] = g_strdup(line);
3779 authors[i_authors] = NULL;
3784 comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
3785 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
3787 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
3788 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
3789 gtk_show_about_dialog(GTK_WINDOW(lw->window),
3790 "title", _("About Geeqie"),
3792 "program-name", GQ_APPNAME,
3794 "logo", pixbuf_logo,
3795 "icon", pixbuf_icon,
3796 "website", GQ_WEBSITE,
3797 "website-label", "Website",
3798 "comments", comment,
3800 "translator-credits", _("translator-credits"),
3801 "wrap-license", TRUE,
3802 "license", copyright->str,
3805 g_string_free(copyright, TRUE);
3808 while(n < i_authors)
3818 static void image_overlay_set_text_colours()
3820 c_options->image_overlay.text_red = options->image_overlay.text_red;
3821 c_options->image_overlay.text_green = options->image_overlay.text_green;
3822 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
3823 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
3824 c_options->image_overlay.background_red = options->image_overlay.background_red;
3825 c_options->image_overlay.background_green = options->image_overlay.background_green;
3826 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
3827 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
3831 *-----------------------------------------------------------------------------
3832 * timezone database routines
3833 *-----------------------------------------------------------------------------
3836 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
3838 GError *error = NULL;
3840 gchar *tmp_filename;
3842 if (!g_cancellable_is_cancelled(tz->cancellable))
3844 generic_dialog_close(tz->gd);
3848 if (g_file_copy_finish(G_FILE(source_object), res, &error))
3850 tmp_filename = g_file_get_parse_name(tz->tmp_g_file);
3851 move_file(tmp_filename, tz->timezone_database_user);
3852 g_free(tmp_filename);
3856 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3859 g_file_delete(tz->tmp_g_file, NULL, &error);
3860 g_object_unref(tz->tmp_g_file);
3861 tz->tmp_g_file = NULL;
3862 g_object_unref(tz->cancellable);
3863 g_object_unref(tz->timezone_database_gq);
3866 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
3870 if (!g_cancellable_is_cancelled(tz->cancellable))
3872 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
3876 static void timezone_cancel_button_cb(GenericDialog *gd, gpointer data)
3880 g_cancellable_cancel(tz->cancellable);
3883 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
3886 GError *error = NULL;
3887 GFileIOStream *io_stream;
3894 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
3898 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3899 log_printf("Error: Download timezone database failed:\n%s", error->message);
3900 g_error_free(error);
3901 g_object_unref(tz->tmp_g_file);
3905 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE);
3907 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
3909 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
3911 tz->progress = gtk_progress_bar_new();
3912 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
3913 gtk_widget_show(tz->progress);
3915 gtk_widget_show(tz->gd->dialog);
3916 tz->cancellable = g_cancellable_new();
3917 g_file_copy_async(tz->timezone_database_gq, tz->tmp_g_file, G_FILE_COPY_OVERWRITE, G_PRIORITY_LOW, tz->cancellable, timezone_progress_cb, tz, timezone_async_ready_cb, tz);
3919 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
3922 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */