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.
22 #include "preferences.h"
26 #include "bar-keywords.h"
28 #include "color-man.h"
33 #include "filefilter.h"
34 #include "fullscreen.h"
36 #include "image-overlay.h"
39 #include "layout-util.h"
41 #include "main-defines.h"
45 #include "pixbuf-util.h"
47 #include "slideshow.h"
51 #include "ui-fileops.h"
53 #include "ui-tabcomp.h"
55 #include "zonedetect.h"
66 #include <gspell/gspell.h>
70 EDITOR_NAME_MAX_LENGTH = 32,
71 EDITOR_COMMAND_MAX_LENGTH = 1024
74 static void image_overlay_set_text_colors();
76 GtkWidget *keyword_text;
77 static void config_tab_keywords_save();
85 static ThumbSize thumb_size_list[] =
120 FILETYPES_COLUMN_ENABLED = 0,
121 FILETYPES_COLUMN_FILTER,
122 FILETYPES_COLUMN_DESCRIPTION,
123 FILETYPES_COLUMN_CLASS,
124 FILETYPES_COLUMN_WRITABLE,
125 FILETYPES_COLUMN_SIDECAR,
126 FILETYPES_COLUMN_COUNT
129 const gchar *format_class_list[] = {
140 /* config memory values */
141 static ConfOptions *c_options = nullptr;
148 static GtkWidget *configwindow = nullptr;
149 static GtkListStore *filter_store = nullptr;
150 static GtkTreeStore *accel_store = nullptr;
152 static GtkWidget *safe_delete_path_entry;
154 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
155 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
156 static GtkWidget *color_profile_screen_file_entry;
157 static GtkWidget *external_preview_select_entry;
158 static GtkWidget *external_preview_extract_entry;
160 static GtkWidget *sidecar_ext_entry;
161 static GtkWidget *help_search_engine_entry;
163 static GtkWidget *log_window_f1_entry;
167 CONFIG_WINDOW_DEF_WIDTH = 700,
168 CONFIG_WINDOW_DEF_HEIGHT = 600
172 *-----------------------------------------------------------------------------
173 * option widget callbacks (private)
174 *-----------------------------------------------------------------------------
177 static void zoom_increment_cb(GtkWidget *spin, gpointer)
179 c_options->image.zoom_increment = static_cast<gint>(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
182 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer)
184 gint mins_secs_tenths;
187 mins_secs_tenths = c_options->slideshow.delay %
188 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
190 delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
191 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
194 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
195 SLIDESHOW_SUBSECOND_PRECISION;
198 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer)
204 hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
205 secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
207 delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
208 (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
209 (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
211 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
212 SLIDESHOW_SUBSECOND_PRECISION;
215 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer)
220 hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
222 delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
223 static_cast<gint>(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
224 static_cast<gdouble>(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
226 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
227 SLIDESHOW_SUBSECOND_PRECISION;
231 *-----------------------------------------------------------------------------
232 * sync program to config window routine (private)
233 *-----------------------------------------------------------------------------
236 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
242 buf = gq_gtk_entry_get_text(GTK_ENTRY(entry));
243 if (buf && strlen(buf) > 0)
248 *option = g_strdup(buf);
253 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *, GtkTreeIter *iter, gpointer)
258 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
260 if (accel_path && accel_path[0])
263 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
264 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
274 static void config_window_apply()
276 gboolean refresh = FALSE;
281 config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
283 if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
284 if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
285 if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
286 if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
287 if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
288 if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
290 options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
291 options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
292 options->file_ops.confirm_move_to_trash = c_options->file_ops.confirm_move_to_trash;
293 options->file_ops.use_system_trash = c_options->file_ops.use_system_trash;
294 options->file_ops.no_trash = c_options->file_ops.no_trash;
295 options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
296 options->tools_restore_state = c_options->tools_restore_state;
297 options->save_window_positions = c_options->save_window_positions;
298 options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
299 options->save_window_workspace = c_options->save_window_workspace;
300 options->save_dialog_window_positions = c_options->save_dialog_window_positions;
301 options->show_window_ids = c_options->show_window_ids;
302 options->image.scroll_reset_method = c_options->image.scroll_reset_method;
303 options->image.zoom_2pass = c_options->image.zoom_2pass;
304 options->image.fit_window_to_image = c_options->image.fit_window_to_image;
305 options->image.limit_window_size = c_options->image.limit_window_size;
306 options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
307 options->image.max_window_size = c_options->image.max_window_size;
308 options->image.limit_autofit_size = c_options->image.limit_autofit_size;
309 options->image.max_autofit_size = c_options->image.max_autofit_size;
310 options->image.max_enlargement_size = c_options->image.max_enlargement_size;
311 options->image.tile_size = c_options->image.tile_size;
312 options->progressive_key_scrolling = c_options->progressive_key_scrolling;
313 options->keyboard_scroll_step = c_options->keyboard_scroll_step;
315 if (options->thumbnails.max_width != c_options->thumbnails.max_width
316 || options->thumbnails.max_height != c_options->thumbnails.max_height
317 || options->thumbnails.quality != c_options->thumbnails.quality)
319 thumb_format_changed = TRUE;
321 options->thumbnails.max_width = c_options->thumbnails.max_width;
322 options->thumbnails.max_height = c_options->thumbnails.max_height;
323 options->thumbnails.quality = c_options->thumbnails.quality;
325 options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
326 options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
327 options->thumbnails.use_exif = c_options->thumbnails.use_exif;
328 options->thumbnails.use_color_management = c_options->thumbnails.use_color_management;
329 options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
330 options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
331 options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
332 options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
333 options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
334 options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
335 options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
336 options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
338 options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
339 options->file_filter.disable = c_options->file_filter.disable;
341 config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, nullptr);
342 sidecar_ext_parse(options->sidecar.ext);
344 options->slideshow.random = c_options->slideshow.random;
345 options->slideshow.repeat = c_options->slideshow.repeat;
346 options->slideshow.delay = c_options->slideshow.delay;
348 options->mousewheel_scrolls = c_options->mousewheel_scrolls;
349 options->image_lm_click_nav = c_options->image_lm_click_nav;
350 options->image_l_click_archive = c_options->image_l_click_archive;
351 options->image_l_click_video = c_options->image_l_click_video;
352 options->image_l_click_video_editor = c_options->image_l_click_video_editor;
354 options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
356 options->image.tile_cache_max = c_options->image.tile_cache_max;
357 options->image.image_cache_max = c_options->image.image_cache_max;
359 options->image.zoom_quality = c_options->image.zoom_quality;
361 options->image.zoom_increment = c_options->image.zoom_increment;
363 options->image.zoom_style = c_options->image.zoom_style;
365 options->image.enable_read_ahead = c_options->image.enable_read_ahead;
367 options->appimage_notifications = c_options->appimage_notifications;
370 if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
371 || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
372 || !gdk_rgba_equal(&options->image.border_color, &c_options->image.border_color))
374 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
375 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
376 options->image.border_color = c_options->image.border_color;
377 layout_colors_update();
378 view_window_colors_update();
381 options->image.alpha_color_1 = c_options->image.alpha_color_1;
382 options->image.alpha_color_2 = c_options->image.alpha_color_2;
384 options->fullscreen.screen = c_options->fullscreen.screen;
385 options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
386 options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
387 options->fullscreen.above = c_options->fullscreen.above;
388 if (c_options->image_overlay.template_string)
389 set_image_overlay_template_string(&options->image_overlay.template_string,
390 c_options->image_overlay.template_string);
391 if (c_options->image_overlay.font)
392 set_image_overlay_font_string(&options->image_overlay.font,
393 c_options->image_overlay.font);
394 options->image_overlay.text_red = c_options->image_overlay.text_red;
395 options->image_overlay.text_green = c_options->image_overlay.text_green;
396 options->image_overlay.text_blue = c_options->image_overlay.text_blue;
397 options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
398 options->image_overlay.background_red = c_options->image_overlay.background_red;
399 options->image_overlay.background_green = c_options->image_overlay.background_green;
400 options->image_overlay.background_blue = c_options->image_overlay.background_blue;
401 options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
402 options->image_overlay.font = c_options->image_overlay.font;
403 options->update_on_time_change = c_options->update_on_time_change;
405 options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
406 options->rot_invariant_sim = c_options->rot_invariant_sim;
408 options->tree_descend_subdirs = c_options->tree_descend_subdirs;
410 options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
411 options->circular_selection_lists = c_options->circular_selection_lists;
413 options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
414 options->recent_folder_image_list_maxsize = c_options->recent_folder_image_list_maxsize;
415 options->dnd_icon_size = c_options->dnd_icon_size;
416 options->clipboard_selection = c_options->clipboard_selection;
417 options->dnd_default_action = c_options->dnd_default_action;
419 options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
420 options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
421 options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
422 options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
423 options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
424 options->metadata.confirm_write = c_options->metadata.confirm_write;
425 options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
426 options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
427 options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
428 options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
429 options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
430 options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
431 options->metadata.write_orientation = c_options->metadata.write_orientation;
432 options->metadata.check_spelling = c_options->metadata.check_spelling;
433 options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
434 (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
435 (c_options->stereo.tmp.flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
436 (c_options->stereo.tmp.mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
437 (c_options->stereo.tmp.flip_left ? PR_STEREO_FLIP_LEFT : 0) |
438 (c_options->stereo.tmp.swap ? PR_STEREO_SWAP : 0) |
439 (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
440 options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
441 (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
442 (c_options->stereo.tmp.fs_flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
443 (c_options->stereo.tmp.fs_mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
444 (c_options->stereo.tmp.fs_flip_left ? PR_STEREO_FLIP_LEFT : 0) |
445 (c_options->stereo.tmp.fs_swap ? PR_STEREO_SWAP : 0) |
446 (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
447 options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
448 options->stereo.fixed_w = c_options->stereo.fixed_w;
449 options->stereo.fixed_h = c_options->stereo.fixed_h;
450 options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
451 options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
452 options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
453 options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
455 options->info_keywords.height = c_options->info_keywords.height;
456 options->info_title.height = c_options->info_title.height;
457 options->info_comment.height = c_options->info_comment.height;
458 options->info_rating.height = c_options->info_rating.height;
460 options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
461 options->expand_menu_toolbar = c_options->expand_menu_toolbar;
462 options->hamburger_menu = c_options->hamburger_menu;
464 options->selectable_bars.menu_bar = c_options->selectable_bars.menu_bar;
465 options->selectable_bars.tool_bar = c_options->selectable_bars.tool_bar;
466 options->selectable_bars.status_bar = c_options->selectable_bars.status_bar;
468 options->marks_save = c_options->marks_save;
469 options->with_rename = c_options->with_rename;
470 options->collections_duplicates = c_options->collections_duplicates;
471 options->collections_on_top = c_options->collections_on_top;
472 options->hide_window_in_fullscreen = c_options->hide_window_in_fullscreen;
473 config_entry_to_option(help_search_engine_entry, &options->help_search_engine, nullptr);
475 options->external_preview.enable = c_options->external_preview.enable;
476 config_entry_to_option(external_preview_select_entry, &options->external_preview.select, nullptr);
477 config_entry_to_option(external_preview_extract_entry, &options->external_preview.extract, nullptr);
479 options->read_metadata_in_idle = c_options->read_metadata_in_idle;
481 options->star_rating.star = c_options->star_rating.star;
482 options->star_rating.rejected = c_options->star_rating.rejected;
484 options->threads.duplicates = c_options->threads.duplicates > 0 ? c_options->threads.duplicates : -1;
486 options->alternate_similarity_algorithm.enabled = c_options->alternate_similarity_algorithm.enabled;
487 options->alternate_similarity_algorithm.grayscale = c_options->alternate_similarity_algorithm.grayscale;
490 set_debug_level(debug_c);
491 config_entry_to_option(log_window_f1_entry, &options->log_window.action, nullptr);
495 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
497 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], nullptr);
498 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], nullptr);
500 config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, nullptr);
501 options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
502 if (options->color_profile.render_intent != c_options->color_profile.render_intent)
504 options->color_profile.render_intent = c_options->color_profile.render_intent;
509 options->mouse_button_8 = c_options->mouse_button_8;
510 options->mouse_button_9 = c_options->mouse_button_9;
512 options->override_disable_gpu = c_options->override_disable_gpu;
514 config_tab_keywords_save();
516 image_options_sync();
521 layout_refresh(nullptr);
524 if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, nullptr);
526 toolbar_apply(TOOLBAR_MAIN);
527 toolbar_apply(TOOLBAR_STATUS);
531 *-----------------------------------------------------------------------------
532 * config window main button callbacks (private)
533 *-----------------------------------------------------------------------------
536 static void config_window_close_cb(GtkWidget *, gpointer)
538 gq_gtk_widget_destroy(configwindow);
539 configwindow = nullptr;
540 filter_store = nullptr;
543 static void config_window_help_cb(GtkWidget *, gpointer data)
545 auto notebook = static_cast<GtkWidget *>(data);
548 static const gchar *html_section[] =
550 "GuideOptionsGeneral.html",
551 "GuideOptionsImage.html",
552 "GuideOptionsOSD.html",
553 "GuideOptionsWindow.html",
554 "GuideOptionsKeyboard.html",
555 "GuideOptionsFiltering.html",
556 "GuideOptionsMetadata.html",
557 "GuideOptionsKeywords.html",
558 "GuideOptionsColor.html",
559 "GuideOptionsStereo.html",
560 "GuideOptionsBehavior.html",
561 "GuideOptionsToolbar.html",
562 "GuideOptionsToolbar.html",
563 "GuideOptionsAdvanced.html"
566 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
567 help_window_show(html_section[i]);
570 static gboolean config_window_delete(GtkWidget *, GdkEventAny *, gpointer)
572 config_window_close_cb(nullptr, nullptr);
576 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
579 auto notebook = static_cast<GtkNotebook *>(data);
587 lw = static_cast<LayoutWindow *>(layout_window_list->data);
589 window = gtk_widget_get_window(widget);
590 gdk_window_get_root_origin(window, &x, &y);
591 w = gdk_window_get_width(window);
592 h = gdk_window_get_height(window);
593 page_number = gtk_notebook_get_current_page(notebook);
595 lw->options.preferences_window.x = x;
596 lw->options.preferences_window.y = y;
597 lw->options.preferences_window.w = w;
598 lw->options.preferences_window.h = h;
599 lw->options.preferences_window.page_number = page_number;
601 config_window_apply();
602 layout_util_sync(lw);
603 save_options(options);
604 config_window_close_cb(nullptr, nullptr);
608 *-----------------------------------------------------------------------------
609 * config window setup (private)
610 *-----------------------------------------------------------------------------
613 static void quality_menu_cb(GtkWidget *combo, gpointer data)
615 auto option = static_cast<gint *>(data);
617 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
621 *option = GDK_INTERP_NEAREST;
624 *option = GDK_INTERP_TILES;
627 *option = GDK_INTERP_BILINEAR;
632 static void dnd_default_action_selection_menu_cb(GtkWidget *combo, gpointer data)
634 auto option = static_cast<gint *>(data);
636 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
640 *option = DND_ACTION_ASK;
643 *option = DND_ACTION_COPY;
646 *option = DND_ACTION_MOVE;
650 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
652 auto option = static_cast<gint *>(data);
654 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
657 *option = CLIPBOARD_PRIMARY;
660 *option = CLIPBOARD_CLIPBOARD;
663 *option = CLIPBOARD_BOTH;
666 *option = CLIPBOARD_BOTH;
670 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
671 guint option, guint *option_c)
678 pref_table_label(table, column, row, text, GTK_ALIGN_START);
680 combo = gtk_combo_box_text_new();
682 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
683 if (option == GDK_INTERP_NEAREST) current = 0;
684 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
685 if (option == GDK_INTERP_TILES) current = 1;
686 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear (best, but slowest)"));
687 if (option == GDK_INTERP_BILINEAR) current = 2;
689 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
691 g_signal_connect(G_OBJECT(combo), "changed",
692 G_CALLBACK(quality_menu_cb), option_c);
694 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
695 gtk_widget_show(combo);
698 static void add_dnd_default_action_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, DnDAction option, DnDAction *option_c)
705 pref_table_label(table, column, row, text, GTK_ALIGN_START);
707 combo = gtk_combo_box_text_new();
709 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Ask"));
710 if (option == DND_ACTION_ASK) current = 0;
711 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Copy"));
712 if (option == DND_ACTION_COPY) current = 1;
713 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Move"));
714 if (option == DND_ACTION_MOVE) current = 2;
716 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
718 g_signal_connect(G_OBJECT(combo), "changed",
719 G_CALLBACK(dnd_default_action_selection_menu_cb), option_c);
721 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
722 gtk_widget_show(combo);
725 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
726 gint option, gint *option_c)
733 pref_table_label(table, column, row, text, GTK_ALIGN_START);
735 combo = gtk_combo_box_text_new();
737 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Primary"));
738 if (option == CLIPBOARD_PRIMARY) current = 0;
739 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Clipboard"));
740 if (option == CLIPBOARD_CLIPBOARD) current = 1;
741 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Both"));
742 if (option == CLIPBOARD_BOTH) current = 2;
744 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
746 g_signal_connect(G_OBJECT(combo), "changed",
747 G_CALLBACK(clipboard_selection_menu_cb), option_c);
749 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
750 gtk_widget_show(combo);
753 static void zoom_style_selection_menu_cb(GtkWidget *combo, gpointer data)
755 auto option = static_cast<gint *>(data);
757 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
760 *option = ZOOM_GEOMETRIC;
763 *option = ZOOM_ARITHMETIC;
766 *option = ZOOM_GEOMETRIC;
770 static void add_zoom_style_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, ZoomStyle option, ZoomStyle *option_c)
777 pref_table_label(table, column, row, text, GTK_ALIGN_START);
779 combo = gtk_combo_box_text_new();
781 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Geometric"));
782 if (option == ZOOM_GEOMETRIC) current = 0;
783 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Arithmetic"));
784 if (option == ZOOM_ARITHMETIC) current = 1;
786 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
788 g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(zoom_style_selection_menu_cb), option_c);
790 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
791 gtk_widget_show(combo);
794 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
796 ActionItem *action_item = nullptr;
797 auto option = static_cast<gchar **>(data);
802 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
804 list = get_action_items();
809 action_item = static_cast<ActionItem *>(work->data);
810 if (g_strcmp0(action_item->label, label) == 0)
818 *option = g_strdup(action_item->name);
820 action_items_free(list);
823 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, gchar *option, gchar **option_c)
825 ActionItem *action_item;
834 pref_table_label(table, column, row, text, GTK_ALIGN_START);
836 combo = gtk_combo_box_text_new();
838 list = get_action_items();
842 action_item = static_cast<ActionItem *>(work->data);
843 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), action_item->label);
845 if (g_strcmp0(action_item->name, option) == 0)
853 action_items_free(list);
855 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
857 g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
859 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
860 gtk_widget_show(combo);
863 static void thumb_size_menu_cb(GtkWidget *combo, gpointer)
867 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
870 if (static_cast<guint>(n) < sizeof(thumb_size_list) / sizeof(ThumbSize))
872 c_options->thumbnails.max_width = thumb_size_list[n].w;
873 c_options->thumbnails.max_height = thumb_size_list[n].h;
877 c_options->thumbnails.max_width = options->thumbnails.max_width;
878 c_options->thumbnails.max_height = options->thumbnails.max_height;
882 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
888 c_options->thumbnails.max_width = options->thumbnails.max_width;
889 c_options->thumbnails.max_height = options->thumbnails.max_height;
891 pref_table_label(table, column, row, text, GTK_ALIGN_START);
893 combo = gtk_combo_box_text_new();
896 for (i = 0; static_cast<guint>(i) < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
902 w = thumb_size_list[i].w;
903 h = thumb_size_list[i].h;
905 buf = g_strdup_printf("%d x %d", w, h);
906 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
909 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
916 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
917 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
923 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
924 g_signal_connect(G_OBJECT(combo), "changed",
925 G_CALLBACK(thumb_size_menu_cb), NULL);
927 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
928 gtk_widget_show(combo);
931 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
933 auto option = static_cast<gint *>(data);
935 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
939 *option = PR_STEREO_NONE;
942 *option = PR_STEREO_ANAGLYPH_RC;
945 *option = PR_STEREO_ANAGLYPH_GM;
948 *option = PR_STEREO_ANAGLYPH_YB;
951 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
954 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
957 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
960 *option = PR_STEREO_ANAGLYPH_DB_RC;
963 *option = PR_STEREO_ANAGLYPH_DB_GM;
966 *option = PR_STEREO_ANAGLYPH_DB_YB;
969 *option = PR_STEREO_HORIZ;
972 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
975 *option = PR_STEREO_VERT;
978 *option = PR_STEREO_VERT | PR_STEREO_HALF;
981 *option = PR_STEREO_FIXED;
986 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
987 gint option, gint *option_c, gboolean add_fixed)
994 pref_table_label(table, column, row, text, GTK_ALIGN_START);
996 combo = gtk_combo_box_text_new();
998 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
1000 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
1001 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
1002 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
1003 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
1004 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
1005 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
1006 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
1007 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
1008 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
1009 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
1010 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
1011 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
1012 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
1013 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
1014 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
1015 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
1016 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
1017 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
1019 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
1020 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
1021 if (option & PR_STEREO_HORIZ)
1024 if (option & PR_STEREO_HALF) current = 11;
1027 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
1028 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
1029 if (option & PR_STEREO_VERT)
1032 if (option & PR_STEREO_HALF) current = 13;
1037 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
1038 if (option & PR_STEREO_FIXED) current = 14;
1041 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1043 g_signal_connect(G_OBJECT(combo), "changed",
1044 G_CALLBACK(stereo_mode_menu_cb), option_c);
1046 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
1047 gtk_widget_show(combo);
1050 static void video_menu_cb(GtkWidget *combo, gpointer data)
1052 auto option = static_cast<gchar **>(data);
1054 auto ed = static_cast<EditorDescription *>(g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo))));
1058 static void video_menu_populate(gpointer data, gpointer user_data)
1060 auto combo = static_cast<GtkWidget *>(user_data);
1061 auto ed = static_cast<EditorDescription *>(data);
1063 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1066 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1067 gchar *option, gchar **option_c)
1071 /* use lists since they are sorted */
1072 GList *eds = editor_list_get();
1076 pref_table_label(table, column, row, text, GTK_ALIGN_START);
1078 combo = gtk_combo_box_text_new();
1079 g_list_foreach(eds,video_menu_populate,combo);
1080 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1082 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1084 g_signal_connect(G_OBJECT(combo), "changed",
1085 G_CALLBACK(video_menu_cb), option_c);
1087 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
1088 gtk_widget_show(combo);
1091 static void filter_store_populate()
1095 if (!filter_store) return;
1097 gtk_list_store_clear(filter_store);
1099 work = filter_get_list();
1105 fe = static_cast<FilterEntry *>(work->data);
1108 gtk_list_store_append(filter_store, &iter);
1109 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1113 static void filter_store_ext_edit_cb(GtkCellRendererText *, gchar *path_str, gchar *new_text, gpointer data)
1115 auto model = static_cast<GtkWidget *>(data);
1116 auto fe = static_cast<FilterEntry *>(data);
1120 if (!new_text || strlen(new_text) < 1) return;
1122 tpath = gtk_tree_path_new_from_string(path_str);
1123 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1124 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1126 g_free(fe->extensions);
1127 fe->extensions = g_strdup(new_text);
1129 gtk_tree_path_free(tpath);
1133 static void filter_store_class_edit_cb(GtkCellRendererText *, gchar *path_str, gchar *new_text, gpointer data)
1135 auto model = static_cast<GtkWidget *>(data);
1136 auto fe = static_cast<FilterEntry *>(data);
1141 if (!new_text || !new_text[0]) return;
1143 tpath = gtk_tree_path_new_from_string(path_str);
1144 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1145 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1147 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1149 if (strcmp(new_text, _(format_class_list[i])) == 0)
1151 fe->file_class = static_cast<FileFormatClass>(i);
1156 gtk_tree_path_free(tpath);
1160 static void filter_store_desc_edit_cb(GtkCellRendererText *, gchar *path_str, gchar *new_text, gpointer data)
1162 auto model = static_cast<GtkWidget *>(data);
1167 if (!new_text || !new_text[0]) return;
1169 tpath = gtk_tree_path_new_from_string(path_str);
1170 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1171 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1173 g_free(fe->description);
1174 fe->description = g_strdup(new_text);
1176 gtk_tree_path_free(tpath);
1179 static void filter_store_enable_cb(GtkCellRendererToggle *, gchar *path_str, gpointer data)
1181 auto model = static_cast<GtkWidget *>(data);
1186 tpath = gtk_tree_path_new_from_string(path_str);
1187 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1188 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1190 fe->enabled = !fe->enabled;
1192 gtk_tree_path_free(tpath);
1196 static void filter_store_writable_cb(GtkCellRendererToggle *, gchar *path_str, gpointer data)
1198 auto model = static_cast<GtkWidget *>(data);
1203 tpath = gtk_tree_path_new_from_string(path_str);
1204 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1205 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1207 fe->writable = !fe->writable;
1208 if (fe->writable) fe->allow_sidecar = FALSE;
1210 gtk_tree_path_free(tpath);
1214 static void filter_store_sidecar_cb(GtkCellRendererToggle *, gchar *path_str, gpointer data)
1216 auto model = static_cast<GtkWidget *>(data);
1221 tpath = gtk_tree_path_new_from_string(path_str);
1222 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1223 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1225 fe->allow_sidecar = !fe->allow_sidecar;
1226 if (fe->allow_sidecar) fe->writable = FALSE;
1228 gtk_tree_path_free(tpath);
1232 static void filter_set_func(GtkTreeViewColumn *, GtkCellRenderer *cell,
1233 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1237 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1239 switch (GPOINTER_TO_INT(data))
1242 g_object_set(GTK_CELL_RENDERER(cell),
1243 "active", fe->enabled, NULL);
1246 g_object_set(GTK_CELL_RENDERER(cell),
1247 "text", fe->extensions, NULL);
1249 case FE_DESCRIPTION:
1250 g_object_set(GTK_CELL_RENDERER(cell),
1251 "text", fe->description, NULL);
1254 g_object_set(GTK_CELL_RENDERER(cell),
1255 "text", _(format_class_list[fe->file_class]), NULL);
1258 g_object_set(GTK_CELL_RENDERER(cell),
1259 "active", fe->writable, NULL);
1261 case FE_ALLOW_SIDECAR:
1262 g_object_set(GTK_CELL_RENDERER(cell),
1263 "active", fe->allow_sidecar, NULL);
1268 static gboolean filter_add_scroll(gpointer data)
1272 GtkCellRenderer *cell;
1273 GtkTreeViewColumn *column;
1276 GtkTreeModel *store;
1278 FilterEntry *filter;
1280 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), nullptr);
1281 path = gtk_tree_path_new_from_indices(rows-1, -1);
1283 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1285 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1286 cell = static_cast<GtkCellRenderer *>(g_list_last(list_cells)->data);
1288 store = gtk_tree_view_get_model(GTK_TREE_VIEW(data));
1289 valid = gtk_tree_model_get_iter_first(store, &iter);
1293 gtk_tree_model_get(store, &iter, 0, &filter, -1);
1295 if (g_strcmp0(filter->extensions, ".new") == 0)
1297 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
1301 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1304 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1305 path, column, FALSE, 0.0, 0.0 );
1306 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1307 path, column, cell, TRUE);
1309 gtk_tree_path_free(path);
1310 g_list_free(list_cells);
1312 return(G_SOURCE_REMOVE);
1315 static void filter_add_cb(GtkWidget *, gpointer data)
1317 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1318 filter_store_populate();
1320 g_idle_add(static_cast<GSourceFunc>(filter_add_scroll), data);
1323 static void filter_remove_cb(GtkWidget *, gpointer data)
1325 auto filter_view = static_cast<GtkWidget *>(data);
1326 GtkTreeSelection *selection;
1330 if (!filter_store) return;
1331 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1332 if (!gtk_tree_selection_get_selected(selection, nullptr, &iter)) return;
1333 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1336 filter_remove_entry(fe);
1338 filter_store_populate();
1341 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1345 GtkTreeViewColumn *column;
1347 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1348 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1349 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1351 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1355 gtk_tree_path_free(path);
1357 return(G_SOURCE_REMOVE);
1360 static void filter_default_ok_cb(GenericDialog *gd, gpointer)
1363 filter_add_defaults();
1365 filter_store_populate();
1367 g_idle_add(reinterpret_cast<GSourceFunc>(filter_default_ok_scroll), gd->data);
1370 static void dummy_cancel_cb(GenericDialog *, gpointer)
1372 /* no op, only so cancel button appears */
1375 static void filter_default_cb(GtkWidget *widget, gpointer data)
1379 gd = generic_dialog_new(_("Reset filters"),
1380 "reset_filter", widget, TRUE,
1381 dummy_cancel_cb, data);
1382 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Reset filters"),
1383 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1384 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", filter_default_ok_cb, TRUE);
1385 gtk_widget_show(gd->dialog);
1388 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1390 auto frame = static_cast<GtkWidget *>(data);
1392 gtk_widget_set_sensitive(frame,
1393 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1396 static void safe_delete_view_cb(GtkWidget *, gpointer)
1398 layout_set_path(nullptr, gq_gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1401 static void safe_delete_clear_ok_cb(GenericDialog *, gpointer)
1403 file_util_trash_clear();
1406 static void safe_delete_clear_cb(GtkWidget *widget, gpointer)
1410 gd = generic_dialog_new(_("Clear trash"),
1411 "clear_trash", widget, TRUE,
1412 dummy_cancel_cb, nullptr);
1413 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Clear trash"),
1414 _("This will remove the trash contents."), FALSE);
1415 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", safe_delete_clear_ok_cb, TRUE);
1416 entry = gtk_entry_new();
1417 gtk_widget_set_can_focus(entry, FALSE);
1418 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1419 if (options->file_ops.safe_delete_path) gq_gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1420 gq_gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1421 gtk_widget_show(entry);
1422 gtk_widget_show(gd->dialog);
1425 static void image_overlay_template_view_changed_cb(GtkWidget *, gpointer data)
1427 GtkWidget *pTextView;
1428 GtkTextBuffer *pTextBuffer;
1432 pTextView = GTK_WIDGET(data);
1434 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1435 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1436 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1438 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1439 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1442 static void image_overlay_default_template_ok_cb(GenericDialog *, gpointer data)
1444 auto text_view = static_cast<GtkTextView *>(data);
1445 GtkTextBuffer *buffer;
1447 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1448 if (!configwindow) return;
1450 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1451 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1454 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1458 gd = generic_dialog_new(_("Reset image overlay template string"),
1459 "reset_image_overlay_template_string", widget, TRUE,
1460 dummy_cancel_cb, data);
1461 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Reset image overlay template string"),
1462 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1463 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", image_overlay_default_template_ok_cb, TRUE);
1464 gtk_widget_show(gd->dialog);
1467 static void image_overlay_help_cb(GtkWidget *, gpointer)
1469 help_window_show("GuideOptionsOSD.html");
1472 static void font_activated_cb(GtkFontChooser *widget, gchar *fontname, gpointer)
1474 g_free(c_options->image_overlay.font);
1475 c_options->image_overlay.font = g_strdup(fontname);
1478 gq_gtk_widget_destroy(GTK_WIDGET(widget));
1481 static void font_response_cb(GtkDialog *dialog, gint response_id, gpointer)
1485 g_free(c_options->image_overlay.font);
1486 c_options->image_overlay.font = g_strdup(options->image_overlay.font);
1488 if (response_id == GTK_RESPONSE_OK)
1490 font = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(dialog));
1491 g_free(c_options->image_overlay.font);
1492 c_options->image_overlay.font = g_strdup(font);
1496 g_object_unref(dialog);
1499 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer)
1503 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1504 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1505 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1507 g_signal_connect(dialog, "font-activated", G_CALLBACK(font_activated_cb), nullptr);
1508 g_signal_connect(dialog, "response", G_CALLBACK(font_response_cb), nullptr);
1510 gtk_widget_show(dialog);
1513 static void text_color_activated_cb(GtkColorChooser *chooser, GdkRGBA *color, gpointer)
1515 c_options->image_overlay.text_red = color->red * 255;
1516 c_options->image_overlay.text_green = color->green * 255;
1517 c_options->image_overlay.text_blue = color->blue * 255;
1518 c_options->image_overlay.text_alpha = color->alpha * 255;
1520 gq_gtk_widget_destroy(GTK_WIDGET(chooser));
1523 static void text_color_response_cb(GtkDialog *dialog, gint response_id, gpointer)
1527 c_options->image_overlay.text_red = options->image_overlay.text_red;
1528 c_options->image_overlay.text_green = options->image_overlay.text_green;
1529 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
1530 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
1532 if (response_id == GTK_RESPONSE_OK)
1534 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &color);
1535 c_options->image_overlay.text_red = color.red * 255;
1536 c_options->image_overlay.text_green = color.green * 255;
1537 c_options->image_overlay.text_blue = color.blue * 255;
1538 c_options->image_overlay.text_alpha = color.alpha * 255;
1541 g_object_unref(dialog);
1544 static void image_overlay_set_text_color_cb(GtkWidget *widget, gpointer)
1549 dialog = gtk_color_chooser_dialog_new(_("Image Overlay Text Color"), GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1550 color.red = options->image_overlay.text_red;
1551 color.green = options->image_overlay.text_green;
1552 color.blue = options->image_overlay.text_blue;
1553 color.alpha = options->image_overlay.text_alpha;
1554 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &color);
1555 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1557 g_signal_connect(dialog, "color-activated", G_CALLBACK(text_color_activated_cb), nullptr);
1558 g_signal_connect(dialog, "response", G_CALLBACK(text_color_response_cb), nullptr);
1560 gtk_widget_show(dialog);
1563 static void bg_color_activated_cb(GtkColorChooser *chooser, GdkRGBA *color, gpointer)
1565 c_options->image_overlay.background_red = color->red * 255;
1566 c_options->image_overlay.background_green = color->green * 255;
1567 c_options->image_overlay.background_blue = color->blue * 255;
1568 c_options->image_overlay.background_alpha = color->alpha * 255;
1570 gq_gtk_widget_destroy(GTK_WIDGET(chooser));
1573 static void bg_color_response_cb(GtkDialog *dialog, gint response_id, gpointer)
1577 c_options->image_overlay.background_red = options->image_overlay.background_red;
1578 c_options->image_overlay.background_green = options->image_overlay.background_green;
1579 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
1580 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
1582 if (response_id == GTK_RESPONSE_OK)
1584 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &color);
1585 c_options->image_overlay.background_red = color.red * 255;
1586 c_options->image_overlay.background_green = color.green * 255;
1587 c_options->image_overlay.background_blue = color.blue * 255;
1588 c_options->image_overlay.background_alpha = color.alpha * 255;
1590 gq_gtk_widget_destroy(GTK_WIDGET(dialog));
1593 static void image_overlay_set_background_color_cb(GtkWidget *widget, gpointer)
1598 dialog = gtk_color_chooser_dialog_new(_("Image Overlay Background Color"), GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1599 color.red = options->image_overlay.background_red;
1600 color.green = options->image_overlay.background_green;
1601 color.blue = options->image_overlay.background_blue;
1602 color.alpha = options->image_overlay.background_alpha;
1603 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &color);
1604 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1606 g_signal_connect(dialog, "color-activated", G_CALLBACK(bg_color_activated_cb), nullptr);
1607 g_signal_connect(dialog, "response", G_CALLBACK(bg_color_response_cb), nullptr);
1609 gtk_widget_show(dialog);
1612 static void accel_store_populate()
1618 const gchar *accel_path;
1622 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1624 gtk_tree_store_clear(accel_store);
1625 lw = static_cast<LayoutWindow *>(layout_window_list->data); /* get the actions from the first window, it should not matter, they should be the same in all windows */
1627 g_assert(lw && lw->ui_manager);
1628 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1631 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1634 action = GTK_ACTION(actions->data);
1635 accel_path = gtk_action_get_accel_path(action);
1636 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1642 g_object_get(action,
1643 "tooltip", &tooltip,
1647 if (pango_parse_markup(label, -1, '_', nullptr, &label2, nullptr, nullptr) && label2)
1653 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1657 gtk_tree_store_append(accel_store, &iter, nullptr);
1658 gtk_tree_store_set(accel_store, &iter,
1661 AE_TOOLTIP, tooltip ? tooltip : "",
1662 AE_ACCEL, accel_path,
1670 actions = actions->next;
1673 groups = groups->next;
1677 static void accel_store_cleared_cb(GtkCellRendererAccel *, gchar *, gpointer)
1682 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *, GtkTreeIter *iter, gpointer data)
1684 auto accel1 = static_cast<gchar *>(data);
1689 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1691 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1692 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1694 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1696 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1697 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1706 static void accel_store_edited_cb(GtkCellRendererAccel *, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint, gpointer)
1708 auto model = reinterpret_cast<GtkTreeModel *>(accel_store);
1712 GtkAccelKey old_key;
1714 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1716 gtk_tree_model_get_iter(model, &iter, path);
1717 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1719 /* test if the accelerator can be stored without conflicts*/
1720 gtk_accel_map_lookup_entry(accel_path, &old_key);
1722 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1723 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1724 gtk_accel_map_lookup_entry(accel_path, &key);
1726 /* restore the original for now, the key will be really changed when the changes are confirmed */
1727 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1729 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1730 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1732 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1733 gtk_tree_path_free(path);
1737 static gboolean accel_default_scroll(GtkTreeView *data)
1741 GtkTreeViewColumn *column;
1743 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1744 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1745 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1747 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1751 gtk_tree_path_free(path);
1753 return(G_SOURCE_REMOVE);
1756 static void accel_default_cb(GtkWidget *, gpointer data)
1758 accel_store_populate();
1760 g_idle_add(reinterpret_cast<GSourceFunc>(accel_default_scroll), data);
1763 void accel_clear_selection(GtkTreeModel *, GtkTreePath *, GtkTreeIter *iter, gpointer)
1765 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1768 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *, GtkTreeIter *iter, gpointer)
1774 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1775 gtk_accel_map_lookup_entry(accel_path, &key);
1776 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1778 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1780 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1785 static void accel_clear_cb(GtkWidget *, gpointer data)
1787 GtkTreeSelection *selection;
1789 if (!accel_store) return;
1790 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1791 gtk_tree_selection_selected_foreach(selection, &accel_clear_selection, nullptr);
1794 static void accel_reset_cb(GtkWidget *, gpointer data)
1796 GtkTreeSelection *selection;
1798 if (!accel_store) return;
1799 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1800 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, nullptr);
1805 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1809 GtkWidget *scrolled;
1810 GtkWidget *viewport;
1812 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
1813 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1814 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1815 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1816 label = gtk_label_new(title);
1817 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1818 gtk_widget_show(scrolled);
1820 viewport = gtk_viewport_new(nullptr, nullptr);
1821 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1822 gq_gtk_container_add(GTK_WIDGET(scrolled), viewport);
1823 gtk_widget_show(viewport);
1825 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
1826 gq_gtk_container_add(GTK_WIDGET(viewport), vbox);
1827 gtk_widget_show(vbox);
1832 static void cache_standard_cb(GtkWidget *widget, gpointer)
1834 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1836 c_options->thumbnails.spec_standard =TRUE;
1837 c_options->thumbnails.cache_into_dirs = FALSE;
1841 static void cache_geeqie_cb(GtkWidget *widget, gpointer)
1843 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1845 c_options->thumbnails.spec_standard =FALSE;
1846 c_options->thumbnails.cache_into_dirs = FALSE;
1850 static void cache_local_cb(GtkWidget *widget, gpointer)
1852 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1854 c_options->thumbnails.cache_into_dirs = TRUE;
1855 c_options->thumbnails.spec_standard =FALSE;
1859 static void help_search_engine_entry_icon_cb(GtkEntry *, GtkEntryIconPosition pos, GdkEvent *, gpointer userdata)
1861 if (pos == GTK_ENTRY_ICON_PRIMARY)
1863 gq_gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1867 gq_gtk_entry_set_text(GTK_ENTRY(userdata), "");
1871 static void star_rating_star_icon_cb(GtkEntry *, GtkEntryIconPosition pos, GdkEvent *, gpointer userdata)
1873 gchar *rating_symbol;
1875 if (pos == GTK_ENTRY_ICON_PRIMARY)
1877 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1878 gq_gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1879 g_free(rating_symbol);
1883 gq_gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1884 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1885 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1889 static void star_rating_rejected_icon_cb(GtkEntry *, GtkEntryIconPosition pos, GdkEvent *, gpointer userdata)
1891 gchar *rating_symbol;
1893 if (pos == GTK_ENTRY_ICON_PRIMARY)
1895 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1896 gq_gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1897 g_free(rating_symbol);
1901 gq_gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1902 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1903 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1907 static guint star_rating_symbol_test(GtkWidget *, gpointer data)
1909 auto hbox = static_cast<GtkContainer *>(data);
1910 GString *str = g_string_new(nullptr);
1911 GtkEntry *hex_code_entry;
1912 gchar *hex_code_full;
1915 guint64 hex_value = 0;
1917 list = gtk_container_get_children(hbox);
1919 hex_code_entry = static_cast<GtkEntry *>(g_list_nth_data(list, 2));
1920 hex_code_full = g_strdup(gq_gtk_entry_get_text(hex_code_entry));
1922 hex_code = g_strsplit(hex_code_full, "+", 2);
1923 if (hex_code[0] && hex_code[1])
1925 hex_value = strtoull(hex_code[1], nullptr, 16);
1927 if (!hex_value || hex_value > 0x10FFFF)
1929 hex_value = 0x003F; // Unicode 'Question Mark'
1931 str = g_string_append_unichar(str, static_cast<gunichar>(hex_value));
1932 gtk_label_set_text(static_cast<GtkLabel *>(g_list_nth_data(list, 1)), str->str);
1934 g_strfreev(hex_code);
1935 g_string_free(str, TRUE);
1936 g_free(hex_code_full);
1941 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1943 guint64 star_symbol;
1945 star_symbol = star_rating_symbol_test(widget, data);
1946 c_options->star_rating.star = star_symbol;
1949 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1951 guint64 rejected_symbol;
1953 rejected_symbol = star_rating_symbol_test(widget, data);
1954 c_options->star_rating.rejected = rejected_symbol;
1957 /* general options tab */
1958 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1962 GCancellable *cancellable;
1964 GtkWidget *progress;
1966 GFile *timezone_database_gq;
1967 gchar *timezone_database_user;
1970 static void config_tab_general(GtkWidget *notebook)
1975 GtkWidget *group_frame;
1976 GtkWidget *subgroup;
1978 GtkWidget *ct_button;
1985 GtkWidget *star_rating_entry;
1987 gchar *rating_symbol;
1990 gchar *download_locn;
1991 GNetworkMonitor *net_mon;
1992 GSocketConnectable *tz_org;
1993 gboolean internet_available = FALSE;
1996 vbox = scrolled_notebook_page(notebook, _("General"));
1998 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
2000 table = pref_table_new(group, 2, 2, FALSE, FALSE);
2001 add_thumb_size_menu(table, 0, 0, _("Size:"));
2002 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
2004 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2005 pref_label_new(hbox, _("Custom size: "));
2006 pref_spin_new_int(hbox, _("Width:"), nullptr, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
2007 pref_spin_new_int(hbox, _("Height:"), nullptr, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
2009 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
2010 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
2012 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2013 pref_checkbox_link_sensitivity(ct_button, subgroup);
2015 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
2016 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
2017 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
2018 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2019 button = pref_radiobutton_new(group_frame, nullptr, get_thumbnails_cache_dir(),
2020 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2021 G_CALLBACK(cache_geeqie_cb), nullptr);
2023 group_frame = pref_frame_new(subgroup, TRUE,
2024 _("Store thumbnails local to image folder (non-standard)"),
2025 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2026 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
2027 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
2028 G_CALLBACK(cache_local_cb), nullptr);
2030 group_frame = pref_frame_new(subgroup, TRUE,
2031 _("Use standard thumbnail style and cache, shared with other applications"),
2032 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2033 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
2034 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2035 G_CALLBACK(cache_standard_cb), nullptr);
2037 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
2038 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
2040 pref_checkbox_new_int(group, _("Thumbnail color management"),
2041 options->thumbnails.use_color_management, &c_options->thumbnails.use_color_management);
2043 spin = pref_spin_new_int(group, _("Collection preview:"), nullptr,
2045 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
2046 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
2048 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
2049 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
2050 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
2053 pref_spacer(group, PREF_PAD_GROUP);
2055 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
2057 c_options->star_rating.star = options->star_rating.star;
2058 c_options->star_rating.rejected = options->star_rating.rejected;
2060 str = g_string_new(nullptr);
2061 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2062 pref_label_new(hbox, _("Star character: "));
2063 str = g_string_append_unichar(str, options->star_rating.star);
2064 pref_label_new(hbox, g_strdup(str->str));
2065 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
2066 star_rating_entry = gtk_entry_new();
2067 gq_gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2068 gq_gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2069 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2070 gtk_widget_show(star_rating_entry);
2071 button = pref_button_new(nullptr, nullptr, _("Set"),
2072 G_CALLBACK(star_rating_star_test_cb), hbox);
2073 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2074 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2075 gtk_widget_show(button);
2076 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."));
2077 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2078 GTK_ENTRY_ICON_SECONDARY, GQ_ICON_CLEAR);
2079 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2080 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2081 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2082 GTK_ENTRY_ICON_PRIMARY, GQ_ICON_REVERT);
2083 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2084 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2085 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2086 G_CALLBACK(star_rating_star_icon_cb),
2089 g_string_free(str, TRUE);
2090 g_free(rating_symbol);
2092 str = g_string_new(nullptr);
2093 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2094 pref_label_new(hbox, _("Rejected character: "));
2095 str = g_string_append_unichar(str, options->star_rating.rejected);
2096 pref_label_new(hbox, g_strdup(str->str));
2097 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2098 star_rating_entry = gtk_entry_new();
2099 gq_gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2100 gq_gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2101 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2102 gtk_widget_show(star_rating_entry);
2103 button = pref_button_new(nullptr, nullptr, _("Set"),
2104 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2105 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2106 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2107 gtk_widget_show(button);
2108 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."));
2109 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2110 GTK_ENTRY_ICON_SECONDARY, GQ_ICON_CLEAR);
2111 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2112 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2113 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2114 GTK_ENTRY_ICON_PRIMARY, GQ_ICON_REVERT);
2115 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2116 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2117 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2118 G_CALLBACK(star_rating_rejected_icon_cb),
2121 g_string_free(str, TRUE);
2122 g_free(rating_symbol);
2124 pref_spacer(group, PREF_PAD_GROUP);
2126 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2128 c_options->slideshow.delay = options->slideshow.delay;
2129 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2130 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2131 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2132 seconds = static_cast<gdouble>(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2133 SLIDESHOW_SUBSECOND_PRECISION;
2135 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2137 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), nullptr,
2139 options->slideshow.delay ? hours : 0.0,
2140 G_CALLBACK(slideshow_delay_hours_cb), nullptr);
2141 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2142 spin = pref_spin_new(hbox, ":" , nullptr,
2144 options->slideshow.delay ? minutes: 0.0,
2145 G_CALLBACK(slideshow_delay_minutes_cb), nullptr);
2146 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2147 spin = pref_spin_new(hbox, ":", nullptr,
2148 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2149 options->slideshow.delay ? seconds : 10.0,
2150 G_CALLBACK(slideshow_delay_seconds_cb), nullptr);
2151 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2153 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2154 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2156 pref_spacer(group, PREF_PAD_GROUP);
2158 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2160 pref_spin_new_int(group, _("Decoded image cache size (MiB):"), nullptr,
2161 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2162 pref_checkbox_new_int(group, _("Preload next image"),
2163 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2165 pref_checkbox_new_int(group, _("Refresh on file change"),
2166 options->update_on_time_change, &c_options->update_on_time_change);
2169 pref_spacer(group, PREF_PAD_GROUP);
2171 group = pref_group_new(vbox, FALSE, _("Menu style"), GTK_ORIENTATION_VERTICAL);
2173 pref_checkbox_new_int(group, _("☰ style menu button (NOTE! Geeqie must be restarted for change to take effect)"),
2174 options->hamburger_menu, &c_options->hamburger_menu);
2175 gtk_widget_set_tooltip_text(group, _("Use a ☰ style menu button instead of the classic style across the top of the frame"));
2177 pref_spacer(group, PREF_PAD_GROUP);
2179 group = pref_group_new(vbox, FALSE, _("Expand toolbar"), GTK_ORIENTATION_VERTICAL);
2181 pref_checkbox_new_int(group, _("Expand menu/toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2182 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2183 gtk_widget_set_tooltip_text(group, _("Expand the menu/toolbar to the full width of the window"));
2185 pref_spacer(group, PREF_PAD_GROUP);
2187 group = pref_group_new(vbox, FALSE, _("Hide Selectable Bars"), GTK_ORIENTATION_VERTICAL);
2189 pref_checkbox_new_int(group, _("Menu bar"),
2190 options->selectable_bars.menu_bar, &c_options->selectable_bars.menu_bar);
2192 pref_checkbox_new_int(group, _("Tool bar"),
2193 options->selectable_bars.tool_bar, &c_options->selectable_bars.tool_bar);
2195 pref_checkbox_new_int(group, _("Status bar"),
2196 options->selectable_bars.status_bar, &c_options->selectable_bars.status_bar);
2197 gtk_widget_set_tooltip_text(group, _("The Hide Selectable Bars menu item (default keystroke is control-backtick) will toggle the display of the bars selected here"));
2199 pref_spacer(group, PREF_PAD_GROUP);
2201 if (g_getenv("APPDIR") && strstr(g_getenv("APPDIR"), "/tmp/.mount_Geeqie"))
2203 group = pref_group_new(vbox, FALSE, _("AppImage updates notifications"), GTK_ORIENTATION_VERTICAL);
2204 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2205 pref_checkbox_new_int(group, _("Enable"), options->appimage_notifications, &c_options->appimage_notifications);
2206 gtk_widget_set_tooltip_text(group, _("Show a notification on start-up if the server has a newer version than the current. Requires an Internet connection"));
2208 pref_spacer(group, PREF_PAD_GROUP);
2212 net_mon = g_network_monitor_get_default();
2213 tz_org = g_network_address_parse_uri(TIMEZONE_DATABASE_WEB, 80, nullptr);
2216 internet_available = g_network_monitor_can_reach(net_mon, tz_org, nullptr, nullptr);
2217 g_object_unref(tz_org);
2220 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2221 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2223 if (!internet_available)
2225 gtk_widget_set_sensitive(group, FALSE);
2228 tz = g_new0(TZData, 1);
2230 path = path_from_utf8(TIMEZONE_DATABASE_WEB);
2231 basename = g_path_get_basename(path);
2232 tz->timezone_database_user = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
2236 if (isfile(tz->timezone_database_user))
2238 button = pref_button_new(GTK_WIDGET(hbox), nullptr, _("Update"), G_CALLBACK(timezone_database_install_cb), tz);
2242 button = pref_button_new(GTK_WIDGET(hbox), nullptr, _("Install"), G_CALLBACK(timezone_database_install_cb), tz);
2245 download_locn = g_strconcat(_("Download database from: "), TIMEZONE_DATABASE_WEB, NULL);
2246 pref_label_new(GTK_WIDGET(hbox), download_locn);
2247 g_free(download_locn);
2249 if (!internet_available)
2251 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"));
2255 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"));
2257 gtk_widget_show(button);
2259 pref_spacer(group, PREF_PAD_GROUP);
2261 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2263 help_search_engine_entry = gtk_entry_new();
2264 gq_gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2265 gq_gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2266 gtk_widget_show(help_search_engine_entry);
2268 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"));
2270 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(help_search_engine_entry),
2271 GTK_ENTRY_ICON_SECONDARY, GQ_ICON_CLEAR);
2272 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2273 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2274 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(help_search_engine_entry),
2275 GTK_ENTRY_ICON_PRIMARY, GQ_ICON_REVERT);
2276 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2277 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2278 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2279 G_CALLBACK(help_search_engine_entry_icon_cb),
2280 help_search_engine_entry);
2284 static void config_tab_image(GtkWidget *notebook)
2289 GtkWidget *ct_button;
2290 GtkWidget *enlargement_button;
2294 vbox = scrolled_notebook_page(notebook, _("Image"));
2296 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2298 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2299 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2301 pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2302 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2304 c_options->image.zoom_increment = options->image.zoom_increment;
2305 spin = pref_spin_new(group, _("Zoom increment:"), nullptr,
2306 0.01, 4.0, 0.01, 2, static_cast<gdouble>(options->image.zoom_increment) / 100.0,
2307 G_CALLBACK(zoom_increment_cb), nullptr);
2308 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2310 c_options->image.zoom_style = options->image.zoom_style;
2311 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2312 add_zoom_style_selection_menu(table, 0, 0, _("Zoom style:"), options->image.zoom_style, &c_options->image.zoom_style);
2314 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2316 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2317 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2318 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2319 spin = pref_spin_new_int(hbox, nullptr, nullptr,
2321 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2322 pref_checkbox_link_sensitivity(enlargement_button, spin);
2323 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."));
2325 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2326 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2327 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2328 spin = pref_spin_new_int(hbox, nullptr, nullptr,
2330 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2331 pref_checkbox_link_sensitivity(ct_button, spin);
2332 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."));
2334 group = pref_group_new(vbox, FALSE, _("Tile size"), GTK_ORIENTATION_VERTICAL);
2336 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2337 spin = pref_spin_new_int(hbox, _("Pixels"), _("(Requires restart)"),
2339 options->image.tile_size, &c_options->image.tile_size);
2340 gtk_widget_set_tooltip_text(GTK_WIDGET(hbox), _("This value changes the size of the tiles large images are split into. Increasing the size of the tiles will reduce the tiling effect seen on image changes, but will also slightly increase the delay before the first part of a large image is seen."));
2342 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2344 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2345 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2347 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2348 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2350 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2351 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2353 c_options->image.border_color = options->image.border_color;
2355 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2356 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2358 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2359 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2361 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2362 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2367 static void save_default_window_layout_cb(GtkWidget *, gpointer)
2369 LayoutWindow *lw = nullptr;
2370 gchar *default_path;
2373 /* Get current lw */
2376 tmp_id = lw->options.id;
2377 lw->options.id = g_strdup("");
2379 default_path = g_build_filename(get_rc_dir(), DEFAULT_WINDOW_LAYOUT, NULL);
2380 save_default_layout_options_to_file(default_path, options, lw);
2381 g_free(lw->options.id);
2382 lw->options.id = tmp_id;
2383 g_free(default_path);
2386 static gboolean popover_cb(gpointer data)
2388 auto popover = static_cast<GtkPopover *>(data);
2390 gtk_popover_popdown(popover);
2395 static void default_layout_changed_cb(GtkWidget *, GtkPopover *popover)
2397 gtk_popover_popup(popover);
2399 g_timeout_add(2000, popover_cb, popover);
2402 static GtkWidget *create_popover(GtkWidget *parent, GtkWidget *child, GtkPositionType pos)
2406 popover = gtk_popover_new(parent);
2407 gtk_popover_set_position(GTK_POPOVER (popover), pos);
2408 gq_gtk_container_add(GTK_WIDGET(popover), child);
2409 gtk_container_set_border_width(GTK_CONTAINER (popover), 6);
2410 gtk_widget_show (child);
2415 static void config_tab_windows(GtkWidget *notebook)
2420 GtkWidget *subgroup;
2422 GtkWidget *checkbox;
2423 GtkWidget *ct_button;
2426 vbox = scrolled_notebook_page(notebook, _("Windows"));
2428 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2430 ct_button = pref_checkbox_new_int(group, _("Remember session"),
2431 options->save_window_positions, &c_options->save_window_positions);
2433 checkbox = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2434 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2435 pref_checkbox_link_sensitivity(ct_button, checkbox);
2437 checkbox = pref_checkbox_new_int(group, _("Remember window workspace"),
2438 options->save_window_workspace, &c_options->save_window_workspace);
2439 pref_checkbox_link_sensitivity(ct_button, checkbox);
2441 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2442 options->tools_restore_state, &c_options->tools_restore_state);
2444 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2445 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2447 pref_checkbox_new_int(group, _("Show window IDs"),
2448 options->show_window_ids, &c_options->show_window_ids);
2450 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2451 pref_label_new(subgroup, _("Use current layout for default: "));
2452 button = pref_button_new(subgroup, nullptr, _("Set"), G_CALLBACK(save_default_window_layout_cb), nullptr);
2456 popover = create_popover(button, gtk_label_new(_("Current window layout\nhas been set as default")), GTK_POS_TOP);
2457 gtk_popover_set_modal(GTK_POPOVER (popover), FALSE);
2458 g_signal_connect(button, "clicked", G_CALLBACK(default_layout_changed_cb), popover);
2460 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2462 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2463 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2465 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2466 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2467 options->image.limit_window_size, &c_options->image.limit_window_size);
2468 spin = pref_spin_new_int(hbox, nullptr, nullptr,
2470 options->image.max_window_size, &c_options->image.max_window_size);
2471 pref_checkbox_link_sensitivity(ct_button, spin);
2473 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2475 c_options->fullscreen.screen = options->fullscreen.screen;
2476 c_options->fullscreen.above = options->fullscreen.above;
2477 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2478 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2479 gtk_widget_show(hbox);
2481 pref_checkbox_new_int(group, _("Smooth image flip"),
2482 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2483 pref_checkbox_new_int(group, _("Disable screen saver"),
2484 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2488 PRE_FORMATTED_COLUMNS = 5
2490 static void config_tab_osd(GtkWidget *notebook)
2496 GtkWidget *image_overlay_template_view;
2497 GtkWidget *scrolled;
2498 GtkWidget *scrolled_pre_formatted;
2499 GtkTextBuffer *buffer;
2501 GtkWidget *subgroup;
2503 vbox = scrolled_notebook_page(notebook, _("OSD"));
2505 image_overlay_template_view = gtk_text_view_new();
2507 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2509 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2511 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2512 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2513 gq_gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2514 gtk_widget_show(scrolled_pre_formatted);
2515 gtk_widget_show(subgroup);
2517 pref_line(group, PREF_PAD_GAP);
2519 pref_label_new(group, _("Image overlay template"));
2521 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
2522 gtk_widget_set_size_request(scrolled, 200, 150);
2523 gq_gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2524 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2525 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2526 gq_gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2527 gtk_widget_show(scrolled);
2529 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2530 _("Extensive formatting options are shown in the Help file"));
2532 gq_gtk_container_add(GTK_WIDGET(scrolled), image_overlay_template_view);
2533 gtk_widget_show(image_overlay_template_view);
2535 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2537 button = pref_button_new(nullptr, GQ_ICON_SELECT_FONT, _("Font"),
2538 G_CALLBACK(image_overlay_set_font_cb), notebook);
2540 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2541 gtk_widget_show(button);
2543 button = pref_button_new(nullptr, GQ_ICON_SELECT_COLOR, _("Text"), G_CALLBACK(image_overlay_set_text_color_cb), nullptr);
2544 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2545 gtk_widget_show(button);
2547 button = pref_button_new(nullptr, GQ_ICON_SELECT_COLOR, _("Background"), G_CALLBACK(image_overlay_set_background_color_cb), nullptr);
2548 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2549 gtk_widget_show(button);
2550 image_overlay_set_text_colors();
2552 button = pref_button_new(nullptr, nullptr, _("Defaults"),
2553 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2554 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2555 gtk_widget_show(button);
2557 button = pref_button_new(nullptr, GQ_ICON_HELP, _("Help"),
2558 G_CALLBACK(image_overlay_help_cb), nullptr);
2559 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2560 gtk_widget_show(button);
2562 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2563 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2564 g_signal_connect(G_OBJECT(buffer), "changed",
2565 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2567 pref_line(group, PREF_PAD_GAP);
2569 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2570 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2571 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2572 gtk_widget_show(hbox);
2573 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2574 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2575 gtk_widget_show(label);
2576 pref_spacer(group,TRUE);
2578 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2579 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2580 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2581 gtk_widget_show(hbox);
2582 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2583 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2584 gtk_widget_show(label);
2585 pref_spacer(group,TRUE);
2587 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2588 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2589 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2590 gtk_widget_show(hbox);
2591 label = gtk_label_new(_("%path:39%"));
2592 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2593 gtk_widget_show(label);
2594 pref_spacer(group,TRUE);
2596 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2597 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2598 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2599 gtk_widget_show(hbox);
2600 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%"));
2601 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2602 gtk_widget_show(label);
2603 pref_spacer(group,TRUE);
2605 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2606 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2607 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2608 gtk_widget_show(hbox);
2609 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2610 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2611 gtk_widget_show(label);
2614 static GtkTreeModel *create_class_model()
2616 GtkListStore *model;
2620 /* create list store */
2621 model = gtk_list_store_new(1, G_TYPE_STRING);
2622 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2624 gtk_list_store_append(model, &iter);
2625 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2627 return GTK_TREE_MODEL (model);
2632 static gint filter_table_sort_cb(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data)
2634 gint n = GPOINTER_TO_INT(data);
2636 FilterEntry *filter_a;
2637 FilterEntry *filter_b;
2639 gtk_tree_model_get(model, a, 0, &filter_a, -1);
2640 gtk_tree_model_get(model, b, 0, &filter_b, -1);
2644 case FILETYPES_COLUMN_ENABLED:
2646 ret = filter_a->enabled - filter_b->enabled;
2649 case FILETYPES_COLUMN_FILTER:
2651 ret = g_utf8_collate(filter_a->extensions, filter_b->extensions);
2654 case FILETYPES_COLUMN_DESCRIPTION:
2656 ret = g_utf8_collate(filter_a->description, filter_b->description);
2659 case FILETYPES_COLUMN_CLASS:
2661 ret = g_strcmp0(format_class_list[filter_a->file_class], format_class_list[filter_b->file_class]);
2664 case FILETYPES_COLUMN_WRITABLE:
2666 ret = filter_a->writable - filter_b->writable;
2669 case FILETYPES_COLUMN_SIDECAR:
2671 ret = filter_a->allow_sidecar - filter_b->allow_sidecar;
2675 g_return_val_if_reached(0);
2681 static gboolean search_function_cb(GtkTreeModel *model, gint, const gchar *key, GtkTreeIter *iter, gpointer)
2684 gboolean ret = TRUE;
2686 gtk_tree_model_get(model, iter, 0, &fe, -1);
2688 if (g_strstr_len(fe->extensions, -1, key))
2696 static void config_tab_files(GtkWidget *notebook)
2703 GtkWidget *ct_button;
2704 GtkWidget *scrolled;
2705 GtkWidget *filter_view;
2706 GtkCellRenderer *renderer;
2707 GtkTreeSelection *selection;
2708 GtkTreeViewColumn *column;
2710 vbox = scrolled_notebook_page(notebook, _("File Filters"));
2712 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2714 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2715 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2716 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2717 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2718 pref_checkbox_new_int(group, _("Case sensitive sort (Search and Collection windows, and tab completion)"), options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2719 pref_checkbox_new_int(group, _("Disable file extension checks"),
2720 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2722 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2723 options->file_filter.disable, &c_options->file_filter.disable);
2726 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2728 sidecar_ext_entry = gtk_entry_new();
2729 gq_gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2730 gq_gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2731 gtk_widget_show(sidecar_ext_entry);
2733 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2735 frame = pref_group_parent(group);
2736 g_signal_connect(G_OBJECT(ct_button), "toggled",
2737 G_CALLBACK(filter_disable_cb), frame);
2738 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2740 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
2741 gq_gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2742 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2743 gq_gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2744 gtk_widget_show(scrolled);
2746 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2747 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2748 g_object_unref(filter_store);
2749 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2750 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2752 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2754 column = gtk_tree_view_column_new();
2755 gtk_tree_view_column_set_title(column, _("Enabled"));
2756 gtk_tree_view_column_set_resizable(column, TRUE);
2758 renderer = gtk_cell_renderer_toggle_new();
2759 g_signal_connect(G_OBJECT(renderer), "toggled",
2760 G_CALLBACK(filter_store_enable_cb), filter_store);
2761 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2762 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2763 GINT_TO_POINTER(FE_ENABLE), nullptr);
2764 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_ENABLED, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_ENABLED), nullptr);
2765 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_ENABLED);
2766 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2768 column = gtk_tree_view_column_new();
2769 gtk_tree_view_column_set_title(column, _("Filter"));
2770 gtk_tree_view_column_set_resizable(column, TRUE);
2771 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_FILTER, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_FILTER), nullptr);
2772 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_FILTER);
2774 renderer = gtk_cell_renderer_text_new();
2775 g_signal_connect(G_OBJECT(renderer), "edited",
2776 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2777 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2778 g_object_set(G_OBJECT(renderer), "editable", static_cast<gboolean>TRUE, NULL);
2779 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2780 GINT_TO_POINTER(FE_EXTENSION), nullptr);
2781 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2783 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), TRUE);
2784 gtk_tree_view_set_search_column(GTK_TREE_VIEW(filter_view), FILETYPES_COLUMN_FILTER);
2785 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(filter_view), search_function_cb, nullptr, nullptr);
2787 column = gtk_tree_view_column_new();
2788 gtk_tree_view_column_set_title(column, _("Description"));
2789 gtk_tree_view_column_set_resizable(column, TRUE);
2790 gtk_tree_view_column_set_fixed_width(column, 200);
2791 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2793 renderer = gtk_cell_renderer_text_new();
2794 g_signal_connect(G_OBJECT(renderer), "edited",
2795 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2796 g_object_set(G_OBJECT(renderer), "editable", static_cast<gboolean>TRUE, NULL);
2797 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2798 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2799 GINT_TO_POINTER(FE_DESCRIPTION), nullptr);
2800 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2801 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_DESCRIPTION, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_DESCRIPTION), nullptr);
2802 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_DESCRIPTION);
2804 column = gtk_tree_view_column_new();
2805 gtk_tree_view_column_set_title(column, _("Class"));
2806 gtk_tree_view_column_set_resizable(column, TRUE);
2807 renderer = gtk_cell_renderer_combo_new();
2808 g_object_set(G_OBJECT(renderer), "editable", static_cast<gboolean>TRUE,
2809 "model", create_class_model(),
2814 g_signal_connect(G_OBJECT(renderer), "edited",
2815 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2816 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2817 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2818 GINT_TO_POINTER(FE_CLASS), nullptr);
2819 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2820 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_CLASS, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_CLASS), nullptr);
2821 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_CLASS);
2823 column = gtk_tree_view_column_new();
2824 gtk_tree_view_column_set_title(column, _("Writable"));
2825 gtk_tree_view_column_set_resizable(column, FALSE);
2826 renderer = gtk_cell_renderer_toggle_new();
2827 g_signal_connect(G_OBJECT(renderer), "toggled",
2828 G_CALLBACK(filter_store_writable_cb), filter_store);
2829 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2830 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2831 GINT_TO_POINTER(FE_WRITABLE), nullptr);
2832 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2833 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_WRITABLE, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_WRITABLE), nullptr);
2834 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_WRITABLE);
2836 column = gtk_tree_view_column_new();
2837 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2838 gtk_tree_view_column_set_resizable(column, FALSE);
2839 renderer = gtk_cell_renderer_toggle_new();
2840 g_signal_connect(G_OBJECT(renderer), "toggled",
2841 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2842 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2843 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2844 GINT_TO_POINTER(FE_ALLOW_SIDECAR), nullptr);
2845 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2846 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_SIDECAR, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_SIDECAR), nullptr);
2847 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_SIDECAR);
2849 filter_store_populate();
2850 gq_gtk_container_add(GTK_WIDGET(scrolled), filter_view);
2851 gtk_widget_show(filter_view);
2853 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2855 button = pref_button_new(nullptr, nullptr, _("Defaults"),
2856 G_CALLBACK(filter_default_cb), filter_view);
2857 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2858 gtk_widget_show(button);
2860 button = pref_button_new(nullptr, GQ_ICON_REMOVE, _("Remove"),
2861 G_CALLBACK(filter_remove_cb), filter_view);
2862 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2863 gtk_widget_show(button);
2865 button = pref_button_new(nullptr, GQ_ICON_ADD, _("Add"),
2866 G_CALLBACK(filter_add_cb), filter_view);
2867 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2868 gtk_widget_show(button);
2872 static void config_tab_metadata(GtkWidget *notebook)
2877 GtkWidget *ct_button;
2879 GtkWidget *tmp_widget;
2881 GtkWidget *text_label;
2883 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2886 group = pref_group_new(vbox, FALSE, _("Metadata writing sequence"), GTK_ORIENTATION_VERTICAL);
2888 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2890 label = pref_label_new(group, _("When writing metadata, Geeqie will follow these steps, if selected. This process will stop when the first successful write occurs."));
2891 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2892 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2894 gtk_widget_set_tooltip_text(label, _("A flowchart of the sequence is shown in the Help file"));
2896 ct_button = pref_checkbox_new_int(group, "", options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2897 text_label = gtk_bin_get_child(GTK_BIN(ct_button));
2898 markup = g_markup_printf_escaped ("<span weight=\"bold\">%s</span>%s", _("Step 1"), _(") Save metadata in either the image file or the sidecar file, according to the XMP standard"));
2899 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2901 markup = g_markup_printf_escaped ("%s<span style=\"italic\">%s</span>%s<span style=\"italic\">%s</span>%s", _("The destination is dependent on the settings in the "), _("Writable"), _(" and "), _("Sidecar Is Allowed"), _(" columns of the File Filters tab)"));
2902 gtk_widget_set_tooltip_markup(ct_button, markup);
2906 gtk_widget_set_sensitive(ct_button, FALSE);
2909 tmp_widget = pref_checkbox_new_int(group, "", options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2910 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2911 markup = g_markup_printf_escaped ("<span weight=\"bold\">%s</span>%s<span style=\"italic\">%s</span>%s", _("Step 2"), _(") Save metadata in the folder "),".metadata,", _(" local to the image folder (non-standard)"));
2912 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2915 label = pref_label_new(group, "");
2916 markup = g_markup_printf_escaped ("<span weight=\"bold\">%s</span>%s<span style=\"italic\">%s</span>%s", _("Step 3"), _(") Save metadata in Geeqie private directory "), get_metadata_cache_dir(), "/");
2917 gtk_label_set_markup (GTK_LABEL(label), markup);
2920 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2921 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2922 gtk_widget_set_margin_start(label, 22);
2923 pref_spacer(group, PREF_PAD_GROUP);
2925 group = pref_group_new(vbox, FALSE, _("Step 1 Options:"), GTK_ORIENTATION_VERTICAL);
2927 gtk_widget_set_sensitive(group, FALSE);
2930 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2931 pref_checkbox_link_sensitivity(ct_button, hbox);
2933 tmp_widget= pref_checkbox_new_int(hbox, _("Store metadata also in IPTC tags (converted according to the IPTC4XMP standard)"), options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2934 gtk_widget_set_tooltip_text(tmp_widget, _("A simplified conversion list is in the Help file"));
2936 pref_checkbox_new_int(hbox, _("Warn if the image or sidecar file is not writable"), options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2938 pref_checkbox_new_int(hbox, _("Ask before writing to image files"), options->metadata.confirm_write, &c_options->metadata.confirm_write);
2940 tmp_widget= pref_checkbox_new_int(hbox, "", options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2941 gtk_widget_set_tooltip_text(tmp_widget, _("This file naming convention is used by Darktable"));
2942 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2943 markup = g_markup_printf_escaped ("%s<span style=\"italic\">%s</span>%s<span style=\"italic\">%s</span>%s", _("Create sidecar files named "), "image.ext.xmp", _(" (as opposed to the normal "), "image.xmp", ")");
2944 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2947 pref_spacer(group, PREF_PAD_GROUP);
2949 group = pref_group_new(vbox, FALSE, _("Steps 2 and 3 Option:"), GTK_ORIENTATION_VERTICAL);
2951 gtk_widget_set_sensitive(group, FALSE);
2954 pref_checkbox_new_int(group, _("Use GQview legacy metadata format instead of XMP (supports only Keywords and Comments)"), options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2956 pref_spacer(group, PREF_PAD_GROUP);
2958 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2959 tmp_widget = pref_checkbox_new_int(group, _("Write the same description tags to all grouped sidecars"), options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2960 gtk_widget_set_tooltip_text(tmp_widget, _("See the Help file for a list of the tags used"));
2962 tmp_widget = pref_checkbox_new_int(group, _("Permit Keywords to be case-sensitive"), options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2963 gtk_widget_set_tooltip_text(tmp_widget, _("When selected, \"Place\" and \"place\" are two different keywords"));
2965 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"), options->metadata.write_orientation, &c_options->metadata.write_orientation);
2966 gtk_widget_set_tooltip_text(ct_button, _("If checked, the results of orientation commands (Rotate, Mirror and Flip) issued on an image will be written to metadata\nNote: If this option is not checked, the results of orientation commands will be lost when Geeqie closes"));
2969 gtk_widget_set_sensitive(ct_button, FALSE);
2972 pref_spacer(group, PREF_PAD_GROUP);
2974 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2976 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"), options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2978 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2979 pref_checkbox_link_sensitivity(ct_button, hbox);
2981 pref_spin_new_int(hbox, _("Timeout (seconds):"), nullptr, 0, 900, 1, options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2983 pref_checkbox_new_int(group, _("Write metadata on image change"), options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2985 pref_checkbox_new_int(group, _("Write metadata on directory change"), options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2987 pref_spacer(group, PREF_PAD_GROUP);
2990 group = pref_group_new(vbox, FALSE, _("Spelling checks"), GTK_ORIENTATION_VERTICAL);
2992 ct_button = pref_checkbox_new_int(group, _("Check spelling - Requires restart"), options->metadata.check_spelling, &c_options->metadata.check_spelling);
2993 gtk_widget_set_tooltip_text(ct_button, _("Spelling checks are performed on info sidebar panes Comment, Headline and Title"));
2996 pref_spacer(group, PREF_PAD_GROUP);
2998 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
3000 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"), options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
3001 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");
3006 struct KeywordFindData
3013 GtkWidget *button_close;
3014 GtkWidget *button_stop;
3015 GtkWidget *button_start;
3016 GtkWidget *progress;
3024 guint idle_id; /* event source id */
3028 KEYWORD_DIALOG_WIDTH = 400
3031 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
3033 GList *list_d = nullptr;
3034 GList *list_f = nullptr;
3038 filelist_read(dir_fd, &list_f, &list_d);
3042 filelist_read(dir_fd, &list_f, nullptr);
3045 list_f = filelist_filter(list_f, FALSE);
3046 list_d = filelist_filter(list_d, TRUE);
3048 kfd->list = g_list_concat(list_f, kfd->list);
3049 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
3052 static void keywords_find_reset(KeywordFindData *kfd)
3054 filelist_free(kfd->list);
3055 kfd->list = nullptr;
3057 filelist_free(kfd->list_dir);
3058 kfd->list_dir = nullptr;
3061 static void keywords_find_close_cb(GenericDialog *, gpointer data)
3063 auto kfd = static_cast<KeywordFindData *>(data);
3065 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
3067 keywords_find_reset(kfd);
3068 generic_dialog_close(kfd->gd);
3072 static void keywords_find_finish(KeywordFindData *kfd)
3074 keywords_find_reset(kfd);
3076 gq_gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
3077 gtk_spinner_stop(GTK_SPINNER(kfd->spinner));
3079 gtk_widget_set_sensitive(kfd->group, TRUE);
3080 gtk_widget_set_sensitive(kfd->button_start, TRUE);
3081 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3082 gtk_widget_set_sensitive(kfd->button_close, TRUE);
3085 static void keywords_find_stop_cb(GenericDialog *, gpointer data)
3087 auto kfd = static_cast<KeywordFindData *>(data);
3089 g_idle_remove_by_data(kfd);
3091 keywords_find_finish(kfd);
3094 static gboolean keywords_find_file(gpointer data)
3096 auto kfd = static_cast<KeywordFindData *>(data);
3098 GtkTextBuffer *buffer;
3106 fd = static_cast<FileData *>(kfd->list->data);
3107 kfd->list = g_list_remove(kfd->list, fd);
3109 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
3110 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3114 gtk_text_buffer_get_end_iter(buffer, &iter);
3115 tmp = g_strconcat(static_cast<const gchar *>(keywords->data), "\n", NULL);
3116 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3118 keywords = keywords->next;
3121 gq_gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
3122 file_data_unref(fd);
3123 g_list_free_full(keywords, g_free);
3125 return (G_SOURCE_CONTINUE);
3132 fd = static_cast<FileData *>(kfd->list_dir->data);
3133 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
3135 keywords_find_folder(kfd, fd);
3137 file_data_unref(fd);
3139 return G_SOURCE_CONTINUE;
3142 keywords_find_finish(kfd);
3144 return G_SOURCE_REMOVE;
3147 static void keywords_find_start_cb(GenericDialog *, gpointer data)
3149 auto kfd = static_cast<KeywordFindData *>(data);
3152 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
3154 path = remove_trailing_slash((gq_gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
3155 parse_out_relatives(path);
3159 warning_dialog(_("Invalid folder"),
3160 _("The specified folder can not be found."),
3161 GQ_ICON_DIALOG_WARNING, kfd->gd->dialog);
3167 gtk_widget_set_sensitive(kfd->group, FALSE);
3168 gtk_widget_set_sensitive(kfd->button_start, FALSE);
3169 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
3170 gtk_widget_set_sensitive(kfd->button_close, FALSE);
3171 gtk_spinner_start(GTK_SPINNER(kfd->spinner));
3173 dir_fd = file_data_new_dir(path);
3174 keywords_find_folder(kfd, dir_fd);
3175 file_data_unref(dir_fd);
3176 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
3182 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
3184 KeywordFindData *kfd;
3188 kfd = g_new0(KeywordFindData, 1);
3190 kfd->gd = generic_dialog_new(_("Search for keywords"),
3191 "search_for_keywords",
3194 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
3195 kfd->gd->cancel_cb = keywords_find_close_cb;
3196 kfd->button_close = generic_dialog_add_button(kfd->gd, GQ_ICON_CLOSE, _("Close"),
3197 keywords_find_close_cb, FALSE);
3198 kfd->button_start = generic_dialog_add_button(kfd->gd, GQ_ICON_OK, _("S_tart"),
3199 keywords_find_start_cb, FALSE);
3200 kfd->button_stop = generic_dialog_add_button(kfd->gd, GQ_ICON_STOP, _("Stop"),
3201 keywords_find_stop_cb, FALSE);
3202 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3204 generic_dialog_add_message(kfd->gd, nullptr, _("Search for keywords"), nullptr, FALSE);
3206 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
3207 pref_spacer(hbox, PREF_PAD_INDENT);
3208 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
3210 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3211 pref_label_new(hbox, _("Folder:"));
3213 label = tab_completion_new(&kfd->entry, path, nullptr, nullptr, nullptr, nullptr);
3214 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
3215 gq_gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
3216 gtk_widget_show(label);
3218 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
3220 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
3221 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3223 kfd->progress = gtk_entry_new();
3224 gtk_widget_set_can_focus(kfd->progress, FALSE);
3225 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
3226 gq_gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
3227 gq_gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
3228 gtk_widget_show(kfd->progress);
3230 kfd->spinner = gtk_spinner_new();
3231 gq_gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
3232 gtk_widget_show(kfd->spinner);
3234 kfd->list = nullptr;
3236 gtk_widget_show(kfd->gd->dialog);
3239 static void keywords_find_cb(GtkWidget *widget, gpointer)
3241 const gchar *path = layout_get_path(nullptr);
3243 if (!path || !*path) path = homedir();
3244 keywords_find_dialog(widget, path);
3247 static void config_tab_keywords_save()
3251 GtkTextBuffer *buffer;
3252 GList *kw_list = nullptr;
3258 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3259 gtk_text_buffer_get_bounds(buffer, &start, &end);
3261 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3263 kw_split = strtok(buffer_text, "\n");
3264 while (kw_split != nullptr)
3270 if (g_strcmp0(static_cast<const gchar *>(work->data), kw_split) == 0)
3279 kw_list = g_list_append(kw_list, g_strdup(kw_split));
3281 kw_split = strtok(nullptr, "\n");
3284 keyword_list_set(kw_list);
3286 g_list_free_full(kw_list, g_free);
3287 g_free(buffer_text);
3290 static void config_tab_keywords(GtkWidget *notebook)
3296 GtkWidget *scrolled;
3298 GtkTextBuffer *buffer;
3301 GspellTextView *gspell_view;
3304 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3306 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3308 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3310 button = pref_button_new(hbox, GQ_ICON_RUN, _("Search"),
3311 G_CALLBACK(keywords_find_cb), keyword_text);
3312 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
3315 keyword_text = gtk_text_view_new();
3316 gtk_widget_set_size_request(keyword_text, 20, 20);
3317 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
3318 gq_gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3319 gtk_widget_show(scrolled);
3322 if (options->metadata.check_spelling)
3324 gspell_view = gspell_text_view_get_from_gtk_text_view(GTK_TEXT_VIEW(keyword_text));
3325 gspell_text_view_basic_setup(gspell_view);
3329 gq_gtk_container_add(GTK_WIDGET(scrolled), keyword_text);
3330 gtk_widget_show(keyword_text);
3332 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3334 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3335 gtk_text_buffer_create_tag(buffer, "monospace",
3336 "family", "monospace", NULL);
3338 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3339 gtk_text_buffer_get_start_iter(buffer, &iter);
3340 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3343 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3345 GList *kwl = keyword_list_get();
3346 kwl = g_list_first(kwl);
3349 gtk_text_buffer_get_end_iter (buffer, &iter);
3350 tmp = g_strconcat(static_cast<const gchar *>(kwl->data), "\n", NULL);
3351 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3356 gtk_text_buffer_set_modified(buffer, FALSE);
3363 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3365 auto option = static_cast<gint *>(data);
3367 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3371 *option = INTENT_PERCEPTUAL;
3374 *option = INTENT_RELATIVE_COLORIMETRIC;
3377 *option = INTENT_SATURATION;
3380 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3385 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3386 gint option, gint *option_c)
3393 pref_table_label(table, column, row, text, GTK_ALIGN_START);
3395 combo = gtk_combo_box_text_new();
3397 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3398 if (option == INTENT_PERCEPTUAL) current = 0;
3399 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3400 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3401 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3402 if (option == INTENT_SATURATION) current = 2;
3403 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3404 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3406 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3408 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3410 g_signal_connect(G_OBJECT(combo), "changed",
3411 G_CALLBACK(intent_menu_cb), option_c);
3413 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
3414 gtk_widget_show(combo);
3418 static void config_tab_color(GtkWidget *notebook)
3427 vbox = scrolled_notebook_page(notebook, _("Color management"));
3429 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3431 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3434 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3435 gtk_grid_set_column_spacing(GTK_GRID(table), PREF_PAD_GAP);
3437 label = pref_table_label(table, 0, 0, _("Type"), GTK_ALIGN_START);
3438 pref_label_bold(label, TRUE, FALSE);
3440 label = pref_table_label(table, 1, 0, _("Menu name"), GTK_ALIGN_START);
3441 pref_label_bold(label, TRUE, FALSE);
3443 label = pref_table_label(table, 2, 0, _("File"), GTK_ALIGN_START);
3444 pref_label_bold(label, TRUE, FALSE);
3446 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3451 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3452 pref_table_label(table, 0, i + 1, buf, GTK_ALIGN_END);
3455 entry = gtk_entry_new();
3456 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3457 if (options->color_profile.input_name[i])
3459 gq_gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3461 gq_gtk_grid_attach(GTK_GRID(table), entry, 1, 2, i + 1, i + 2, static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), static_cast<GtkAttachOptions>(0), 0, 0);
3462 gtk_widget_show(entry);
3463 color_profile_input_name_entry[i] = entry;
3465 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], nullptr, ".icc", "ICC Files", nullptr);
3466 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3467 gtk_widget_set_size_request(entry, 160, -1);
3468 gq_gtk_grid_attach(GTK_GRID(table), tabcomp, 2, 3, i + 1, i + 2, static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), static_cast<GtkAttachOptions>(0), 0, 0);
3469 gtk_widget_show(tabcomp);
3470 color_profile_input_file_entry[i] = entry;
3473 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3475 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3477 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3478 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3480 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3482 pref_table_label(table, 0, 0, _("Screen:"), GTK_ALIGN_END);
3483 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3484 options->color_profile.screen_file, nullptr, ".icc", "ICC Files", nullptr);
3485 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3486 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3488 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3490 gq_gtk_grid_attach(GTK_GRID(table), tabcomp, 1, 2, 0, 1, static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), static_cast<GtkAttachOptions>(0), 0, 0);
3492 gtk_widget_show(tabcomp);
3495 /* advanced entry tab */
3496 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer)
3498 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3500 c_options->file_ops.use_system_trash = FALSE;
3501 c_options->file_ops.no_trash = FALSE;
3505 static void use_system_trash_cb(GtkWidget *widget, gpointer)
3507 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3509 c_options->file_ops.use_system_trash = TRUE;
3510 c_options->file_ops.no_trash = FALSE;
3514 static void use_no_cache_cb(GtkWidget *widget, gpointer)
3516 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3518 c_options->file_ops.no_trash = TRUE;
3522 static void config_tab_behavior(GtkWidget *notebook)
3529 GtkWidget *ct_button;
3533 GtkWidget *with_rename;
3534 GtkWidget *collections_on_top;
3535 GtkWidget *hide_window_in_fullscreen;
3536 GtkWidget *checkbox;
3539 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3541 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3543 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3544 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3545 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3546 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3547 pref_checkbox_new_int(group, _("Enable Delete key"),
3548 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3550 ct_button = pref_radiobutton_new(group, nullptr, _("Use Geeqie trash location"),
3551 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),nullptr);
3553 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3554 pref_checkbox_link_sensitivity(ct_button, hbox);
3556 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3557 pref_label_new(hbox, _("Folder:"));
3559 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, nullptr, nullptr, nullptr, nullptr);
3560 tab_completion_add_select_button(safe_delete_path_entry, nullptr, TRUE);
3561 gq_gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3562 gtk_widget_show(tabcomp);
3564 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3565 pref_checkbox_link_sensitivity(ct_button, hbox);
3567 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3568 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MiB"),
3569 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3570 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3571 button = pref_button_new(nullptr, nullptr, _("View"),
3572 G_CALLBACK(safe_delete_view_cb), nullptr);
3573 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3574 gtk_widget_show(button);
3576 button = pref_button_new(nullptr, GQ_ICON_CLEAR, nullptr,
3577 G_CALLBACK(safe_delete_clear_cb), nullptr);
3578 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3580 c_options->file_ops.no_trash = options->file_ops.no_trash;
3581 c_options->file_ops.use_system_trash = options->file_ops.use_system_trash;
3583 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3584 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), nullptr);
3586 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3587 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), nullptr);
3589 gtk_widget_show(button);
3591 pref_spacer(group, PREF_PAD_GROUP);
3594 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3596 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3597 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3599 pref_checkbox_new_int(group, _("In place renaming"),
3600 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3602 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3603 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3605 tmp = pref_checkbox_new_int(group, _("Circular selection lists"),
3606 options->circular_selection_lists, &c_options->circular_selection_lists);
3607 gtk_widget_set_tooltip_text(tmp, _("Traverse selection lists in a circular manner"));
3609 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3610 options->marks_save, &c_options->marks_save);
3611 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3613 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3614 options->with_rename, &c_options->with_rename);
3615 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3617 collections_on_top = pref_checkbox_new_int(group, _("Permit duplicates in Collections"),
3618 options->collections_duplicates, &c_options->collections_duplicates);
3619 gtk_widget_set_tooltip_text(collections_on_top,"Allow the same image to be in a Collection more than once");
3621 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3622 options->collections_on_top, &c_options->collections_on_top);
3623 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3625 hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3626 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3627 gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice");
3629 pref_spin_new_int(group, _("Recent folder list maximum size"), nullptr,
3630 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3632 tmp = pref_spin_new_int(group, _("Recent folder-image list maximum size"), nullptr, 0, 50, 1, options->recent_folder_image_list_maxsize, &c_options->recent_folder_image_list_maxsize);
3633 gtk_widget_set_tooltip_text(tmp, _("List of the last image viewed in each recent folder.\nRe-opening a folder will set focus to the last image viewed."));
3635 pref_spin_new_int(group, _("Drag'n drop icon size"), nullptr,
3636 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3638 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3639 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3641 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3642 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3644 pref_spacer(group, PREF_PAD_GROUP);
3646 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3648 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3649 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3650 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), nullptr,
3651 1, 32, 1, options->keyboard_scroll_step, reinterpret_cast<int *>(&c_options->keyboard_scroll_step));
3652 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3653 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3654 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3655 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3656 pref_checkbox_new_int(group, _("Open archive by left click on image"),
3657 options->image_l_click_archive, &c_options->image_l_click_archive);
3658 pref_checkbox_new_int(group, _("Play video by left click on image"),
3659 options->image_l_click_video, &c_options->image_l_click_video);
3660 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3661 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3663 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3664 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3665 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3666 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3667 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3669 pref_spacer(group, PREF_PAD_GROUP);
3671 group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3673 checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3674 options->override_disable_gpu, &c_options->override_disable_gpu);
3675 gtk_widget_set_tooltip_text(checkbox, "Contact the developers for usage");
3678 pref_spacer(group, PREF_PAD_GROUP);
3680 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3682 pref_spin_new_int(group, _("Debug level:"), nullptr,
3683 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3685 pref_checkbox_new_int(group, _("Timer data"),
3686 options->log_window.timer_data, &c_options->log_window.timer_data);
3688 pref_spin_new_int(group, _("Log Window max. lines:"), nullptr,
3689 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3691 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3692 pref_label_new(hbox, _("Log Window F1 command: "));
3693 log_window_f1_entry = gtk_entry_new();
3694 gq_gtk_entry_set_text(GTK_ENTRY(log_window_f1_entry), options->log_window.action);
3695 gq_gtk_box_pack_start(GTK_BOX(hbox), log_window_f1_entry, FALSE, FALSE, 0);
3696 gtk_entry_set_width_chars(GTK_ENTRY(log_window_f1_entry), 15);
3697 gtk_widget_show(log_window_f1_entry);
3701 /* accelerators tab */
3703 static gboolean accel_search_function_cb(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer)
3705 gboolean ret = TRUE;
3710 gtk_tree_model_get(model, iter, column, &text, -1);
3711 text_nocase = g_utf8_casefold(text, -1);
3712 key_nocase = g_utf8_casefold(key, -1);
3714 if (g_strstr_len(text_nocase, -1, key_nocase))
3721 g_free(text_nocase);
3726 static void accel_row_activated_cb(GtkTreeView *tree_view, GtkTreePath *, GtkTreeViewColumn *column, gpointer)
3731 list = gtk_tree_view_get_columns(tree_view);
3732 col_num = g_list_index(list, column);
3736 gtk_tree_view_set_search_column(tree_view, col_num);
3739 static void config_tab_accelerators(GtkWidget *notebook)
3745 GtkWidget *scrolled;
3746 GtkWidget *accel_view;
3747 GtkCellRenderer *renderer;
3748 GtkTreeSelection *selection;
3749 GtkTreeViewColumn *column;
3751 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3753 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3755 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
3756 gq_gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3757 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3758 gq_gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3759 gtk_widget_show(scrolled);
3761 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3763 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3764 g_object_unref(accel_store);
3765 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3766 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3768 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3770 renderer = gtk_cell_renderer_text_new();
3772 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3777 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3778 gtk_tree_view_column_set_resizable(column, TRUE);
3779 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3782 renderer = gtk_cell_renderer_accel_new();
3783 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3784 G_CALLBACK(accel_store_cleared_cb), accel_store);
3785 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3786 G_CALLBACK(accel_store_edited_cb), accel_store);
3789 g_object_set (renderer,
3791 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3794 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3799 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3800 gtk_tree_view_column_set_resizable(column, TRUE);
3801 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3803 renderer = gtk_cell_renderer_text_new();
3805 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3810 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3811 gtk_tree_view_column_set_resizable(column, TRUE);
3812 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3814 renderer = gtk_cell_renderer_text_new();
3816 column = gtk_tree_view_column_new_with_attributes("Accel",
3821 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3822 gtk_tree_view_column_set_resizable(column, TRUE);
3823 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3825 /* Search on text in column */
3826 gtk_tree_view_set_activate_on_single_click(GTK_TREE_VIEW(accel_view), TRUE);
3827 g_signal_connect(accel_view, "row_activated", G_CALLBACK(accel_row_activated_cb), accel_store);
3828 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), TRUE);
3829 gtk_tree_view_set_search_column(GTK_TREE_VIEW(accel_view), AE_TOOLTIP);
3830 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(accel_view), accel_search_function_cb, nullptr, nullptr);
3832 accel_store_populate();
3833 gq_gtk_container_add(GTK_WIDGET(scrolled), accel_view);
3834 gtk_widget_show(accel_view);
3836 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3838 button = pref_button_new(nullptr, nullptr, _("Defaults"),
3839 G_CALLBACK(accel_default_cb), accel_view);
3840 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3841 gtk_widget_show(button);
3843 button = pref_button_new(nullptr, nullptr, _("Reset selected"),
3844 G_CALLBACK(accel_reset_cb), accel_view);
3845 gtk_widget_set_tooltip_text(button, _("Will only reset changes made before the settings are saved"));
3846 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3847 gtk_widget_show(button);
3849 button = pref_button_new(nullptr, nullptr, _("Clear selected"),
3850 G_CALLBACK(accel_clear_cb), accel_view);
3851 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3852 gtk_widget_show(button);
3855 /* toolbar main tab */
3856 static void config_tab_toolbar_main(GtkWidget *notebook)
3859 GtkWidget *toolbardata;
3862 lw = static_cast<LayoutWindow *>(layout_window_list->data);
3864 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3866 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3867 gq_gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3868 gtk_widget_show(vbox);
3871 /* toolbar status tab */
3872 static void config_tab_toolbar_status(GtkWidget *notebook)
3875 GtkWidget *toolbardata;
3878 lw = static_cast<LayoutWindow *>(layout_window_list->data);
3880 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3882 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3883 gq_gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3884 gtk_widget_show(vbox);
3888 static gint extension_sort_cb(gconstpointer a, gconstpointer b)
3890 return g_strcmp0(static_cast<const gchar *>(a), static_cast<const gchar *>(b));
3893 static void config_tab_advanced(GtkWidget *notebook)
3896 GdkPixbufFormat *fm;
3898 GList *extensions_list = nullptr;
3899 GSList *formats_list;
3900 GString *types_string = g_string_new(nullptr);
3901 GtkWidget *alternate_checkbox;
3902 GtkWidget *dupes_threads_spin;
3904 GtkWidget *subgroup;
3906 GtkWidget *threads_string_label;
3907 GtkWidget *types_string_label;
3910 vbox = scrolled_notebook_page(notebook, _("Advanced"));
3911 group = pref_group_new(vbox, FALSE, _("External preview extraction"), GTK_ORIENTATION_VERTICAL);
3913 pref_checkbox_new_int(group, _("Use external preview extraction - Requires restart"), options->external_preview.enable, &c_options->external_preview.enable);
3915 pref_spacer(group, PREF_PAD_GROUP);
3917 formats_list = gdk_pixbuf_get_formats();
3919 while (formats_list)
3921 fm = static_cast<GdkPixbufFormat *>(formats_list->data);
3922 extensions = gdk_pixbuf_format_get_extensions(fm);
3925 while (extensions[i])
3927 extensions_list = g_list_insert_sorted(extensions_list, g_strdup(extensions[i]), extension_sort_cb);
3931 g_strfreev(extensions);
3932 formats_list = formats_list->next;
3935 while (extensions_list)
3937 if (types_string->len == 0)
3939 types_string = g_string_append(types_string, static_cast<const gchar *>(extensions_list->data));
3943 types_string = g_string_append(types_string, ", ");
3944 types_string = g_string_append(types_string, static_cast<const gchar *>(extensions_list->data));
3947 extensions_list = extensions_list->next;
3950 types_string = g_string_prepend(types_string, _("Usable file types:\n"));
3951 types_string_label = pref_label_new(group, types_string->str);
3952 gtk_label_set_line_wrap(GTK_LABEL(types_string_label), TRUE);
3954 pref_spacer(group, PREF_PAD_GROUP);
3956 group = pref_group_new(vbox, FALSE, _("File identification tool"), GTK_ORIENTATION_VERTICAL);
3957 external_preview_select_entry = gtk_entry_new();
3958 tabcomp = tab_completion_new(&external_preview_select_entry, options->external_preview.select, nullptr, nullptr, nullptr, nullptr);
3959 tab_completion_add_select_button(external_preview_select_entry, _("Select file identification tool"), FALSE);
3960 gq_gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3961 gtk_widget_show(tabcomp);
3963 group = pref_group_new(vbox, FALSE, _("Preview extraction tool"), GTK_ORIENTATION_VERTICAL);
3964 external_preview_extract_entry = gtk_entry_new();
3965 tabcomp = tab_completion_new(&external_preview_extract_entry, options->external_preview.extract, nullptr, nullptr, nullptr, nullptr);
3966 tab_completion_add_select_button(external_preview_extract_entry, _("Select preview extraction tool"), FALSE);
3967 gq_gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3968 gtk_widget_show(tabcomp);
3970 gtk_widget_show(vbox);
3972 g_slist_free(formats_list);
3973 g_list_free_full(extensions_list, g_free);
3974 g_string_free(types_string, TRUE);
3976 pref_spacer(group, PREF_PAD_GROUP);
3978 pref_line(vbox, PREF_PAD_SPACE);
3979 group = pref_group_new(vbox, FALSE, _("Thread pool limits"), GTK_ORIENTATION_VERTICAL);
3981 threads_string_label = pref_label_new(group, "This option limits the number of threads (or cpu cores) that Geeqie will use when running duplicate checks.\nThe value 0 means all available cores will be used.");
3982 gtk_label_set_line_wrap(GTK_LABEL(threads_string_label), TRUE);
3984 pref_spacer(vbox, PREF_PAD_GROUP);
3986 dupes_threads_spin = pref_spin_new_int(vbox, _("Duplicate check:"), _("max. threads"), 0, get_cpu_cores(), 1, options->threads.duplicates, &c_options->threads.duplicates);
3987 gtk_widget_set_tooltip_markup(dupes_threads_spin, _("Set to 0 for unlimited"));
3989 pref_spacer(group, PREF_PAD_GROUP);
3991 pref_line(vbox, PREF_PAD_SPACE);
3993 group = pref_group_new(vbox, FALSE, _("Alternate similarity alogorithm"), GTK_ORIENTATION_VERTICAL);
3995 alternate_checkbox = pref_checkbox_new_int(group, _("Enable alternate similarity algorithm"), options->alternate_similarity_algorithm.enabled, &c_options->alternate_similarity_algorithm.enabled);
3997 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
3998 pref_checkbox_link_sensitivity(alternate_checkbox, subgroup);
4000 alternate_checkbox = pref_checkbox_new_int(subgroup, _("Use grayscale"), options->alternate_similarity_algorithm.grayscale, &c_options->alternate_similarity_algorithm.grayscale);
4001 gtk_widget_set_tooltip_text(alternate_checkbox, _("Reduce fingerprint to grayscale"));
4005 static void config_tab_stereo(GtkWidget *notebook)
4013 GtkWidget *fs_button;
4014 vbox = scrolled_notebook_page(notebook, _("Stereo"));
4016 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
4018 table = pref_table_new(group, 2, 1, FALSE, FALSE);
4019 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
4021 table = pref_table_new(group, 2, 2, TRUE, FALSE);
4022 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
4023 pref_checkbox_new_int(box, _("Mirror left image"),
4024 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
4025 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
4026 pref_checkbox_new_int(box, _("Flip left image"),
4027 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
4028 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
4029 pref_checkbox_new_int(box, _("Mirror right image"),
4030 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
4031 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
4032 pref_checkbox_new_int(box, _("Flip right image"),
4033 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
4034 pref_checkbox_new_int(group, _("Swap left and right images"),
4035 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
4036 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
4037 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
4039 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
4040 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
4041 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
4042 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
4043 pref_checkbox_link_sensitivity(fs_button, box2);
4044 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
4045 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
4046 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
4047 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
4048 pref_checkbox_new_int(box, _("Mirror left image"),
4049 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
4050 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
4051 pref_checkbox_new_int(box, _("Flip left image"),
4052 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
4053 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
4054 pref_checkbox_new_int(box, _("Mirror right image"),
4055 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
4056 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
4057 pref_checkbox_new_int(box, _("Flip right image"),
4058 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
4059 pref_checkbox_new_int(box2, _("Swap left and right images"),
4060 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
4061 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
4062 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
4064 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
4065 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
4066 pref_table_spin_new_int(table, 0, 0, _("Width"), nullptr,
4067 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
4068 pref_table_spin_new_int(table, 3, 0, _("Height"), nullptr,
4069 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
4070 pref_table_spin_new_int(table, 0, 1, _("Left X"), nullptr,
4071 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
4072 pref_table_spin_new_int(table, 3, 1, _("Left Y"), nullptr,
4073 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
4074 pref_table_spin_new_int(table, 0, 2, _("Right X"), nullptr,
4075 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
4076 pref_table_spin_new_int(table, 3, 2, _("Right Y"), nullptr,
4077 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
4081 /* Main preferences window */
4082 static void config_window_create(LayoutWindow *lw)
4084 GtkWidget *win_vbox;
4086 GtkWidget *notebook;
4088 GtkWidget *ct_button;
4090 if (!c_options) c_options = init_options(nullptr);
4092 configwindow = window_new("preferences", PIXBUF_INLINE_ICON_CONFIG, nullptr, _("Preferences"));
4093 DEBUG_NAME(configwindow);
4094 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
4095 g_signal_connect(G_OBJECT(configwindow), "delete_event",
4096 G_CALLBACK(config_window_delete), NULL);
4097 if (options->save_dialog_window_positions)
4099 gtk_window_resize(GTK_WINDOW(configwindow), lw->options.preferences_window.w, lw->options.preferences_window.h);
4100 gq_gtk_window_move(GTK_WINDOW(configwindow), lw->options.preferences_window.x, lw->options.preferences_window.y);
4104 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
4106 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
4107 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
4109 win_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
4110 gq_gtk_container_add(GTK_WIDGET(configwindow), win_vbox);
4111 gtk_widget_show(win_vbox);
4113 notebook = gtk_notebook_new();
4114 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
4115 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
4116 gq_gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
4118 config_tab_general(notebook);
4119 config_tab_image(notebook);
4120 config_tab_osd(notebook);
4121 config_tab_windows(notebook);
4122 config_tab_accelerators(notebook);
4123 config_tab_files(notebook);
4124 config_tab_metadata(notebook);
4125 config_tab_keywords(notebook);
4126 config_tab_color(notebook);
4127 config_tab_stereo(notebook);
4128 config_tab_behavior(notebook);
4129 config_tab_toolbar_main(notebook);
4130 config_tab_toolbar_status(notebook);
4131 config_tab_advanced(notebook);
4133 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), lw->options.preferences_window.page_number);
4135 hbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
4136 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
4137 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
4138 gq_gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
4139 gtk_widget_show(hbox);
4141 button = pref_button_new(nullptr, GQ_ICON_HELP, _("Help"),
4142 G_CALLBACK(config_window_help_cb), notebook);
4143 gq_gtk_container_add(GTK_WIDGET(hbox), button);
4144 gtk_widget_set_can_default(button, TRUE);
4145 gtk_widget_show(button);
4147 button = pref_button_new(nullptr, GQ_ICON_OK, "OK",
4148 G_CALLBACK(config_window_ok_cb), notebook);
4149 gq_gtk_container_add(GTK_WIDGET(hbox), button);
4150 gtk_widget_set_can_default(button, TRUE);
4151 gtk_widget_grab_default(button);
4152 gtk_widget_show(button);
4156 button = pref_button_new(nullptr, GQ_ICON_CANCEL, _("Cancel"),
4157 G_CALLBACK(config_window_close_cb), nullptr);
4158 gq_gtk_container_add(GTK_WIDGET(hbox), button);
4159 gtk_widget_set_can_default(button, TRUE);
4160 gtk_widget_show(button);
4162 if (!generic_dialog_get_alternative_button_order(configwindow))
4164 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
4167 gtk_widget_show(notebook);
4169 gtk_widget_show(configwindow);
4173 *-----------------------------------------------------------------------------
4174 * config window show (public)
4175 *-----------------------------------------------------------------------------
4178 void show_config_window(LayoutWindow *lw)
4182 gtk_window_present(GTK_WINDOW(configwindow));
4186 config_window_create(lw);
4195 void show_about_window(LayoutWindow *lw)
4197 GDataInputStream *data_stream;
4198 GInputStream *in_stream_authors;
4199 GInputStream *in_stream_translators;
4201 GdkPixbuf *pixbuf_icon;
4202 GdkPixbuf *pixbuf_logo;
4206 gchar *authors[1000];
4208 gchar *timezone_path;
4217 copyright = g_string_new("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");
4219 timezone_path = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
4220 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
4222 cd = ZDOpenDatabase(timezone_path);
4225 copyright = g_string_append(copyright, ZDGetNotice(cd));
4229 log_printf("Error: Init of timezone database %s failed\n", timezone_path);
4231 ZDCloseDatabase(cd);
4233 g_free(timezone_path);
4235 copyright = g_string_append(copyright, "\n\nSome icons by https://www.flaticon.com");
4237 in_stream_authors = g_resources_open_stream(GQ_RESOURCE_PATH_CREDITS "/authors", G_RESOURCE_LOOKUP_FLAGS_NONE, nullptr);
4239 data_stream = g_data_input_stream_new(in_stream_authors);
4241 authors[0] = nullptr;
4242 while ((author_line = g_data_input_stream_read_line(G_DATA_INPUT_STREAM(data_stream), &length, nullptr, nullptr)))
4244 authors[i_authors] = g_strdup(author_line);
4246 g_free(author_line);
4248 authors[i_authors] = nullptr;
4250 g_input_stream_close(in_stream_authors, nullptr, nullptr);
4252 constexpr auto translators_path = GQ_RESOURCE_PATH_CREDITS "/translators";
4254 g_resources_get_info(translators_path, G_RESOURCE_LOOKUP_FLAGS_NONE, &size, &flags, nullptr);
4256 in_stream_translators = g_resources_open_stream(translators_path, G_RESOURCE_LOOKUP_FLAGS_NONE, nullptr);
4257 translators = static_cast<gchar *>(g_malloc0(size));
4258 g_input_stream_read_all(in_stream_translators, translators, size, &bytes_read, nullptr, nullptr);
4259 g_input_stream_close(in_stream_translators, nullptr, nullptr);
4261 comment = g_strconcat("Project created by John Ellis\nGQview 1998\nGeeqie 2007\n\n\nDevelopment and bug reports:\n", GQ_EMAIL_ADDRESS, "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
4263 artists[0] = g_strdup("Néstor Díaz Valencia <nestor@estudionexos.com>");
4264 artists[1] = nullptr;
4266 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
4267 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
4268 gtk_show_about_dialog(GTK_WINDOW(lw->window),
4269 "title", _("About Geeqie"),
4271 "program-name", GQ_APPNAME,
4273 "logo", pixbuf_logo,
4274 "icon", pixbuf_icon,
4275 "website", GQ_WEBSITE,
4276 "website-label", "Website",
4277 "comments", comment,
4280 "translator-credits", translators,
4281 "wrap-license", TRUE,
4282 "license", copyright->str,
4285 g_string_free(copyright, TRUE);
4287 while(n < i_authors)
4295 g_free(translators);
4296 g_object_unref(data_stream);
4297 g_object_unref(in_stream_authors);
4298 g_object_unref(in_stream_translators);
4301 static void image_overlay_set_text_colors()
4303 c_options->image_overlay.text_red = options->image_overlay.text_red;
4304 c_options->image_overlay.text_green = options->image_overlay.text_green;
4305 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
4306 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
4307 c_options->image_overlay.background_red = options->image_overlay.background_red;
4308 c_options->image_overlay.background_green = options->image_overlay.background_green;
4309 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
4310 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
4314 *-----------------------------------------------------------------------------
4315 * timezone database routines
4316 *-----------------------------------------------------------------------------
4319 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
4321 GError *error = nullptr;
4322 auto tz = static_cast<TZData *>(data);
4323 gchar *tmp_filename;
4324 gchar *timezone_bin;
4325 gchar *tmp_dir = nullptr;
4328 if (!g_cancellable_is_cancelled(tz->cancellable))
4330 generic_dialog_close(tz->gd);
4334 if (g_file_copy_finish(G_FILE(source_object), res, &error))
4336 tmp_filename = g_file_get_path(tz->tmp_g_file);
4337 fd = file_data_new_simple(tmp_filename);
4338 tmp_dir = open_archive(fd);
4342 timezone_bin = g_build_filename(tmp_dir, TIMEZONE_DATABASE_VERSION, TIMEZONE_DATABASE_FILE, NULL);
4343 if (isfile(timezone_bin))
4345 move_file(timezone_bin, tz->timezone_database_user);
4349 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GQ_ICON_DIALOG_WARNING, nullptr);
4352 g_free(timezone_bin);
4353 g_free(tmp_dir); // The folder in /tmp is deleted in exit_program_final()
4357 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GQ_ICON_DIALOG_WARNING, nullptr);
4359 g_free(tmp_filename);
4360 file_data_unref(fd);
4364 file_util_warning_dialog(_("Error: Timezone database download failed"), error->message, GQ_ICON_DIALOG_ERROR, nullptr);
4367 g_file_delete(tz->tmp_g_file, nullptr, &error);
4368 g_object_unref(tz->tmp_g_file);
4369 tz->tmp_g_file = nullptr;
4370 g_object_unref(tz->cancellable);
4371 g_object_unref(tz->timezone_database_gq);
4374 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
4376 auto tz = static_cast<TZData *>(data);
4378 if (!g_cancellable_is_cancelled(tz->cancellable))
4380 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), static_cast<gdouble>(current_num_bytes) / total_num_bytes);
4384 static void timezone_cancel_button_cb(GenericDialog *, gpointer data)
4386 auto tz = static_cast<TZData *>(data);
4388 g_cancellable_cancel(tz->cancellable);
4391 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
4393 auto tz = static_cast<TZData *>(data);
4394 GError *error = nullptr;
4395 GFileIOStream *io_stream;
4402 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
4406 file_util_warning_dialog(_("Timezone database download failed"), error->message, GQ_ICON_DIALOG_ERROR, nullptr);
4407 log_printf("Error: Download timezone database failed:\n%s", error->message);
4408 g_error_free(error);
4409 g_object_unref(tz->tmp_g_file);
4413 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE_WEB);
4415 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", nullptr, TRUE, timezone_cancel_button_cb, tz);
4417 generic_dialog_add_message(tz->gd, GQ_ICON_DIALOG_INFO, _("Downloading timezone database"), nullptr, FALSE);
4419 tz->progress = gtk_progress_bar_new();
4420 gq_gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
4421 gtk_widget_show(tz->progress);
4423 gtk_widget_show(tz->gd->dialog);
4424 tz->cancellable = g_cancellable_new();
4425 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);
4427 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
4430 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */