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"
29 #include <gdk-pixbuf/gdk-pixbuf.h>
32 #include <glib-object.h>
35 #include <gspell/gspell.h>
46 #include <pango/pango.h>
49 #include "bar-keywords.h"
51 #include "color-man.h"
56 #include "filefilter.h"
57 #include "fullscreen.h"
58 #include "image-overlay.h"
62 #include "layout-util.h"
64 #include "main-defines.h"
70 #include "pixbuf-util.h"
72 #include "slideshow.h"
73 #include "third-party/zonedetect.h"
77 #include "ui-fileops.h"
79 #include "ui-tabcomp.h"
80 #include "ui-utildlg.h"
87 constexpr gint PRE_FORMATTED_COLUMNS = 5;
88 constexpr gint KEYWORD_DIALOG_WIDTH = 400;
95 EDITOR_NAME_MAX_LENGTH = 32,
96 EDITOR_COMMAND_MAX_LENGTH = 1024
99 static void image_overlay_set_text_colors();
101 GtkWidget *keyword_text;
102 static void config_tab_keywords_save();
110 static ThumbSize thumb_size_list[] =
146 FILETYPES_COLUMN_ENABLED = 0,
147 FILETYPES_COLUMN_FILTER,
148 FILETYPES_COLUMN_DESCRIPTION,
149 FILETYPES_COLUMN_CLASS,
150 FILETYPES_COLUMN_WRITABLE,
151 FILETYPES_COLUMN_SIDECAR,
152 FILETYPES_COLUMN_COUNT
155 const gchar *format_class_list[] = {
166 /* config memory values */
167 static ConfOptions *c_options = nullptr;
174 static GtkWidget *configwindow = nullptr;
175 static GtkListStore *filter_store = nullptr;
176 static GtkTreeStore *accel_store = nullptr;
178 static GtkWidget *safe_delete_path_entry;
180 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
181 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
182 static GtkWidget *color_profile_screen_file_entry;
183 static GtkWidget *external_preview_select_entry;
184 static GtkWidget *external_preview_extract_entry;
186 static GtkWidget *sidecar_ext_entry;
187 static GtkWidget *help_search_engine_entry;
189 static GtkWidget *log_window_f1_entry;
193 CONFIG_WINDOW_DEF_WIDTH = 700,
194 CONFIG_WINDOW_DEF_HEIGHT = 600
198 *-----------------------------------------------------------------------------
199 * option widget callbacks (private)
200 *-----------------------------------------------------------------------------
203 static void zoom_increment_cb(GtkWidget *spin, gpointer)
205 c_options->image.zoom_increment = static_cast<gint>(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
208 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer)
210 gint mins_secs_tenths;
213 mins_secs_tenths = c_options->slideshow.delay %
214 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
216 delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
217 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
220 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
221 SLIDESHOW_SUBSECOND_PRECISION;
224 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer)
230 hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
231 secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
233 delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
234 (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
235 (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
237 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
238 SLIDESHOW_SUBSECOND_PRECISION;
241 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer)
246 hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
248 delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
249 static_cast<gint>(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
250 static_cast<gdouble>(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
252 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
253 SLIDESHOW_SUBSECOND_PRECISION;
257 *-----------------------------------------------------------------------------
258 * sync program to config window routine (private)
259 *-----------------------------------------------------------------------------
262 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
268 buf = gq_gtk_entry_get_text(GTK_ENTRY(entry));
269 if (buf && strlen(buf) > 0)
274 *option = g_strdup(buf);
279 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *, GtkTreeIter *iter, gpointer)
284 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
286 if (accel_path && accel_path[0])
289 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
290 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
300 static void config_window_apply()
302 gboolean refresh = FALSE;
307 config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
309 if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
310 if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
311 if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
312 if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
313 if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
314 if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
316 options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
317 options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
318 options->file_ops.confirm_move_to_trash = c_options->file_ops.confirm_move_to_trash;
319 options->file_ops.use_system_trash = c_options->file_ops.use_system_trash;
320 options->file_ops.no_trash = c_options->file_ops.no_trash;
321 options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
322 options->tools_restore_state = c_options->tools_restore_state;
323 options->save_window_positions = c_options->save_window_positions;
324 options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
325 options->save_window_workspace = c_options->save_window_workspace;
326 options->save_dialog_window_positions = c_options->save_dialog_window_positions;
327 options->hide_window_decorations = c_options->hide_window_decorations;
328 options->show_window_ids = c_options->show_window_ids;
329 options->image.scroll_reset_method = c_options->image.scroll_reset_method;
330 options->image.zoom_2pass = c_options->image.zoom_2pass;
331 options->image.fit_window_to_image = c_options->image.fit_window_to_image;
332 options->image.limit_window_size = c_options->image.limit_window_size;
333 options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
334 options->image.max_window_size = c_options->image.max_window_size;
335 options->image.limit_autofit_size = c_options->image.limit_autofit_size;
336 options->image.max_autofit_size = c_options->image.max_autofit_size;
337 options->image.max_enlargement_size = c_options->image.max_enlargement_size;
338 options->image.tile_size = c_options->image.tile_size;
339 options->progressive_key_scrolling = c_options->progressive_key_scrolling;
340 options->keyboard_scroll_step = c_options->keyboard_scroll_step;
342 if (options->thumbnails.max_width != c_options->thumbnails.max_width
343 || options->thumbnails.max_height != c_options->thumbnails.max_height
344 || options->thumbnails.quality != c_options->thumbnails.quality)
346 thumb_format_changed = TRUE;
348 options->thumbnails.max_width = c_options->thumbnails.max_width;
349 options->thumbnails.max_height = c_options->thumbnails.max_height;
350 options->thumbnails.quality = c_options->thumbnails.quality;
352 options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
353 options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
354 options->thumbnails.use_exif = c_options->thumbnails.use_exif;
355 options->thumbnails.use_color_management = c_options->thumbnails.use_color_management;
356 options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
357 options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
358 options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
359 options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
360 options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
361 options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
362 options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
363 options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
365 options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
366 options->file_filter.disable = c_options->file_filter.disable;
368 config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, nullptr);
369 sidecar_ext_parse(options->sidecar.ext);
371 options->slideshow.random = c_options->slideshow.random;
372 options->slideshow.repeat = c_options->slideshow.repeat;
373 options->slideshow.delay = c_options->slideshow.delay;
375 options->mousewheel_scrolls = c_options->mousewheel_scrolls;
376 options->image_lm_click_nav = c_options->image_lm_click_nav;
377 options->image_l_click_archive = c_options->image_l_click_archive;
378 options->image_l_click_video = c_options->image_l_click_video;
379 options->image_l_click_video_editor = c_options->image_l_click_video_editor;
381 options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
383 options->image.tile_cache_max = c_options->image.tile_cache_max;
384 options->image.image_cache_max = c_options->image.image_cache_max;
386 options->image.zoom_quality = c_options->image.zoom_quality;
388 options->image.zoom_increment = c_options->image.zoom_increment;
390 options->image.zoom_style = c_options->image.zoom_style;
392 options->image.enable_read_ahead = c_options->image.enable_read_ahead;
394 options->appimage_notifications = c_options->appimage_notifications;
397 if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
398 || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
399 || !gdk_rgba_equal(&options->image.border_color, &c_options->image.border_color))
401 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
402 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
403 options->image.border_color = c_options->image.border_color;
404 layout_colors_update();
405 view_window_colors_update();
408 options->image.alpha_color_1 = c_options->image.alpha_color_1;
409 options->image.alpha_color_2 = c_options->image.alpha_color_2;
411 options->fullscreen.screen = c_options->fullscreen.screen;
412 options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
413 options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
414 options->fullscreen.above = c_options->fullscreen.above;
415 if (c_options->image_overlay.template_string)
416 set_image_overlay_template_string(&options->image_overlay.template_string,
417 c_options->image_overlay.template_string);
418 if (c_options->image_overlay.font)
419 set_image_overlay_font_string(&options->image_overlay.font,
420 c_options->image_overlay.font);
421 options->image_overlay.text_red = c_options->image_overlay.text_red;
422 options->image_overlay.text_green = c_options->image_overlay.text_green;
423 options->image_overlay.text_blue = c_options->image_overlay.text_blue;
424 options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
425 options->image_overlay.background_red = c_options->image_overlay.background_red;
426 options->image_overlay.background_green = c_options->image_overlay.background_green;
427 options->image_overlay.background_blue = c_options->image_overlay.background_blue;
428 options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
429 options->image_overlay.font = c_options->image_overlay.font;
430 options->update_on_time_change = c_options->update_on_time_change;
432 options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
433 options->rot_invariant_sim = c_options->rot_invariant_sim;
435 options->tree_descend_subdirs = c_options->tree_descend_subdirs;
437 options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
438 options->circular_selection_lists = c_options->circular_selection_lists;
440 options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
441 options->recent_folder_image_list_maxsize = c_options->recent_folder_image_list_maxsize;
442 options->dnd_icon_size = c_options->dnd_icon_size;
443 options->clipboard_selection = c_options->clipboard_selection;
444 options->dnd_default_action = c_options->dnd_default_action;
446 options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
447 options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
448 options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
449 options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
450 options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
451 options->metadata.confirm_write = c_options->metadata.confirm_write;
452 options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
453 options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
454 options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
455 options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
456 options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
457 options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
458 options->metadata.write_orientation = c_options->metadata.write_orientation;
459 options->metadata.check_spelling = c_options->metadata.check_spelling;
460 options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
461 (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
462 (c_options->stereo.tmp.flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
463 (c_options->stereo.tmp.mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
464 (c_options->stereo.tmp.flip_left ? PR_STEREO_FLIP_LEFT : 0) |
465 (c_options->stereo.tmp.swap ? PR_STEREO_SWAP : 0) |
466 (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
467 options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
468 (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
469 (c_options->stereo.tmp.fs_flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
470 (c_options->stereo.tmp.fs_mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
471 (c_options->stereo.tmp.fs_flip_left ? PR_STEREO_FLIP_LEFT : 0) |
472 (c_options->stereo.tmp.fs_swap ? PR_STEREO_SWAP : 0) |
473 (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
474 options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
475 options->stereo.fixed_w = c_options->stereo.fixed_w;
476 options->stereo.fixed_h = c_options->stereo.fixed_h;
477 options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
478 options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
479 options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
480 options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
482 options->info_keywords.height = c_options->info_keywords.height;
483 options->info_title.height = c_options->info_title.height;
484 options->info_comment.height = c_options->info_comment.height;
485 options->info_rating.height = c_options->info_rating.height;
487 options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
488 options->expand_menu_toolbar = c_options->expand_menu_toolbar;
489 options->hamburger_menu = c_options->hamburger_menu;
491 options->selectable_bars.menu_bar = c_options->selectable_bars.menu_bar;
492 options->selectable_bars.tool_bar = c_options->selectable_bars.tool_bar;
493 options->selectable_bars.status_bar = c_options->selectable_bars.status_bar;
495 options->marks_save = c_options->marks_save;
496 options->with_rename = c_options->with_rename;
497 options->collections_duplicates = c_options->collections_duplicates;
498 options->collections_on_top = c_options->collections_on_top;
499 options->hide_window_in_fullscreen = c_options->hide_window_in_fullscreen;
500 options->hide_osd_in_fullscreen = c_options->hide_osd_in_fullscreen;
501 config_entry_to_option(help_search_engine_entry, &options->help_search_engine, nullptr);
503 options->external_preview.enable = c_options->external_preview.enable;
504 config_entry_to_option(external_preview_select_entry, &options->external_preview.select, nullptr);
505 config_entry_to_option(external_preview_extract_entry, &options->external_preview.extract, nullptr);
507 options->read_metadata_in_idle = c_options->read_metadata_in_idle;
509 options->star_rating.star = c_options->star_rating.star;
510 options->star_rating.rejected = c_options->star_rating.rejected;
512 options->threads.duplicates = c_options->threads.duplicates > 0 ? c_options->threads.duplicates : -1;
514 options->alternate_similarity_algorithm.enabled = c_options->alternate_similarity_algorithm.enabled;
515 options->alternate_similarity_algorithm.grayscale = c_options->alternate_similarity_algorithm.grayscale;
518 set_debug_level(debug_c);
519 config_entry_to_option(log_window_f1_entry, &options->log_window.action, nullptr);
523 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
525 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], nullptr);
526 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], nullptr);
528 config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, nullptr);
529 options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
530 if (options->color_profile.render_intent != c_options->color_profile.render_intent)
532 options->color_profile.render_intent = c_options->color_profile.render_intent;
537 options->mouse_button_8 = c_options->mouse_button_8;
538 options->mouse_button_9 = c_options->mouse_button_9;
540 options->override_disable_gpu = c_options->override_disable_gpu;
542 config_tab_keywords_save();
544 image_options_sync();
549 layout_refresh(nullptr);
552 if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, nullptr);
554 toolbar_apply(TOOLBAR_MAIN);
555 toolbar_apply(TOOLBAR_STATUS);
559 *-----------------------------------------------------------------------------
560 * config window main button callbacks (private)
561 *-----------------------------------------------------------------------------
564 static void config_window_close_cb(GtkWidget *, gpointer)
566 gq_gtk_widget_destroy(configwindow);
567 configwindow = nullptr;
568 filter_store = nullptr;
571 static void config_window_help_cb(GtkWidget *, gpointer data)
573 auto notebook = static_cast<GtkWidget *>(data);
576 static const gchar *html_section[] =
578 "GuideOptionsGeneral.html",
579 "GuideOptionsImage.html",
580 "GuideOptionsOSD.html",
581 "GuideOptionsWindow.html",
582 "GuideOptionsKeyboard.html",
583 "GuideOptionsFiltering.html",
584 "GuideOptionsMetadata.html",
585 "GuideOptionsKeywords.html",
586 "GuideOptionsColor.html",
587 "GuideOptionsStereo.html",
588 "GuideOptionsBehavior.html",
589 "GuideOptionsToolbar.html",
590 "GuideOptionsToolbar.html",
591 "GuideOptionsAdvanced.html"
594 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
595 help_window_show(html_section[i]);
598 static gboolean config_window_delete(GtkWidget *, GdkEventAny *, gpointer)
600 config_window_close_cb(nullptr, nullptr);
604 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
607 auto notebook = static_cast<GtkNotebook *>(data);
615 lw = static_cast<LayoutWindow *>(layout_window_list->data);
617 window = gtk_widget_get_window(widget);
618 gdk_window_get_root_origin(window, &x, &y);
619 w = gdk_window_get_width(window);
620 h = gdk_window_get_height(window);
621 page_number = gtk_notebook_get_current_page(notebook);
623 lw->options.preferences_window.x = x;
624 lw->options.preferences_window.y = y;
625 lw->options.preferences_window.w = w;
626 lw->options.preferences_window.h = h;
627 lw->options.preferences_window.page_number = page_number;
629 config_window_apply();
630 layout_util_sync(lw);
631 save_options(options);
632 config_window_close_cb(nullptr, nullptr);
636 *-----------------------------------------------------------------------------
637 * config window setup (private)
638 *-----------------------------------------------------------------------------
641 static void quality_menu_cb(GtkWidget *combo, gpointer data)
643 auto option = static_cast<gint *>(data);
645 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
649 *option = GDK_INTERP_NEAREST;
652 *option = GDK_INTERP_TILES;
655 *option = GDK_INTERP_BILINEAR;
660 static void dnd_default_action_selection_menu_cb(GtkWidget *combo, gpointer data)
662 auto option = static_cast<gint *>(data);
664 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
668 *option = DND_ACTION_ASK;
671 *option = DND_ACTION_COPY;
674 *option = DND_ACTION_MOVE;
678 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
680 auto option = static_cast<gint *>(data);
682 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
685 *option = CLIPBOARD_PRIMARY;
688 *option = CLIPBOARD_CLIPBOARD;
691 *option = CLIPBOARD_BOTH;
694 *option = CLIPBOARD_BOTH;
698 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
699 guint option, guint *option_c)
706 pref_table_label(table, column, row, text, GTK_ALIGN_START);
708 combo = gtk_combo_box_text_new();
710 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
711 if (option == GDK_INTERP_NEAREST) current = 0;
712 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
713 if (option == GDK_INTERP_TILES) current = 1;
714 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear (best, but slowest)"));
715 if (option == GDK_INTERP_BILINEAR) current = 2;
717 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
719 g_signal_connect(G_OBJECT(combo), "changed",
720 G_CALLBACK(quality_menu_cb), option_c);
722 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
723 gtk_widget_show(combo);
726 static void add_dnd_default_action_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, DnDAction option, DnDAction *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), _("Ask"));
738 if (option == DND_ACTION_ASK) current = 0;
739 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Copy"));
740 if (option == DND_ACTION_COPY) current = 1;
741 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Move"));
742 if (option == DND_ACTION_MOVE) current = 2;
744 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
746 g_signal_connect(G_OBJECT(combo), "changed",
747 G_CALLBACK(dnd_default_action_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 add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
754 gint option, gint *option_c)
761 pref_table_label(table, column, row, text, GTK_ALIGN_START);
763 combo = gtk_combo_box_text_new();
765 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Primary"));
766 if (option == CLIPBOARD_PRIMARY) current = 0;
767 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Clipboard"));
768 if (option == CLIPBOARD_CLIPBOARD) current = 1;
769 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Both"));
770 if (option == CLIPBOARD_BOTH) current = 2;
772 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
774 g_signal_connect(G_OBJECT(combo), "changed",
775 G_CALLBACK(clipboard_selection_menu_cb), option_c);
777 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
778 gtk_widget_show(combo);
781 static void zoom_style_selection_menu_cb(GtkWidget *combo, gpointer data)
783 auto option = static_cast<gint *>(data);
785 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
788 *option = ZOOM_GEOMETRIC;
791 *option = ZOOM_ARITHMETIC;
794 *option = ZOOM_GEOMETRIC;
798 static void add_zoom_style_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, ZoomStyle option, ZoomStyle *option_c)
805 pref_table_label(table, column, row, text, GTK_ALIGN_START);
807 combo = gtk_combo_box_text_new();
809 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Geometric"));
810 if (option == ZOOM_GEOMETRIC) current = 0;
811 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Arithmetic"));
812 if (option == ZOOM_ARITHMETIC) current = 1;
814 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
816 g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(zoom_style_selection_menu_cb), option_c);
818 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
819 gtk_widget_show(combo);
822 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
824 auto option = static_cast<gchar **>(data);
829 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
831 list = get_action_items();
832 work = g_list_find_custom(list, label, reinterpret_cast<GCompareFunc>(action_item_compare_label));
835 auto *action_item = static_cast<ActionItem *>(work->data);
838 *option = g_strdup(action_item->name);
842 action_items_free(list);
845 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, gchar *option, gchar **option_c)
847 ActionItem *action_item;
856 pref_table_label(table, column, row, text, GTK_ALIGN_START);
858 combo = gtk_combo_box_text_new();
860 list = get_action_items();
864 action_item = static_cast<ActionItem *>(work->data);
865 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), action_item->label);
867 if (g_strcmp0(action_item->name, option) == 0)
875 action_items_free(list);
877 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
879 g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
881 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
882 gtk_widget_show(combo);
885 static void thumb_size_menu_cb(GtkWidget *combo, gpointer)
889 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
892 if (static_cast<guint>(n) < sizeof(thumb_size_list) / sizeof(ThumbSize))
894 c_options->thumbnails.max_width = thumb_size_list[n].w;
895 c_options->thumbnails.max_height = thumb_size_list[n].h;
899 c_options->thumbnails.max_width = options->thumbnails.max_width;
900 c_options->thumbnails.max_height = options->thumbnails.max_height;
904 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
910 c_options->thumbnails.max_width = options->thumbnails.max_width;
911 c_options->thumbnails.max_height = options->thumbnails.max_height;
913 pref_table_label(table, column, row, text, GTK_ALIGN_START);
915 combo = gtk_combo_box_text_new();
918 for (i = 0; static_cast<guint>(i) < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
924 w = thumb_size_list[i].w;
925 h = thumb_size_list[i].h;
927 buf = g_strdup_printf("%d x %d", w, h);
928 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
931 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
938 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
939 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
945 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
946 g_signal_connect(G_OBJECT(combo), "changed",
947 G_CALLBACK(thumb_size_menu_cb), NULL);
949 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
950 gtk_widget_show(combo);
953 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
955 auto option = static_cast<gint *>(data);
957 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
961 *option = PR_STEREO_NONE;
964 *option = PR_STEREO_ANAGLYPH_RC;
967 *option = PR_STEREO_ANAGLYPH_GM;
970 *option = PR_STEREO_ANAGLYPH_YB;
973 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
976 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
979 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
982 *option = PR_STEREO_ANAGLYPH_DB_RC;
985 *option = PR_STEREO_ANAGLYPH_DB_GM;
988 *option = PR_STEREO_ANAGLYPH_DB_YB;
991 *option = PR_STEREO_HORIZ;
994 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
997 *option = PR_STEREO_VERT;
1000 *option = PR_STEREO_VERT | PR_STEREO_HALF;
1003 *option = PR_STEREO_FIXED;
1008 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1009 gint option, gint *option_c, gboolean add_fixed)
1016 pref_table_label(table, column, row, text, GTK_ALIGN_START);
1018 combo = gtk_combo_box_text_new();
1020 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
1022 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
1023 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
1024 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
1025 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
1026 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
1027 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
1028 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
1029 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
1030 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
1031 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
1032 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
1033 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
1034 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
1035 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
1036 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
1037 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
1038 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
1039 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
1041 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
1042 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
1043 if (option & PR_STEREO_HORIZ)
1046 if (option & PR_STEREO_HALF) current = 11;
1049 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
1050 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
1051 if (option & PR_STEREO_VERT)
1054 if (option & PR_STEREO_HALF) current = 13;
1059 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
1060 if (option & PR_STEREO_FIXED) current = 14;
1063 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1065 g_signal_connect(G_OBJECT(combo), "changed",
1066 G_CALLBACK(stereo_mode_menu_cb), option_c);
1068 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
1069 gtk_widget_show(combo);
1072 static void video_menu_cb(GtkWidget *combo, gpointer data)
1074 auto option = static_cast<gchar **>(data);
1076 auto ed = static_cast<EditorDescription *>(g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo))));
1080 static void video_menu_populate(gpointer data, gpointer user_data)
1082 auto combo = static_cast<GtkWidget *>(user_data);
1083 auto ed = static_cast<EditorDescription *>(data);
1085 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1088 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1089 gchar *option, gchar **option_c)
1093 /* use lists since they are sorted */
1094 GList *eds = editor_list_get();
1098 pref_table_label(table, column, row, text, GTK_ALIGN_START);
1100 combo = gtk_combo_box_text_new();
1101 g_list_foreach(eds,video_menu_populate,combo);
1102 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1104 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1106 g_signal_connect(G_OBJECT(combo), "changed",
1107 G_CALLBACK(video_menu_cb), option_c);
1109 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
1110 gtk_widget_show(combo);
1113 static void filter_store_populate()
1117 if (!filter_store) return;
1119 gtk_list_store_clear(filter_store);
1121 work = filter_get_list();
1127 fe = static_cast<FilterEntry *>(work->data);
1130 gtk_list_store_append(filter_store, &iter);
1131 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1135 static void filter_store_ext_edit_cb(GtkCellRendererText *, gchar *path_str, gchar *new_text, gpointer data)
1137 auto model = static_cast<GtkWidget *>(data);
1138 auto fe = static_cast<FilterEntry *>(data);
1142 if (!new_text || strlen(new_text) < 1) return;
1144 tpath = gtk_tree_path_new_from_string(path_str);
1145 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1146 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1148 g_free(fe->extensions);
1149 fe->extensions = g_strdup(new_text);
1151 gtk_tree_path_free(tpath);
1155 static void filter_store_class_edit_cb(GtkCellRendererText *, gchar *path_str, gchar *new_text, gpointer data)
1157 auto model = static_cast<GtkWidget *>(data);
1158 auto fe = static_cast<FilterEntry *>(data);
1163 if (!new_text || !new_text[0]) return;
1165 tpath = gtk_tree_path_new_from_string(path_str);
1166 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1167 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1169 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1171 if (strcmp(new_text, _(format_class_list[i])) == 0)
1173 fe->file_class = static_cast<FileFormatClass>(i);
1178 gtk_tree_path_free(tpath);
1182 static void filter_store_desc_edit_cb(GtkCellRendererText *, gchar *path_str, gchar *new_text, gpointer data)
1184 auto model = static_cast<GtkWidget *>(data);
1189 if (!new_text || !new_text[0]) return;
1191 tpath = gtk_tree_path_new_from_string(path_str);
1192 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1193 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1195 g_free(fe->description);
1196 fe->description = g_strdup(new_text);
1198 gtk_tree_path_free(tpath);
1201 static void filter_store_enable_cb(GtkCellRendererToggle *, gchar *path_str, gpointer data)
1203 auto model = static_cast<GtkWidget *>(data);
1208 tpath = gtk_tree_path_new_from_string(path_str);
1209 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1210 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1212 fe->enabled = !fe->enabled;
1214 gtk_tree_path_free(tpath);
1218 static void filter_store_writable_cb(GtkCellRendererToggle *, gchar *path_str, gpointer data)
1220 auto model = static_cast<GtkWidget *>(data);
1225 tpath = gtk_tree_path_new_from_string(path_str);
1226 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1227 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1229 fe->writable = !fe->writable;
1230 if (fe->writable) fe->allow_sidecar = FALSE;
1232 gtk_tree_path_free(tpath);
1236 static void filter_store_sidecar_cb(GtkCellRendererToggle *, gchar *path_str, gpointer data)
1238 auto model = static_cast<GtkWidget *>(data);
1243 tpath = gtk_tree_path_new_from_string(path_str);
1244 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1245 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1247 fe->allow_sidecar = !fe->allow_sidecar;
1248 if (fe->allow_sidecar) fe->writable = FALSE;
1250 gtk_tree_path_free(tpath);
1254 static void filter_set_func(GtkTreeViewColumn *, GtkCellRenderer *cell,
1255 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1259 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1261 switch (GPOINTER_TO_INT(data))
1264 g_object_set(GTK_CELL_RENDERER(cell),
1265 "active", fe->enabled, NULL);
1268 g_object_set(GTK_CELL_RENDERER(cell),
1269 "text", fe->extensions, NULL);
1271 case FE_DESCRIPTION:
1272 g_object_set(GTK_CELL_RENDERER(cell),
1273 "text", fe->description, NULL);
1276 g_object_set(GTK_CELL_RENDERER(cell),
1277 "text", _(format_class_list[fe->file_class]), NULL);
1280 g_object_set(GTK_CELL_RENDERER(cell),
1281 "active", fe->writable, NULL);
1283 case FE_ALLOW_SIDECAR:
1284 g_object_set(GTK_CELL_RENDERER(cell),
1285 "active", fe->allow_sidecar, NULL);
1292 static gboolean filter_add_scroll(gpointer data)
1296 GtkCellRenderer *cell;
1297 GtkTreeViewColumn *column;
1300 GtkTreeModel *store;
1302 FilterEntry *filter;
1304 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), nullptr);
1305 path = gtk_tree_path_new_from_indices(rows-1, -1);
1307 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1309 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1310 cell = static_cast<GtkCellRenderer *>(g_list_last(list_cells)->data);
1312 store = gtk_tree_view_get_model(GTK_TREE_VIEW(data));
1313 valid = gtk_tree_model_get_iter_first(store, &iter);
1317 gtk_tree_model_get(store, &iter, 0, &filter, -1);
1319 if (g_strcmp0(filter->extensions, ".new") == 0)
1321 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
1325 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1328 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1329 path, column, FALSE, 0.0, 0.0 );
1330 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1331 path, column, cell, TRUE);
1333 gtk_tree_path_free(path);
1334 g_list_free(list_cells);
1336 return(G_SOURCE_REMOVE);
1339 static void filter_add_cb(GtkWidget *, gpointer data)
1341 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1342 filter_store_populate();
1344 g_idle_add(static_cast<GSourceFunc>(filter_add_scroll), data);
1347 static void filter_remove_cb(GtkWidget *, gpointer data)
1349 auto filter_view = static_cast<GtkWidget *>(data);
1350 GtkTreeSelection *selection;
1354 if (!filter_store) return;
1355 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1356 if (!gtk_tree_selection_get_selected(selection, nullptr, &iter)) return;
1357 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1360 filter_remove_entry(fe);
1362 filter_store_populate();
1365 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1369 GtkTreeViewColumn *column;
1371 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1372 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1373 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1375 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1379 gtk_tree_path_free(path);
1381 return(G_SOURCE_REMOVE);
1384 static void filter_default_ok_cb(GenericDialog *gd, gpointer)
1387 filter_add_defaults();
1389 filter_store_populate();
1391 g_idle_add(reinterpret_cast<GSourceFunc>(filter_default_ok_scroll), gd->data);
1394 static void dummy_cancel_cb(GenericDialog *, gpointer)
1396 /* no op, only so cancel button appears */
1399 static void filter_default_cb(GtkWidget *widget, gpointer data)
1403 gd = generic_dialog_new(_("Reset filters"),
1404 "reset_filter", widget, TRUE,
1405 dummy_cancel_cb, data);
1406 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Reset filters"),
1407 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1408 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", filter_default_ok_cb, TRUE);
1409 gtk_widget_show(gd->dialog);
1412 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1414 auto frame = static_cast<GtkWidget *>(data);
1416 gtk_widget_set_sensitive(frame,
1417 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1420 static void safe_delete_view_cb(GtkWidget *, gpointer)
1422 layout_set_path(nullptr, gq_gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1425 static void safe_delete_clear_ok_cb(GenericDialog *, gpointer)
1427 file_util_trash_clear();
1430 static void safe_delete_clear_cb(GtkWidget *widget, gpointer)
1434 gd = generic_dialog_new(_("Clear trash"),
1435 "clear_trash", widget, TRUE,
1436 dummy_cancel_cb, nullptr);
1437 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Clear trash"),
1438 _("This will remove the trash contents."), FALSE);
1439 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", safe_delete_clear_ok_cb, TRUE);
1440 entry = gtk_entry_new();
1441 gtk_widget_set_can_focus(entry, FALSE);
1442 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1443 if (options->file_ops.safe_delete_path) gq_gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1444 gq_gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1445 gtk_widget_show(entry);
1446 gtk_widget_show(gd->dialog);
1449 static void image_overlay_template_view_changed_cb(GtkWidget *, gpointer data)
1451 GtkWidget *pTextView;
1452 GtkTextBuffer *pTextBuffer;
1456 pTextView = GTK_WIDGET(data);
1458 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1459 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1460 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1462 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1463 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1466 static void image_overlay_default_template_ok_cb(GenericDialog *, gpointer data)
1468 auto text_view = static_cast<GtkTextView *>(data);
1469 GtkTextBuffer *buffer;
1471 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1472 if (!configwindow) return;
1474 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1475 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1478 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1482 gd = generic_dialog_new(_("Reset image overlay template string"),
1483 "reset_image_overlay_template_string", widget, TRUE,
1484 dummy_cancel_cb, data);
1485 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Reset image overlay template string"),
1486 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1487 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", image_overlay_default_template_ok_cb, TRUE);
1488 gtk_widget_show(gd->dialog);
1491 static void image_overlay_help_cb(GtkWidget *, gpointer)
1493 help_window_show("GuideOptionsOSD.html");
1496 static void font_activated_cb(GtkFontChooser *widget, gchar *fontname, gpointer)
1498 g_free(c_options->image_overlay.font);
1499 c_options->image_overlay.font = g_strdup(fontname);
1502 gq_gtk_widget_destroy(GTK_WIDGET(widget));
1505 static void font_response_cb(GtkDialog *dialog, gint response_id, gpointer)
1509 g_free(c_options->image_overlay.font);
1510 c_options->image_overlay.font = g_strdup(options->image_overlay.font);
1512 if (response_id == GTK_RESPONSE_OK)
1514 font = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(dialog));
1515 g_free(c_options->image_overlay.font);
1516 c_options->image_overlay.font = g_strdup(font);
1520 gq_gtk_widget_destroy(GTK_WIDGET(dialog));
1523 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer)
1527 dialog = gtk_font_chooser_dialog_new(_("Image Overlay Font"), GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1528 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1529 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1531 g_signal_connect(dialog, "font-activated", G_CALLBACK(font_activated_cb), nullptr);
1532 g_signal_connect(dialog, "response", G_CALLBACK(font_response_cb), nullptr);
1534 gtk_widget_show(dialog);
1537 static void text_color_activated_cb(GtkColorChooser *chooser, GdkRGBA *color, gpointer)
1539 c_options->image_overlay.text_red = color->red * 255;
1540 c_options->image_overlay.text_green = color->green * 255;
1541 c_options->image_overlay.text_blue = color->blue * 255;
1542 c_options->image_overlay.text_alpha = color->alpha * 255;
1544 gq_gtk_widget_destroy(GTK_WIDGET(chooser));
1547 static void text_color_response_cb(GtkDialog *dialog, gint response_id, gpointer)
1551 c_options->image_overlay.text_red = options->image_overlay.text_red;
1552 c_options->image_overlay.text_green = options->image_overlay.text_green;
1553 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
1554 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
1556 if (response_id == GTK_RESPONSE_OK)
1558 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &color);
1559 c_options->image_overlay.text_red = color.red * 255;
1560 c_options->image_overlay.text_green = color.green * 255;
1561 c_options->image_overlay.text_blue = color.blue * 255;
1562 c_options->image_overlay.text_alpha = color.alpha * 255;
1565 gq_gtk_widget_destroy(GTK_WIDGET(dialog));
1568 static void image_overlay_set_text_color_cb(GtkWidget *widget, gpointer)
1573 dialog = gtk_color_chooser_dialog_new(_("Image Overlay Text Color"), GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1574 color.red = options->image_overlay.text_red;
1575 color.green = options->image_overlay.text_green;
1576 color.blue = options->image_overlay.text_blue;
1577 color.alpha = options->image_overlay.text_alpha;
1578 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &color);
1579 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1581 g_signal_connect(dialog, "color-activated", G_CALLBACK(text_color_activated_cb), nullptr);
1582 g_signal_connect(dialog, "response", G_CALLBACK(text_color_response_cb), nullptr);
1584 gtk_widget_show(dialog);
1587 static void bg_color_activated_cb(GtkColorChooser *chooser, GdkRGBA *color, gpointer)
1589 c_options->image_overlay.background_red = color->red * 255;
1590 c_options->image_overlay.background_green = color->green * 255;
1591 c_options->image_overlay.background_blue = color->blue * 255;
1592 c_options->image_overlay.background_alpha = color->alpha * 255;
1594 gq_gtk_widget_destroy(GTK_WIDGET(chooser));
1597 static void bg_color_response_cb(GtkDialog *dialog, gint response_id, gpointer)
1601 c_options->image_overlay.background_red = options->image_overlay.background_red;
1602 c_options->image_overlay.background_green = options->image_overlay.background_green;
1603 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
1604 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
1606 if (response_id == GTK_RESPONSE_OK)
1608 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &color);
1609 c_options->image_overlay.background_red = color.red * 255;
1610 c_options->image_overlay.background_green = color.green * 255;
1611 c_options->image_overlay.background_blue = color.blue * 255;
1612 c_options->image_overlay.background_alpha = color.alpha * 255;
1614 gq_gtk_widget_destroy(GTK_WIDGET(dialog));
1617 static void image_overlay_set_background_color_cb(GtkWidget *widget, gpointer)
1622 dialog = gtk_color_chooser_dialog_new(_("Image Overlay Background Color"), GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1623 color.red = options->image_overlay.background_red;
1624 color.green = options->image_overlay.background_green;
1625 color.blue = options->image_overlay.background_blue;
1626 color.alpha = options->image_overlay.background_alpha;
1627 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &color);
1628 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1630 g_signal_connect(dialog, "color-activated", G_CALLBACK(bg_color_activated_cb), nullptr);
1631 g_signal_connect(dialog, "response", G_CALLBACK(bg_color_response_cb), nullptr);
1633 gtk_widget_show(dialog);
1636 static void accel_store_populate()
1642 const gchar *accel_path;
1643 const gchar *icon_name;
1647 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1649 gtk_tree_store_clear(accel_store);
1650 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 */
1652 g_assert(lw && lw->ui_manager);
1653 groups = gq_gtk_ui_manager_get_action_groups(lw->ui_manager);
1656 actions = gq_gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1659 action = GTK_ACTION(actions->data);
1660 accel_path = gq_gtk_action_get_accel_path(action);
1661 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1667 g_object_get(action,
1668 "tooltip", &tooltip,
1672 if (pango_parse_markup(label, -1, '_', nullptr, &label2, nullptr, nullptr) && label2)
1678 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1679 icon_name = gq_gtk_action_get_icon_name(action);
1683 gtk_tree_store_append(accel_store, &iter, nullptr);
1684 gtk_tree_store_set(accel_store, &iter,
1687 AE_TOOLTIP, tooltip ? tooltip : "",
1688 AE_ACCEL, accel_path,
1697 actions = actions->next;
1700 groups = groups->next;
1704 static void accel_store_cleared_cb(GtkCellRendererAccel *, gchar *, gpointer)
1709 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *, GtkTreeIter *iter, gpointer data)
1711 auto accel1 = static_cast<gchar *>(data);
1716 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1718 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1719 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1721 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1723 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1724 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1733 static void accel_store_edited_cb(GtkCellRendererAccel *, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint, gpointer)
1735 auto model = reinterpret_cast<GtkTreeModel *>(accel_store);
1739 GtkAccelKey old_key;
1741 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1743 gtk_tree_model_get_iter(model, &iter, path);
1744 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1746 /* test if the accelerator can be stored without conflicts*/
1747 gtk_accel_map_lookup_entry(accel_path, &old_key);
1749 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1750 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1751 gtk_accel_map_lookup_entry(accel_path, &key);
1753 /* restore the original for now, the key will be really changed when the changes are confirmed */
1754 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1756 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1757 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1759 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1760 gtk_tree_path_free(path);
1764 static gboolean accel_default_scroll(GtkTreeView *data)
1768 GtkTreeViewColumn *column;
1770 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1771 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1772 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1774 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1778 gtk_tree_path_free(path);
1780 return(G_SOURCE_REMOVE);
1783 static void accel_default_cb(GtkWidget *, gpointer data)
1785 accel_store_populate();
1787 g_idle_add(reinterpret_cast<GSourceFunc>(accel_default_scroll), data);
1790 void accel_clear_selection(GtkTreeModel *, GtkTreePath *, GtkTreeIter *iter, gpointer)
1792 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1795 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *, GtkTreeIter *iter, gpointer)
1801 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1802 gtk_accel_map_lookup_entry(accel_path, &key);
1803 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1805 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1807 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1812 static void accel_clear_cb(GtkWidget *, gpointer data)
1814 GtkTreeSelection *selection;
1816 if (!accel_store) return;
1817 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1818 gtk_tree_selection_selected_foreach(selection, &accel_clear_selection, nullptr);
1821 static void accel_reset_cb(GtkWidget *, gpointer data)
1823 GtkTreeSelection *selection;
1825 if (!accel_store) return;
1826 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1827 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, nullptr);
1832 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1836 GtkWidget *scrolled;
1837 GtkWidget *viewport;
1839 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
1840 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1841 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1842 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1843 label = gtk_label_new(title);
1844 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1845 gtk_widget_show(scrolled);
1847 viewport = gtk_viewport_new(nullptr, nullptr);
1848 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1849 gq_gtk_container_add(GTK_WIDGET(scrolled), viewport);
1850 gtk_widget_show(viewport);
1852 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
1853 gq_gtk_container_add(GTK_WIDGET(viewport), vbox);
1854 gtk_widget_show(vbox);
1859 static void cache_standard_cb(GtkWidget *widget, gpointer)
1861 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1863 c_options->thumbnails.spec_standard =TRUE;
1864 c_options->thumbnails.cache_into_dirs = FALSE;
1868 static void cache_geeqie_cb(GtkWidget *widget, gpointer)
1870 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1872 c_options->thumbnails.spec_standard =FALSE;
1873 c_options->thumbnails.cache_into_dirs = FALSE;
1877 static void cache_local_cb(GtkWidget *widget, gpointer)
1879 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1881 c_options->thumbnails.cache_into_dirs = TRUE;
1882 c_options->thumbnails.spec_standard =FALSE;
1886 static void help_search_engine_entry_icon_cb(GtkEntry *, GtkEntryIconPosition pos, GdkEvent *, gpointer userdata)
1888 if (pos == GTK_ENTRY_ICON_PRIMARY)
1890 gq_gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1894 gq_gtk_entry_set_text(GTK_ENTRY(userdata), "");
1898 static void star_rating_star_icon_cb(GtkEntry *, GtkEntryIconPosition pos, GdkEvent *, gpointer userdata)
1900 gchar *rating_symbol;
1902 if (pos == GTK_ENTRY_ICON_PRIMARY)
1904 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1905 gq_gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1906 g_free(rating_symbol);
1910 gq_gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1911 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1912 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1916 static void star_rating_rejected_icon_cb(GtkEntry *, GtkEntryIconPosition pos, GdkEvent *, gpointer userdata)
1918 gchar *rating_symbol;
1920 if (pos == GTK_ENTRY_ICON_PRIMARY)
1922 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1923 gq_gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1924 g_free(rating_symbol);
1928 gq_gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1929 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1930 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1934 static guint star_rating_symbol_test(GtkWidget *, gpointer data)
1936 auto hbox = static_cast<GtkContainer *>(data);
1937 GString *str = g_string_new(nullptr);
1938 GtkEntry *hex_code_entry;
1939 gchar *hex_code_full;
1942 guint64 hex_value = 0;
1944 list = gtk_container_get_children(hbox);
1946 hex_code_entry = static_cast<GtkEntry *>(g_list_nth_data(list, 2));
1947 hex_code_full = g_strdup(gq_gtk_entry_get_text(hex_code_entry));
1949 hex_code = g_strsplit(hex_code_full, "+", 2);
1950 if (hex_code[0] && hex_code[1])
1952 hex_value = strtoull(hex_code[1], nullptr, 16);
1954 if (!hex_value || hex_value > 0x10FFFF)
1956 hex_value = 0x003F; // Unicode 'Question Mark'
1958 str = g_string_append_unichar(str, static_cast<gunichar>(hex_value));
1959 gtk_label_set_text(static_cast<GtkLabel *>(g_list_nth_data(list, 1)), str->str);
1961 g_strfreev(hex_code);
1962 g_string_free(str, TRUE);
1963 g_free(hex_code_full);
1968 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1970 guint64 star_symbol;
1972 star_symbol = star_rating_symbol_test(widget, data);
1973 c_options->star_rating.star = star_symbol;
1976 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1978 guint64 rejected_symbol;
1980 rejected_symbol = star_rating_symbol_test(widget, data);
1981 c_options->star_rating.rejected = rejected_symbol;
1984 /* general options tab */
1985 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1989 GCancellable *cancellable;
1991 GtkWidget *progress;
1993 GFile *timezone_database_gq;
1994 gchar *timezone_database_user;
1997 static void config_tab_general(GtkWidget *notebook)
2002 GtkWidget *group_frame;
2003 GtkWidget *subgroup;
2005 GtkWidget *ct_button;
2012 GtkWidget *star_rating_entry;
2014 gchar *rating_symbol;
2017 gchar *download_locn;
2018 GNetworkMonitor *net_mon;
2019 GSocketConnectable *tz_org;
2020 gboolean internet_available = FALSE;
2023 vbox = scrolled_notebook_page(notebook, _("General"));
2025 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
2027 table = pref_table_new(group, 2, 2, FALSE, FALSE);
2028 add_thumb_size_menu(table, 0, 0, _("Size:"));
2029 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
2031 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2032 pref_label_new(hbox, _("Custom size: "));
2033 pref_spin_new_int(hbox, _("Width:"), nullptr, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
2034 pref_spin_new_int(hbox, _("Height:"), nullptr, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
2036 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
2037 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
2039 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2040 pref_checkbox_link_sensitivity(ct_button, subgroup);
2042 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
2043 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
2044 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
2045 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2046 button = pref_radiobutton_new(group_frame, nullptr, get_thumbnails_cache_dir(),
2047 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2048 G_CALLBACK(cache_geeqie_cb), nullptr);
2050 group_frame = pref_frame_new(subgroup, TRUE,
2051 _("Store thumbnails local to image folder (non-standard)"),
2052 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2053 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
2054 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
2055 G_CALLBACK(cache_local_cb), nullptr);
2057 group_frame = pref_frame_new(subgroup, TRUE,
2058 _("Use standard thumbnail style and cache, shared with other applications"),
2059 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2060 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
2061 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2062 G_CALLBACK(cache_standard_cb), nullptr);
2064 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
2065 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
2067 pref_checkbox_new_int(group, _("Thumbnail color management"),
2068 options->thumbnails.use_color_management, &c_options->thumbnails.use_color_management);
2070 spin = pref_spin_new_int(group, _("Collection preview:"), nullptr,
2072 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
2073 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
2075 #if HAVE_FFMPEGTHUMBNAILER_METADATA
2076 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
2077 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
2080 pref_spacer(group, PREF_PAD_GROUP);
2082 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
2084 c_options->star_rating.star = options->star_rating.star;
2085 c_options->star_rating.rejected = options->star_rating.rejected;
2087 str = g_string_new(nullptr);
2088 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2089 pref_label_new(hbox, _("Star character: "));
2090 str = g_string_append_unichar(str, options->star_rating.star);
2091 pref_label_new(hbox, g_strdup(str->str));
2092 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
2093 star_rating_entry = gtk_entry_new();
2094 gq_gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2095 gq_gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2096 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2097 gtk_widget_show(star_rating_entry);
2098 button = pref_button_new(nullptr, nullptr, _("Set"),
2099 G_CALLBACK(star_rating_star_test_cb), hbox);
2100 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2101 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2102 gtk_widget_show(button);
2103 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."));
2104 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2105 GTK_ENTRY_ICON_SECONDARY, GQ_ICON_CLEAR);
2106 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2107 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2108 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2109 GTK_ENTRY_ICON_PRIMARY, GQ_ICON_REVERT);
2110 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2111 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2112 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2113 G_CALLBACK(star_rating_star_icon_cb),
2116 g_string_free(str, TRUE);
2117 g_free(rating_symbol);
2119 str = g_string_new(nullptr);
2120 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2121 pref_label_new(hbox, _("Rejected character: "));
2122 str = g_string_append_unichar(str, options->star_rating.rejected);
2123 pref_label_new(hbox, g_strdup(str->str));
2124 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2125 star_rating_entry = gtk_entry_new();
2126 gq_gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2127 gq_gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2128 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2129 gtk_widget_show(star_rating_entry);
2130 button = pref_button_new(nullptr, nullptr, _("Set"),
2131 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2132 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2133 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2134 gtk_widget_show(button);
2135 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."));
2136 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2137 GTK_ENTRY_ICON_SECONDARY, GQ_ICON_CLEAR);
2138 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2139 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2140 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2141 GTK_ENTRY_ICON_PRIMARY, GQ_ICON_REVERT);
2142 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2143 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2144 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2145 G_CALLBACK(star_rating_rejected_icon_cb),
2148 g_string_free(str, TRUE);
2149 g_free(rating_symbol);
2151 pref_spacer(group, PREF_PAD_GROUP);
2153 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2155 c_options->slideshow.delay = options->slideshow.delay;
2156 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2157 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2158 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2159 seconds = static_cast<gdouble>(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2160 SLIDESHOW_SUBSECOND_PRECISION;
2162 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2164 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), nullptr,
2166 options->slideshow.delay ? hours : 0.0,
2167 G_CALLBACK(slideshow_delay_hours_cb), nullptr);
2168 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2169 spin = pref_spin_new(hbox, ":" , nullptr,
2171 options->slideshow.delay ? minutes: 0.0,
2172 G_CALLBACK(slideshow_delay_minutes_cb), nullptr);
2173 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2174 spin = pref_spin_new(hbox, ":", nullptr,
2175 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2176 options->slideshow.delay ? seconds : 10.0,
2177 G_CALLBACK(slideshow_delay_seconds_cb), nullptr);
2178 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2180 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2181 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2183 pref_spacer(group, PREF_PAD_GROUP);
2185 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2187 pref_spin_new_int(group, _("Decoded image cache size (MiB):"), nullptr,
2188 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2189 pref_checkbox_new_int(group, _("Preload next image"),
2190 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2192 pref_checkbox_new_int(group, _("Refresh on file change"),
2193 options->update_on_time_change, &c_options->update_on_time_change);
2196 pref_spacer(group, PREF_PAD_GROUP);
2198 group = pref_group_new(vbox, FALSE, _("Menu style"), GTK_ORIENTATION_VERTICAL);
2200 pref_checkbox_new_int(group, _("☰ style menu button (NOTE! Geeqie must be restarted for change to take effect)"),
2201 options->hamburger_menu, &c_options->hamburger_menu);
2202 gtk_widget_set_tooltip_text(group, _("Use a ☰ style menu button instead of the classic style across the top of the frame"));
2204 pref_spacer(group, PREF_PAD_GROUP);
2206 group = pref_group_new(vbox, FALSE, _("Expand toolbar"), GTK_ORIENTATION_VERTICAL);
2208 pref_checkbox_new_int(group, _("Expand menu/toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2209 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2210 gtk_widget_set_tooltip_text(group, _("Expand the menu/toolbar to the full width of the window"));
2212 pref_spacer(group, PREF_PAD_GROUP);
2214 group = pref_group_new(vbox, FALSE, _("Hide Selectable Bars"), GTK_ORIENTATION_VERTICAL);
2216 pref_checkbox_new_int(group, _("Menu bar"),
2217 options->selectable_bars.menu_bar, &c_options->selectable_bars.menu_bar);
2219 pref_checkbox_new_int(group, _("Tool bar"),
2220 options->selectable_bars.tool_bar, &c_options->selectable_bars.tool_bar);
2222 pref_checkbox_new_int(group, _("Status bar"),
2223 options->selectable_bars.status_bar, &c_options->selectable_bars.status_bar);
2224 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"));
2226 pref_spacer(group, PREF_PAD_GROUP);
2228 if ((g_getenv("APPDIR") && strstr(g_getenv("APPDIR"), "/tmp/.mount_Geeqie")) || (g_strstr_len(gq_executable_path, -1, "squashfs-root")))
2230 group = pref_group_new(vbox, FALSE, _("AppImage updates notifications"), GTK_ORIENTATION_VERTICAL);
2231 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2232 pref_checkbox_new_int(group, _("Enable"), options->appimage_notifications, &c_options->appimage_notifications);
2233 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"));
2235 pref_spacer(group, PREF_PAD_GROUP);
2239 net_mon = g_network_monitor_get_default();
2240 tz_org = g_network_address_parse_uri(TIMEZONE_DATABASE_WEB, 80, nullptr);
2243 internet_available = g_network_monitor_can_reach(net_mon, tz_org, nullptr, nullptr);
2244 g_object_unref(tz_org);
2247 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2248 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2250 if (!internet_available)
2252 gtk_widget_set_sensitive(group, FALSE);
2255 tz = g_new0(TZData, 1);
2257 path = path_from_utf8(TIMEZONE_DATABASE_WEB);
2258 basename = g_path_get_basename(path);
2259 tz->timezone_database_user = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
2263 if (isfile(tz->timezone_database_user))
2265 button = pref_button_new(GTK_WIDGET(hbox), nullptr, _("Update"), G_CALLBACK(timezone_database_install_cb), tz);
2269 button = pref_button_new(GTK_WIDGET(hbox), nullptr, _("Install"), G_CALLBACK(timezone_database_install_cb), tz);
2272 download_locn = g_strconcat(_("Download database from: "), TIMEZONE_DATABASE_WEB, NULL);
2273 pref_label_new(GTK_WIDGET(hbox), download_locn);
2274 g_free(download_locn);
2276 if (!internet_available)
2278 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"));
2282 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"));
2284 gtk_widget_show(button);
2286 pref_spacer(group, PREF_PAD_GROUP);
2288 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2290 help_search_engine_entry = gtk_entry_new();
2291 gq_gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2292 gq_gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2293 gtk_widget_show(help_search_engine_entry);
2295 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"));
2297 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(help_search_engine_entry),
2298 GTK_ENTRY_ICON_SECONDARY, GQ_ICON_CLEAR);
2299 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2300 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2301 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(help_search_engine_entry),
2302 GTK_ENTRY_ICON_PRIMARY, GQ_ICON_REVERT);
2303 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2304 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2305 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2306 G_CALLBACK(help_search_engine_entry_icon_cb),
2307 help_search_engine_entry);
2311 static void config_tab_image(GtkWidget *notebook)
2316 GtkWidget *ct_button;
2317 GtkWidget *enlargement_button;
2321 vbox = scrolled_notebook_page(notebook, _("Image"));
2323 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2325 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2326 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2328 pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2329 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2331 c_options->image.zoom_increment = options->image.zoom_increment;
2332 spin = pref_spin_new(group, _("Zoom increment:"), nullptr,
2333 0.01, 4.0, 0.01, 2, static_cast<gdouble>(options->image.zoom_increment) / 100.0,
2334 G_CALLBACK(zoom_increment_cb), nullptr);
2335 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2337 c_options->image.zoom_style = options->image.zoom_style;
2338 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2339 add_zoom_style_selection_menu(table, 0, 0, _("Zoom style:"), options->image.zoom_style, &c_options->image.zoom_style);
2341 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2343 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2344 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2345 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2346 spin = pref_spin_new_int(hbox, nullptr, nullptr,
2348 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2349 pref_checkbox_link_sensitivity(enlargement_button, spin);
2350 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."));
2352 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2353 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (%% of actual window):"),
2354 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2355 spin = pref_spin_new_int(hbox, nullptr, nullptr,
2357 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2358 pref_checkbox_link_sensitivity(ct_button, spin);
2359 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."));
2361 group = pref_group_new(vbox, FALSE, _("Tile size"), GTK_ORIENTATION_VERTICAL);
2363 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2364 spin = pref_spin_new_int(hbox, _("Pixels"), _("(Requires restart)"),
2366 options->image.tile_size, &c_options->image.tile_size);
2367 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."));
2369 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2371 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2372 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2374 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2375 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2377 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2378 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2380 c_options->image.border_color = options->image.border_color;
2382 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2383 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2385 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2386 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2388 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2389 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2394 static void save_default_window_layout_cb(GtkWidget *, gpointer)
2396 LayoutWindow *lw = nullptr;
2397 gchar *default_path;
2400 /* Get current lw */
2403 tmp_id = lw->options.id;
2404 lw->options.id = g_strdup("");
2406 default_path = g_build_filename(get_rc_dir(), DEFAULT_WINDOW_LAYOUT, NULL);
2407 save_default_layout_options_to_file(default_path, options, lw);
2408 g_free(lw->options.id);
2409 lw->options.id = tmp_id;
2410 g_free(default_path);
2413 static gboolean popover_cb(gpointer data)
2415 auto popover = static_cast<GtkPopover *>(data);
2417 gtk_popover_popdown(popover);
2422 static void default_layout_changed_cb(GtkWidget *, GtkPopover *popover)
2424 gtk_popover_popup(popover);
2426 g_timeout_add(2000, popover_cb, popover);
2429 static GtkWidget *create_popover(GtkWidget *parent, GtkWidget *child, GtkPositionType pos)
2433 popover = gtk_popover_new(parent);
2434 gtk_popover_set_position(GTK_POPOVER (popover), pos);
2435 gq_gtk_container_add(GTK_WIDGET(popover), child);
2436 gtk_container_set_border_width(GTK_CONTAINER (popover), 6);
2437 gtk_widget_show (child);
2442 static void config_tab_windows(GtkWidget *notebook)
2447 GtkWidget *subgroup;
2449 GtkWidget *checkbox;
2450 GtkWidget *ct_button;
2454 vbox = scrolled_notebook_page(notebook, _("Windows"));
2456 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2458 ct_button = pref_checkbox_new_int(group, _("Remember session"),
2459 options->save_window_positions, &c_options->save_window_positions);
2461 checkbox = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2462 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2463 pref_checkbox_link_sensitivity(ct_button, checkbox);
2465 checkbox = pref_checkbox_new_int(group, _("Remember window workspace"),
2466 options->save_window_workspace, &c_options->save_window_workspace);
2467 pref_checkbox_link_sensitivity(ct_button, checkbox);
2469 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2470 options->tools_restore_state, &c_options->tools_restore_state);
2472 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2473 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2475 widget = pref_checkbox_new_int(group, _("Hide window decorations"),
2476 options->hide_window_decorations, &c_options->hide_window_decorations);
2477 gtk_widget_set_tooltip_text(widget, _("Remove borders and title bar from windows. A restart of Geeqie is required for this feature to take effect on the main layout window"));
2479 pref_checkbox_new_int(group, _("Show window IDs"),
2480 options->show_window_ids, &c_options->show_window_ids);
2482 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2483 pref_label_new(subgroup, _("Use current layout for default: "));
2484 button = pref_button_new(subgroup, nullptr, _("Set"), G_CALLBACK(save_default_window_layout_cb), nullptr);
2488 popover = create_popover(button, gtk_label_new(_("Current window layout\nhas been set as default")), GTK_POS_TOP);
2489 gtk_popover_set_modal(GTK_POPOVER (popover), FALSE);
2490 g_signal_connect(button, "clicked", G_CALLBACK(default_layout_changed_cb), popover);
2492 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2494 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2495 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2497 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2498 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2499 options->image.limit_window_size, &c_options->image.limit_window_size);
2500 spin = pref_spin_new_int(hbox, nullptr, nullptr,
2502 options->image.max_window_size, &c_options->image.max_window_size);
2503 pref_checkbox_link_sensitivity(ct_button, spin);
2505 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2507 c_options->fullscreen.screen = options->fullscreen.screen;
2508 c_options->fullscreen.above = options->fullscreen.above;
2509 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2510 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2511 gtk_widget_show(hbox);
2513 pref_checkbox_new_int(group, _("Smooth image flip"),
2514 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2515 pref_checkbox_new_int(group, _("Disable screen saver"),
2516 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2519 static void config_tab_osd(GtkWidget *notebook)
2525 GtkWidget *image_overlay_template_view;
2526 GtkWidget *scrolled;
2527 GtkWidget *scrolled_pre_formatted;
2528 GtkTextBuffer *buffer;
2530 GtkWidget *subgroup;
2532 vbox = scrolled_notebook_page(notebook, _("OSD"));
2534 image_overlay_template_view = gtk_text_view_new();
2536 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2538 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2540 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2541 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2542 gq_gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2543 gtk_widget_show(scrolled_pre_formatted);
2544 gtk_widget_show(subgroup);
2546 pref_line(group, PREF_PAD_GAP);
2548 pref_label_new(group, _("Image overlay template"));
2550 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
2551 gtk_widget_set_size_request(scrolled, 200, 150);
2552 gq_gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2553 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2554 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2555 gq_gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2556 gtk_widget_show(scrolled);
2558 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2559 _("Extensive formatting options are shown in the Help file"));
2561 gq_gtk_container_add(GTK_WIDGET(scrolled), image_overlay_template_view);
2562 gtk_widget_show(image_overlay_template_view);
2564 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2566 button = pref_button_new(nullptr, GQ_ICON_SELECT_FONT, _("Font"),
2567 G_CALLBACK(image_overlay_set_font_cb), notebook);
2569 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2570 gtk_widget_show(button);
2572 button = pref_button_new(nullptr, GQ_ICON_SELECT_COLOR, _("Text"), G_CALLBACK(image_overlay_set_text_color_cb), nullptr);
2573 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2574 gtk_widget_show(button);
2576 button = pref_button_new(nullptr, GQ_ICON_SELECT_COLOR, _("Background"), G_CALLBACK(image_overlay_set_background_color_cb), nullptr);
2577 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2578 gtk_widget_show(button);
2579 image_overlay_set_text_colors();
2581 button = pref_button_new(nullptr, nullptr, _("Defaults"),
2582 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2583 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2584 gtk_widget_show(button);
2586 button = pref_button_new(nullptr, GQ_ICON_HELP, _("Help"),
2587 G_CALLBACK(image_overlay_help_cb), nullptr);
2588 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2589 gtk_widget_show(button);
2591 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2592 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2593 g_signal_connect(G_OBJECT(buffer), "changed",
2594 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2596 pref_line(group, PREF_PAD_GAP);
2598 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2599 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2600 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2601 gtk_widget_show(hbox);
2602 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2603 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2604 gtk_widget_show(label);
2605 pref_spacer(group,TRUE);
2607 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2608 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2609 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2610 gtk_widget_show(hbox);
2611 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2612 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2613 gtk_widget_show(label);
2614 pref_spacer(group,TRUE);
2616 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2617 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2618 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2619 gtk_widget_show(hbox);
2620 label = gtk_label_new(_("%path:39%"));
2621 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2622 gtk_widget_show(label);
2623 pref_spacer(group,TRUE);
2625 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2626 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2627 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2628 gtk_widget_show(hbox);
2629 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%"));
2630 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2631 gtk_widget_show(label);
2632 pref_spacer(group,TRUE);
2634 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2635 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2636 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2637 gtk_widget_show(hbox);
2638 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2639 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2640 gtk_widget_show(label);
2643 static GtkTreeModel *create_class_model()
2645 GtkListStore *model;
2649 /* create list store */
2650 model = gtk_list_store_new(1, G_TYPE_STRING);
2651 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2653 gtk_list_store_append(model, &iter);
2654 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2656 return GTK_TREE_MODEL (model);
2661 static gint filter_table_sort_cb(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data)
2663 gint n = GPOINTER_TO_INT(data);
2665 FilterEntry *filter_a;
2666 FilterEntry *filter_b;
2668 gtk_tree_model_get(model, a, 0, &filter_a, -1);
2669 gtk_tree_model_get(model, b, 0, &filter_b, -1);
2673 case FILETYPES_COLUMN_ENABLED:
2675 ret = filter_a->enabled - filter_b->enabled;
2678 case FILETYPES_COLUMN_FILTER:
2680 ret = g_utf8_collate(filter_a->extensions, filter_b->extensions);
2683 case FILETYPES_COLUMN_DESCRIPTION:
2685 ret = g_utf8_collate(filter_a->description, filter_b->description);
2688 case FILETYPES_COLUMN_CLASS:
2690 ret = g_strcmp0(format_class_list[filter_a->file_class], format_class_list[filter_b->file_class]);
2693 case FILETYPES_COLUMN_WRITABLE:
2695 ret = filter_a->writable - filter_b->writable;
2698 case FILETYPES_COLUMN_SIDECAR:
2700 ret = filter_a->allow_sidecar - filter_b->allow_sidecar;
2704 g_return_val_if_reached(0);
2710 static gboolean search_function_cb(GtkTreeModel *model, gint, const gchar *key, GtkTreeIter *iter, gpointer)
2713 gboolean ret = TRUE;
2715 gtk_tree_model_get(model, iter, 0, &fe, -1);
2717 if (g_strstr_len(fe->extensions, -1, key))
2725 static void config_tab_files(GtkWidget *notebook)
2732 GtkWidget *ct_button;
2733 GtkWidget *scrolled;
2734 GtkWidget *filter_view;
2735 GtkCellRenderer *renderer;
2736 GtkTreeSelection *selection;
2737 GtkTreeViewColumn *column;
2739 vbox = scrolled_notebook_page(notebook, _("File Filters"));
2741 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2743 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2744 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2745 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2746 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2747 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);
2748 pref_checkbox_new_int(group, _("Disable file extension checks"),
2749 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2751 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2752 options->file_filter.disable, &c_options->file_filter.disable);
2755 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2757 sidecar_ext_entry = gtk_entry_new();
2758 gq_gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2759 gq_gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2760 gtk_widget_show(sidecar_ext_entry);
2762 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2764 frame = pref_group_parent(group);
2765 g_signal_connect(G_OBJECT(ct_button), "toggled",
2766 G_CALLBACK(filter_disable_cb), frame);
2767 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2769 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
2770 gq_gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2771 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2772 gq_gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2773 gtk_widget_show(scrolled);
2775 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2776 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2777 g_object_unref(filter_store);
2778 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2779 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2781 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2783 column = gtk_tree_view_column_new();
2784 gtk_tree_view_column_set_title(column, _("Enabled"));
2785 gtk_tree_view_column_set_resizable(column, TRUE);
2787 renderer = gtk_cell_renderer_toggle_new();
2788 g_signal_connect(G_OBJECT(renderer), "toggled",
2789 G_CALLBACK(filter_store_enable_cb), filter_store);
2790 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2791 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2792 GINT_TO_POINTER(FE_ENABLE), nullptr);
2793 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);
2794 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_ENABLED);
2795 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2797 column = gtk_tree_view_column_new();
2798 gtk_tree_view_column_set_title(column, _("Filter"));
2799 gtk_tree_view_column_set_resizable(column, TRUE);
2800 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);
2801 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_FILTER);
2803 renderer = gtk_cell_renderer_text_new();
2804 g_signal_connect(G_OBJECT(renderer), "edited",
2805 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2806 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2807 g_object_set(G_OBJECT(renderer), "editable", static_cast<gboolean>TRUE, NULL);
2808 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2809 GINT_TO_POINTER(FE_EXTENSION), nullptr);
2810 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2812 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), TRUE);
2813 gtk_tree_view_set_search_column(GTK_TREE_VIEW(filter_view), FILETYPES_COLUMN_FILTER);
2814 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(filter_view), search_function_cb, nullptr, nullptr);
2816 column = gtk_tree_view_column_new();
2817 gtk_tree_view_column_set_title(column, _("Description"));
2818 gtk_tree_view_column_set_resizable(column, TRUE);
2819 gtk_tree_view_column_set_fixed_width(column, 200);
2820 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2822 renderer = gtk_cell_renderer_text_new();
2823 g_signal_connect(G_OBJECT(renderer), "edited",
2824 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2825 g_object_set(G_OBJECT(renderer), "editable", static_cast<gboolean>TRUE, NULL);
2826 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2827 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2828 GINT_TO_POINTER(FE_DESCRIPTION), nullptr);
2829 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2830 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);
2831 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_DESCRIPTION);
2833 column = gtk_tree_view_column_new();
2834 gtk_tree_view_column_set_title(column, _("Class"));
2835 gtk_tree_view_column_set_resizable(column, TRUE);
2836 renderer = gtk_cell_renderer_combo_new();
2837 g_object_set(G_OBJECT(renderer), "editable", static_cast<gboolean>TRUE,
2838 "model", create_class_model(),
2843 g_signal_connect(G_OBJECT(renderer), "edited",
2844 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2845 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2846 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2847 GINT_TO_POINTER(FE_CLASS), nullptr);
2848 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2849 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);
2850 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_CLASS);
2852 column = gtk_tree_view_column_new();
2853 gtk_tree_view_column_set_title(column, _("Writable"));
2854 gtk_tree_view_column_set_resizable(column, FALSE);
2855 renderer = gtk_cell_renderer_toggle_new();
2856 g_signal_connect(G_OBJECT(renderer), "toggled",
2857 G_CALLBACK(filter_store_writable_cb), filter_store);
2858 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2859 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2860 GINT_TO_POINTER(FE_WRITABLE), nullptr);
2861 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2862 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);
2863 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_WRITABLE);
2865 column = gtk_tree_view_column_new();
2866 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2867 gtk_tree_view_column_set_resizable(column, FALSE);
2868 renderer = gtk_cell_renderer_toggle_new();
2869 g_signal_connect(G_OBJECT(renderer), "toggled",
2870 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2871 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2872 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2873 GINT_TO_POINTER(FE_ALLOW_SIDECAR), nullptr);
2874 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2875 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);
2876 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_SIDECAR);
2878 filter_store_populate();
2879 gq_gtk_container_add(GTK_WIDGET(scrolled), filter_view);
2880 gtk_widget_show(filter_view);
2882 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2884 button = pref_button_new(nullptr, nullptr, _("Defaults"),
2885 G_CALLBACK(filter_default_cb), filter_view);
2886 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2887 gtk_widget_show(button);
2889 button = pref_button_new(nullptr, GQ_ICON_REMOVE, _("Remove"),
2890 G_CALLBACK(filter_remove_cb), filter_view);
2891 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2892 gtk_widget_show(button);
2894 button = pref_button_new(nullptr, GQ_ICON_ADD, _("Add"),
2895 G_CALLBACK(filter_add_cb), filter_view);
2896 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2897 gtk_widget_show(button);
2901 static void config_tab_metadata(GtkWidget *notebook)
2906 GtkWidget *ct_button;
2908 GtkWidget *tmp_widget;
2910 GtkWidget *text_label;
2912 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2915 group = pref_group_new(vbox, FALSE, _("Metadata writing sequence"), GTK_ORIENTATION_VERTICAL);
2917 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2919 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."));
2920 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2921 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2923 gtk_widget_set_tooltip_text(label, _("A flowchart of the sequence is shown in the Help file"));
2925 ct_button = pref_checkbox_new_int(group, "", options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2926 text_label = gtk_bin_get_child(GTK_BIN(ct_button));
2927 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"));
2928 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2930 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)"));
2931 gtk_widget_set_tooltip_markup(ct_button, markup);
2935 gtk_widget_set_sensitive(ct_button, FALSE);
2938 tmp_widget = pref_checkbox_new_int(group, "", options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2939 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2940 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)"));
2941 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2944 label = pref_label_new(group, "");
2945 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(), "/");
2946 gtk_label_set_markup (GTK_LABEL(label), markup);
2949 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2950 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2951 gtk_widget_set_margin_start(label, 22);
2952 pref_spacer(group, PREF_PAD_GROUP);
2954 group = pref_group_new(vbox, FALSE, _("Step 1 Options:"), GTK_ORIENTATION_VERTICAL);
2956 gtk_widget_set_sensitive(group, FALSE);
2959 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2960 pref_checkbox_link_sensitivity(ct_button, hbox);
2962 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);
2963 gtk_widget_set_tooltip_text(tmp_widget, _("A simplified conversion list is in the Help file"));
2965 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);
2967 pref_checkbox_new_int(hbox, _("Ask before writing to image files"), options->metadata.confirm_write, &c_options->metadata.confirm_write);
2969 tmp_widget= pref_checkbox_new_int(hbox, "", options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2970 gtk_widget_set_tooltip_text(tmp_widget, _("This file naming convention is used by Darktable"));
2971 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2972 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", ")");
2973 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2976 pref_spacer(group, PREF_PAD_GROUP);
2978 group = pref_group_new(vbox, FALSE, _("Steps 2 and 3 Option:"), GTK_ORIENTATION_VERTICAL);
2980 gtk_widget_set_sensitive(group, FALSE);
2983 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);
2985 pref_spacer(group, PREF_PAD_GROUP);
2987 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2988 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);
2989 gtk_widget_set_tooltip_text(tmp_widget, _("See the Help file for a list of the tags used"));
2991 tmp_widget = pref_checkbox_new_int(group, _("Permit Keywords to be case-sensitive"), options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2992 gtk_widget_set_tooltip_text(tmp_widget, _("When selected, 'Place' and 'place' are two different keywords"));
2994 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"), options->metadata.write_orientation, &c_options->metadata.write_orientation);
2995 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"));
2998 gtk_widget_set_sensitive(ct_button, FALSE);
3001 pref_spacer(group, PREF_PAD_GROUP);
3003 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
3005 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"), options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
3007 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3008 pref_checkbox_link_sensitivity(ct_button, hbox);
3010 pref_spin_new_int(hbox, _("Timeout (seconds):"), nullptr, 0, 900, 1, options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
3012 pref_checkbox_new_int(group, _("Write metadata on image change"), options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
3014 pref_checkbox_new_int(group, _("Write metadata on directory change"), options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
3016 pref_spacer(group, PREF_PAD_GROUP);
3019 group = pref_group_new(vbox, FALSE, _("Spelling checks"), GTK_ORIENTATION_VERTICAL);
3021 ct_button = pref_checkbox_new_int(group, _("Check spelling - Requires restart"), options->metadata.check_spelling, &c_options->metadata.check_spelling);
3022 gtk_widget_set_tooltip_text(ct_button, _("Spelling checks are performed on info sidebar panes Comment, Headline and Title"));
3025 pref_spacer(group, PREF_PAD_GROUP);
3027 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
3029 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"), options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
3030 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"));
3035 struct KeywordFindData
3042 GtkWidget *button_close;
3043 GtkWidget *button_stop;
3044 GtkWidget *button_start;
3045 GtkWidget *progress;
3053 guint idle_id; /* event source id */
3056 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
3058 GList *list_d = nullptr;
3059 GList *list_f = nullptr;
3063 filelist_read(dir_fd, &list_f, &list_d);
3067 filelist_read(dir_fd, &list_f, nullptr);
3070 list_f = filelist_filter(list_f, FALSE);
3071 list_d = filelist_filter(list_d, TRUE);
3073 kfd->list = g_list_concat(list_f, kfd->list);
3074 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
3077 static void keywords_find_reset(KeywordFindData *kfd)
3079 filelist_free(kfd->list);
3080 kfd->list = nullptr;
3082 filelist_free(kfd->list_dir);
3083 kfd->list_dir = nullptr;
3086 static void keywords_find_close_cb(GenericDialog *, gpointer data)
3088 auto kfd = static_cast<KeywordFindData *>(data);
3090 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
3092 keywords_find_reset(kfd);
3093 generic_dialog_close(kfd->gd);
3097 static void keywords_find_finish(KeywordFindData *kfd)
3099 keywords_find_reset(kfd);
3101 gq_gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
3102 gtk_spinner_stop(GTK_SPINNER(kfd->spinner));
3104 gtk_widget_set_sensitive(kfd->group, TRUE);
3105 gtk_widget_set_sensitive(kfd->button_start, TRUE);
3106 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3107 gtk_widget_set_sensitive(kfd->button_close, TRUE);
3110 static void keywords_find_stop_cb(GenericDialog *, gpointer data)
3112 auto kfd = static_cast<KeywordFindData *>(data);
3114 g_idle_remove_by_data(kfd);
3116 keywords_find_finish(kfd);
3119 static gboolean keywords_find_file(gpointer data)
3121 auto kfd = static_cast<KeywordFindData *>(data);
3123 GtkTextBuffer *buffer;
3131 fd = static_cast<FileData *>(kfd->list->data);
3132 kfd->list = g_list_remove(kfd->list, fd);
3134 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
3135 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3139 gtk_text_buffer_get_end_iter(buffer, &iter);
3140 tmp = g_strconcat(static_cast<const gchar *>(keywords->data), "\n", NULL);
3141 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3143 keywords = keywords->next;
3146 gq_gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
3147 file_data_unref(fd);
3148 g_list_free_full(keywords, g_free);
3150 return (G_SOURCE_CONTINUE);
3157 fd = static_cast<FileData *>(kfd->list_dir->data);
3158 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
3160 keywords_find_folder(kfd, fd);
3162 file_data_unref(fd);
3164 return G_SOURCE_CONTINUE;
3167 keywords_find_finish(kfd);
3169 return G_SOURCE_REMOVE;
3172 static void keywords_find_start_cb(GenericDialog *, gpointer data)
3174 auto kfd = static_cast<KeywordFindData *>(data);
3177 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
3179 path = remove_trailing_slash((gq_gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
3180 parse_out_relatives(path);
3184 warning_dialog(_("Invalid folder"),
3185 _("The specified folder can not be found."),
3186 GQ_ICON_DIALOG_WARNING, kfd->gd->dialog);
3192 gtk_widget_set_sensitive(kfd->group, FALSE);
3193 gtk_widget_set_sensitive(kfd->button_start, FALSE);
3194 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
3195 gtk_widget_set_sensitive(kfd->button_close, FALSE);
3196 gtk_spinner_start(GTK_SPINNER(kfd->spinner));
3198 dir_fd = file_data_new_dir(path);
3199 keywords_find_folder(kfd, dir_fd);
3200 file_data_unref(dir_fd);
3201 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
3207 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
3209 KeywordFindData *kfd;
3213 kfd = g_new0(KeywordFindData, 1);
3215 kfd->gd = generic_dialog_new(_("Search for keywords"),
3216 "search_for_keywords",
3219 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
3220 kfd->gd->cancel_cb = keywords_find_close_cb;
3221 kfd->button_close = generic_dialog_add_button(kfd->gd, GQ_ICON_CLOSE, _("Close"),
3222 keywords_find_close_cb, FALSE);
3223 kfd->button_start = generic_dialog_add_button(kfd->gd, GQ_ICON_OK, _("S_tart"),
3224 keywords_find_start_cb, FALSE);
3225 kfd->button_stop = generic_dialog_add_button(kfd->gd, GQ_ICON_STOP, _("Stop"),
3226 keywords_find_stop_cb, FALSE);
3227 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3229 generic_dialog_add_message(kfd->gd, nullptr, _("Search for keywords"), nullptr, FALSE);
3231 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
3232 pref_spacer(hbox, PREF_PAD_INDENT);
3233 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
3235 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3236 pref_label_new(hbox, _("Folder:"));
3238 label = tab_completion_new(&kfd->entry, path, nullptr, nullptr, nullptr, nullptr);
3239 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
3240 gq_gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
3241 gtk_widget_show(label);
3243 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
3245 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
3246 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3248 kfd->progress = gtk_entry_new();
3249 gtk_widget_set_can_focus(kfd->progress, FALSE);
3250 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
3251 gq_gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
3252 gq_gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
3253 gtk_widget_show(kfd->progress);
3255 kfd->spinner = gtk_spinner_new();
3256 gq_gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
3257 gtk_widget_show(kfd->spinner);
3259 kfd->list = nullptr;
3261 gtk_widget_show(kfd->gd->dialog);
3264 static void keywords_find_cb(GtkWidget *widget, gpointer)
3266 const gchar *path = layout_get_path(nullptr);
3268 if (!path || !*path) path = homedir();
3269 keywords_find_dialog(widget, path);
3272 static void config_tab_keywords_save()
3276 GtkTextBuffer *buffer;
3277 GList *kw_list = nullptr;
3281 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3282 gtk_text_buffer_get_bounds(buffer, &start, &end);
3284 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3286 kw_split = strtok(buffer_text, "\n");
3287 while (kw_split != nullptr)
3289 if (!g_list_find_custom(kw_list, kw_split, reinterpret_cast<GCompareFunc>(g_strcmp0)))
3291 kw_list = g_list_append(kw_list, g_strdup(kw_split));
3293 kw_split = strtok(nullptr, "\n");
3296 keyword_list_set(kw_list);
3298 g_list_free_full(kw_list, g_free);
3299 g_free(buffer_text);
3302 static void config_tab_keywords(GtkWidget *notebook)
3308 GtkWidget *scrolled;
3310 GtkTextBuffer *buffer;
3313 GspellTextView *gspell_view;
3316 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3318 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3320 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3322 button = pref_button_new(hbox, GQ_ICON_RUN, _("Search"),
3323 G_CALLBACK(keywords_find_cb), keyword_text);
3324 gtk_widget_set_tooltip_text(button, _("Search for existing keywords"));
3327 keyword_text = gtk_text_view_new();
3328 gtk_widget_set_size_request(keyword_text, 20, 20);
3329 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
3330 gq_gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3331 gtk_widget_show(scrolled);
3334 if (options->metadata.check_spelling)
3336 gspell_view = gspell_text_view_get_from_gtk_text_view(GTK_TEXT_VIEW(keyword_text));
3337 gspell_text_view_basic_setup(gspell_view);
3341 gq_gtk_container_add(GTK_WIDGET(scrolled), keyword_text);
3342 gtk_widget_show(keyword_text);
3344 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3346 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3347 gtk_text_buffer_create_tag(buffer, "monospace",
3348 "family", "monospace", NULL);
3350 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3351 gtk_text_buffer_get_start_iter(buffer, &iter);
3352 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3355 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3357 GList *kwl = keyword_list_get();
3358 kwl = g_list_first(kwl);
3361 gtk_text_buffer_get_end_iter (buffer, &iter);
3362 tmp = g_strconcat(static_cast<const gchar *>(kwl->data), "\n", NULL);
3363 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3368 gtk_text_buffer_set_modified(buffer, FALSE);
3375 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3377 auto option = static_cast<gint *>(data);
3379 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3383 *option = INTENT_PERCEPTUAL;
3386 *option = INTENT_RELATIVE_COLORIMETRIC;
3389 *option = INTENT_SATURATION;
3392 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3397 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3398 gint option, gint *option_c)
3405 pref_table_label(table, column, row, text, GTK_ALIGN_START);
3407 combo = gtk_combo_box_text_new();
3409 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3410 if (option == INTENT_PERCEPTUAL) current = 0;
3411 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3412 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3413 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3414 if (option == INTENT_SATURATION) current = 2;
3415 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3416 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3418 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3420 gtk_widget_set_tooltip_text(combo,_("Refer to the lcms documentation for the defaults used when the selected Intent is not available"));
3422 g_signal_connect(G_OBJECT(combo), "changed",
3423 G_CALLBACK(intent_menu_cb), option_c);
3425 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
3426 gtk_widget_show(combo);
3430 static void config_tab_color(GtkWidget *notebook)
3439 vbox = scrolled_notebook_page(notebook, _("Color management"));
3441 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3443 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3446 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3447 gtk_grid_set_column_spacing(GTK_GRID(table), PREF_PAD_GAP);
3449 label = pref_table_label(table, 0, 0, _("Type"), GTK_ALIGN_START);
3450 pref_label_bold(label, TRUE, FALSE);
3452 label = pref_table_label(table, 1, 0, _("Menu name"), GTK_ALIGN_START);
3453 pref_label_bold(label, TRUE, FALSE);
3455 label = pref_table_label(table, 2, 0, _("File"), GTK_ALIGN_START);
3456 pref_label_bold(label, TRUE, FALSE);
3458 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3463 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3464 pref_table_label(table, 0, i + 1, buf, GTK_ALIGN_END);
3467 entry = gtk_entry_new();
3468 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3469 if (options->color_profile.input_name[i])
3471 gq_gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3473 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);
3474 gtk_widget_show(entry);
3475 color_profile_input_name_entry[i] = entry;
3477 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], nullptr, ".icc", "ICC Files", nullptr);
3478 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3479 gtk_widget_set_size_request(entry, 160, -1);
3480 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);
3481 gtk_widget_show(tabcomp);
3482 color_profile_input_file_entry[i] = entry;
3485 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3487 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3489 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3490 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3492 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3494 pref_table_label(table, 0, 0, _("Screen:"), GTK_ALIGN_END);
3495 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3496 options->color_profile.screen_file, nullptr, ".icc", "ICC Files", nullptr);
3497 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3498 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3500 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3502 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);
3504 gtk_widget_show(tabcomp);
3507 /* advanced entry tab */
3508 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer)
3510 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3512 c_options->file_ops.use_system_trash = FALSE;
3513 c_options->file_ops.no_trash = FALSE;
3517 static void use_system_trash_cb(GtkWidget *widget, gpointer)
3519 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3521 c_options->file_ops.use_system_trash = TRUE;
3522 c_options->file_ops.no_trash = FALSE;
3526 static void use_no_cache_cb(GtkWidget *widget, gpointer)
3528 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3530 c_options->file_ops.no_trash = TRUE;
3534 static void config_tab_behavior(GtkWidget *notebook)
3541 GtkWidget *ct_button;
3545 GtkWidget *with_rename;
3546 GtkWidget *collections_on_top;
3547 GtkWidget *hide_window_in_fullscreen;
3548 GtkWidget *hide_osd_in_fullscreen;
3549 GtkWidget *checkbox;
3552 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3554 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3556 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3557 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3558 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3559 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3560 pref_checkbox_new_int(group, _("Enable Delete key"),
3561 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3563 ct_button = pref_radiobutton_new(group, nullptr, _("Use Geeqie trash location"),
3564 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),nullptr);
3566 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3567 pref_checkbox_link_sensitivity(ct_button, hbox);
3569 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3570 pref_label_new(hbox, _("Folder:"));
3572 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, nullptr, nullptr, nullptr, nullptr);
3573 tab_completion_add_select_button(safe_delete_path_entry, nullptr, TRUE);
3574 gq_gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3575 gtk_widget_show(tabcomp);
3577 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3578 pref_checkbox_link_sensitivity(ct_button, hbox);
3580 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3581 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MiB"),
3582 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3583 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3584 button = pref_button_new(nullptr, nullptr, _("View"),
3585 G_CALLBACK(safe_delete_view_cb), nullptr);
3586 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3587 gtk_widget_show(button);
3589 button = pref_button_new(nullptr, GQ_ICON_CLEAR, nullptr,
3590 G_CALLBACK(safe_delete_clear_cb), nullptr);
3591 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3593 c_options->file_ops.no_trash = options->file_ops.no_trash;
3594 c_options->file_ops.use_system_trash = options->file_ops.use_system_trash;
3596 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3597 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), nullptr);
3599 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3600 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), nullptr);
3602 gtk_widget_show(button);
3604 pref_spacer(group, PREF_PAD_GROUP);
3607 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3609 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3610 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3612 pref_checkbox_new_int(group, _("In place renaming"),
3613 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3615 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3616 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3618 tmp = pref_checkbox_new_int(group, _("Circular selection lists"),
3619 options->circular_selection_lists, &c_options->circular_selection_lists);
3620 gtk_widget_set_tooltip_text(tmp, _("Traverse selection lists in a circular manner"));
3622 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3623 options->marks_save, &c_options->marks_save);
3624 gtk_widget_set_tooltip_text(marks,_("Note that marks linked to a keyword will be saved irrespective of this setting"));
3626 with_rename = pref_checkbox_new_int(group, _("Use 'With Rename' as default for Copy/Move dialogs"),
3627 options->with_rename, &c_options->with_rename);
3628 gtk_widget_set_tooltip_text(with_rename,_("Change the default button for Copy/Move dialogs"));
3630 collections_on_top = pref_checkbox_new_int(group, _("Permit duplicates in Collections"),
3631 options->collections_duplicates, &c_options->collections_duplicates);
3632 gtk_widget_set_tooltip_text(collections_on_top, _("Allow the same image to be in a Collection more than once"));
3634 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3635 options->collections_on_top, &c_options->collections_on_top);
3636 gtk_widget_set_tooltip_text(collections_on_top, _("Open collections window on top"));
3638 hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3639 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3640 gtk_widget_set_tooltip_text(hide_window_in_fullscreen, _("When alt-tabbing, prevent Geeqie window showing twice"));
3642 hide_osd_in_fullscreen = pref_checkbox_new_int(group, _("Hide OSD in fullscreen"),
3643 options->hide_osd_in_fullscreen, &c_options->hide_osd_in_fullscreen);
3644 gtk_widget_set_tooltip_text(hide_osd_in_fullscreen, _("Hide Overlay Screen Display in fullscreen mode"));
3646 pref_spin_new_int(group, _("Recent folder list maximum size"), nullptr,
3647 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3649 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);
3650 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."));
3652 pref_spin_new_int(group, _("Drag'n drop icon size"), nullptr,
3653 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3655 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3656 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3658 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3659 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3661 pref_spacer(group, PREF_PAD_GROUP);
3663 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3665 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3666 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3667 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), nullptr,
3668 1, 32, 1, options->keyboard_scroll_step, reinterpret_cast<int *>(&c_options->keyboard_scroll_step));
3669 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3670 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3671 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3672 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3673 pref_checkbox_new_int(group, _("Open archive by left click on image"),
3674 options->image_l_click_archive, &c_options->image_l_click_archive);
3675 pref_checkbox_new_int(group, _("Play video by left click on image"),
3676 options->image_l_click_video, &c_options->image_l_click_video);
3677 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3678 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3680 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3681 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3682 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3683 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3684 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3686 pref_spacer(group, PREF_PAD_GROUP);
3688 group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3690 checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3691 options->override_disable_gpu, &c_options->override_disable_gpu);
3692 gtk_widget_set_tooltip_text(checkbox, _("Contact the developers for usage"));
3695 pref_spacer(group, PREF_PAD_GROUP);
3697 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3699 pref_spin_new_int(group, _("Debug level:"), nullptr,
3700 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3702 pref_checkbox_new_int(group, _("Timer data"),
3703 options->log_window.timer_data, &c_options->log_window.timer_data);
3705 pref_spin_new_int(group, _("Log Window max. lines:"), nullptr,
3706 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3708 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3709 pref_label_new(hbox, _("Log Window F1 command: "));
3710 log_window_f1_entry = gtk_entry_new();
3711 gq_gtk_entry_set_text(GTK_ENTRY(log_window_f1_entry), options->log_window.action);
3712 gq_gtk_box_pack_start(GTK_BOX(hbox), log_window_f1_entry, FALSE, FALSE, 0);
3713 gtk_entry_set_width_chars(GTK_ENTRY(log_window_f1_entry), 15);
3714 gtk_widget_show(log_window_f1_entry);
3718 /* accelerators tab */
3720 static gboolean accel_search_function_cb(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer)
3722 gboolean ret = TRUE;
3727 gtk_tree_model_get(model, iter, column, &text, -1);
3728 text_nocase = g_utf8_casefold(text, -1);
3729 key_nocase = g_utf8_casefold(key, -1);
3731 if (g_strstr_len(text_nocase, -1, key_nocase))
3738 g_free(text_nocase);
3743 static void accel_row_activated_cb(GtkTreeView *tree_view, GtkTreePath *, GtkTreeViewColumn *column, gpointer)
3748 list = gtk_tree_view_get_columns(tree_view);
3749 col_num = g_list_index(list, column);
3753 gtk_tree_view_set_search_column(tree_view, col_num);
3756 static void config_tab_accelerators(GtkWidget *notebook)
3762 GtkWidget *scrolled;
3763 GtkWidget *accel_view;
3764 GtkCellRenderer *renderer;
3765 GtkTreeSelection *selection;
3766 GtkTreeViewColumn *column;
3768 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3770 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3772 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
3773 gq_gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3774 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3775 gq_gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3776 gtk_widget_show(scrolled);
3778 accel_store = gtk_tree_store_new(5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3780 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3781 g_object_unref(accel_store);
3782 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3783 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3785 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3787 renderer = gtk_cell_renderer_text_new();
3789 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3794 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3795 gtk_tree_view_column_set_resizable(column, TRUE);
3796 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3799 renderer = gtk_cell_renderer_accel_new();
3800 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3801 G_CALLBACK(accel_store_cleared_cb), accel_store);
3802 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3803 G_CALLBACK(accel_store_edited_cb), accel_store);
3806 g_object_set (renderer,
3808 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3811 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3816 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3817 gtk_tree_view_column_set_resizable(column, TRUE);
3818 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3820 renderer = gtk_cell_renderer_text_new();
3822 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3827 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3828 gtk_tree_view_column_set_resizable(column, TRUE);
3829 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3831 renderer = gtk_cell_renderer_text_new();
3833 column = gtk_tree_view_column_new_with_attributes("Accel",
3838 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3839 gtk_tree_view_column_set_resizable(column, TRUE);
3840 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3842 column = gtk_tree_view_column_new_with_attributes("Icon",
3847 gtk_tree_view_column_set_sort_column_id(column, AE_ICON);
3848 gtk_tree_view_column_set_resizable(column, TRUE);
3849 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3851 /* Search on text in column */
3852 gtk_tree_view_set_activate_on_single_click(GTK_TREE_VIEW(accel_view), TRUE);
3853 g_signal_connect(accel_view, "row_activated", G_CALLBACK(accel_row_activated_cb), accel_store);
3854 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), TRUE);
3855 gtk_tree_view_set_search_column(GTK_TREE_VIEW(accel_view), AE_TOOLTIP);
3856 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(accel_view), accel_search_function_cb, nullptr, nullptr);
3858 accel_store_populate();
3859 gq_gtk_container_add(GTK_WIDGET(scrolled), accel_view);
3860 gtk_widget_show(accel_view);
3862 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3864 button = pref_button_new(nullptr, nullptr, _("Defaults"),
3865 G_CALLBACK(accel_default_cb), accel_view);
3866 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3867 gtk_widget_show(button);
3869 button = pref_button_new(nullptr, nullptr, _("Reset selected"),
3870 G_CALLBACK(accel_reset_cb), accel_view);
3871 gtk_widget_set_tooltip_text(button, _("Will only reset changes made before the settings are saved"));
3872 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3873 gtk_widget_show(button);
3875 button = pref_button_new(nullptr, nullptr, _("Clear selected"),
3876 G_CALLBACK(accel_clear_cb), accel_view);
3877 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3878 gtk_widget_show(button);
3881 /* toolbar main tab */
3882 static void config_tab_toolbar_main(GtkWidget *notebook)
3885 GtkWidget *toolbardata;
3888 lw = static_cast<LayoutWindow *>(layout_window_list->data);
3890 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3892 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3893 gq_gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3894 gtk_widget_show(vbox);
3897 /* toolbar status tab */
3898 static void config_tab_toolbar_status(GtkWidget *notebook)
3901 GtkWidget *toolbardata;
3904 lw = static_cast<LayoutWindow *>(layout_window_list->data);
3906 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3908 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3909 gq_gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3910 gtk_widget_show(vbox);
3914 static void config_tab_advanced(GtkWidget *notebook)
3917 GdkPixbufFormat *fm;
3919 GList *extensions_list = nullptr;
3920 GSList *formats_list;
3921 GString *types_string = g_string_new(nullptr);
3922 GtkWidget *alternate_checkbox;
3923 GtkWidget *dupes_threads_spin;
3925 GtkWidget *subgroup;
3927 GtkWidget *threads_string_label;
3928 GtkWidget *types_string_label;
3931 vbox = scrolled_notebook_page(notebook, _("Advanced"));
3932 group = pref_group_new(vbox, FALSE, _("External preview extraction"), GTK_ORIENTATION_VERTICAL);
3934 pref_checkbox_new_int(group, _("Use external preview extraction - Requires restart"), options->external_preview.enable, &c_options->external_preview.enable);
3936 pref_spacer(group, PREF_PAD_GROUP);
3938 formats_list = gdk_pixbuf_get_formats();
3940 while (formats_list)
3942 fm = static_cast<GdkPixbufFormat *>(formats_list->data);
3943 extensions = gdk_pixbuf_format_get_extensions(fm);
3946 while (extensions[i])
3948 extensions_list = g_list_insert_sorted(extensions_list, g_strdup(extensions[i]), reinterpret_cast<GCompareFunc>(g_strcmp0));
3952 g_strfreev(extensions);
3953 formats_list = formats_list->next;
3956 while (extensions_list)
3958 if (types_string->len == 0)
3960 types_string = g_string_append(types_string, static_cast<const gchar *>(extensions_list->data));
3964 types_string = g_string_append(types_string, ", ");
3965 types_string = g_string_append(types_string, static_cast<const gchar *>(extensions_list->data));
3968 extensions_list = extensions_list->next;
3971 types_string = g_string_prepend(types_string, _("Usable file types:\n"));
3972 types_string_label = pref_label_new(group, types_string->str);
3973 gtk_label_set_line_wrap(GTK_LABEL(types_string_label), TRUE);
3975 pref_spacer(group, PREF_PAD_GROUP);
3977 group = pref_group_new(vbox, FALSE, _("File identification tool"), GTK_ORIENTATION_VERTICAL);
3978 external_preview_select_entry = gtk_entry_new();
3979 tabcomp = tab_completion_new(&external_preview_select_entry, options->external_preview.select, nullptr, nullptr, nullptr, nullptr);
3980 tab_completion_add_select_button(external_preview_select_entry, _("Select file identification tool"), FALSE);
3981 gq_gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3982 gtk_widget_show(tabcomp);
3984 group = pref_group_new(vbox, FALSE, _("Preview extraction tool"), GTK_ORIENTATION_VERTICAL);
3985 external_preview_extract_entry = gtk_entry_new();
3986 tabcomp = tab_completion_new(&external_preview_extract_entry, options->external_preview.extract, nullptr, nullptr, nullptr, nullptr);
3987 tab_completion_add_select_button(external_preview_extract_entry, _("Select preview extraction tool"), FALSE);
3988 gq_gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3989 gtk_widget_show(tabcomp);
3991 gtk_widget_show(vbox);
3993 g_slist_free(formats_list);
3994 g_list_free_full(extensions_list, g_free);
3995 g_string_free(types_string, TRUE);
3997 pref_spacer(group, PREF_PAD_GROUP);
3999 pref_line(vbox, PREF_PAD_SPACE);
4000 group = pref_group_new(vbox, FALSE, _("Thread pool limits"), GTK_ORIENTATION_VERTICAL);
4002 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."));
4003 gtk_label_set_line_wrap(GTK_LABEL(threads_string_label), TRUE);
4005 pref_spacer(vbox, PREF_PAD_GROUP);
4007 dupes_threads_spin = pref_spin_new_int(vbox, _("Duplicate check:"), _("max. threads"), 0, get_cpu_cores(), 1, options->threads.duplicates, &c_options->threads.duplicates);
4008 gtk_widget_set_tooltip_markup(dupes_threads_spin, _("Set to 0 for unlimited"));
4010 pref_spacer(group, PREF_PAD_GROUP);
4012 pref_line(vbox, PREF_PAD_SPACE);
4014 group = pref_group_new(vbox, FALSE, _("Alternate similarity alogorithm"), GTK_ORIENTATION_VERTICAL);
4016 alternate_checkbox = pref_checkbox_new_int(group, _("Enable alternate similarity algorithm"), options->alternate_similarity_algorithm.enabled, &c_options->alternate_similarity_algorithm.enabled);
4018 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
4019 pref_checkbox_link_sensitivity(alternate_checkbox, subgroup);
4021 alternate_checkbox = pref_checkbox_new_int(subgroup, _("Use grayscale"), options->alternate_similarity_algorithm.grayscale, &c_options->alternate_similarity_algorithm.grayscale);
4022 gtk_widget_set_tooltip_text(alternate_checkbox, _("Reduce fingerprint to grayscale"));
4026 static void config_tab_stereo(GtkWidget *notebook)
4034 GtkWidget *fs_button;
4035 vbox = scrolled_notebook_page(notebook, _("Stereo"));
4037 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
4039 table = pref_table_new(group, 2, 1, FALSE, FALSE);
4040 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
4042 table = pref_table_new(group, 2, 2, TRUE, FALSE);
4043 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
4044 pref_checkbox_new_int(box, _("Mirror left image"),
4045 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
4046 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
4047 pref_checkbox_new_int(box, _("Flip left image"),
4048 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
4049 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
4050 pref_checkbox_new_int(box, _("Mirror right image"),
4051 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
4052 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
4053 pref_checkbox_new_int(box, _("Flip right image"),
4054 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
4055 pref_checkbox_new_int(group, _("Swap left and right images"),
4056 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
4057 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
4058 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
4060 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
4061 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
4062 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
4063 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
4064 pref_checkbox_link_sensitivity(fs_button, box2);
4065 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
4066 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
4067 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
4068 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
4069 pref_checkbox_new_int(box, _("Mirror left image"),
4070 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
4071 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
4072 pref_checkbox_new_int(box, _("Flip left image"),
4073 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
4074 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
4075 pref_checkbox_new_int(box, _("Mirror right image"),
4076 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
4077 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
4078 pref_checkbox_new_int(box, _("Flip right image"),
4079 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
4080 pref_checkbox_new_int(box2, _("Swap left and right images"),
4081 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
4082 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
4083 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
4085 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
4086 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
4087 pref_table_spin_new_int(table, 0, 0, _("Width"), nullptr,
4088 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
4089 pref_table_spin_new_int(table, 3, 0, _("Height"), nullptr,
4090 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
4091 pref_table_spin_new_int(table, 0, 1, _("Left X"), nullptr,
4092 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
4093 pref_table_spin_new_int(table, 3, 1, _("Left Y"), nullptr,
4094 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
4095 pref_table_spin_new_int(table, 0, 2, _("Right X"), nullptr,
4096 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
4097 pref_table_spin_new_int(table, 3, 2, _("Right Y"), nullptr,
4098 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
4102 /* Main preferences window */
4103 static void config_window_create(LayoutWindow *lw)
4105 GtkWidget *win_vbox;
4107 GtkWidget *notebook;
4109 GtkWidget *ct_button;
4111 if (!c_options) c_options = init_options(nullptr);
4113 configwindow = window_new("preferences", PIXBUF_INLINE_ICON_CONFIG, nullptr, _("Preferences"));
4114 DEBUG_NAME(configwindow);
4115 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
4116 g_signal_connect(G_OBJECT(configwindow), "delete_event",
4117 G_CALLBACK(config_window_delete), NULL);
4118 if (options->save_dialog_window_positions)
4120 gtk_window_resize(GTK_WINDOW(configwindow), lw->options.preferences_window.w, lw->options.preferences_window.h);
4121 gq_gtk_window_move(GTK_WINDOW(configwindow), lw->options.preferences_window.x, lw->options.preferences_window.y);
4125 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
4127 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
4128 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
4130 win_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
4131 gq_gtk_container_add(GTK_WIDGET(configwindow), win_vbox);
4132 gtk_widget_show(win_vbox);
4134 notebook = gtk_notebook_new();
4135 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
4136 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
4137 gq_gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
4139 config_tab_general(notebook);
4140 config_tab_image(notebook);
4141 config_tab_osd(notebook);
4142 config_tab_windows(notebook);
4143 config_tab_accelerators(notebook);
4144 config_tab_files(notebook);
4145 config_tab_metadata(notebook);
4146 config_tab_keywords(notebook);
4147 config_tab_color(notebook);
4148 config_tab_stereo(notebook);
4149 config_tab_behavior(notebook);
4150 config_tab_toolbar_main(notebook);
4151 config_tab_toolbar_status(notebook);
4152 config_tab_advanced(notebook);
4154 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), lw->options.preferences_window.page_number);
4156 hbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
4157 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
4158 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
4159 gq_gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
4160 gtk_widget_show(hbox);
4162 button = pref_button_new(nullptr, GQ_ICON_HELP, _("Help"),
4163 G_CALLBACK(config_window_help_cb), notebook);
4164 gq_gtk_container_add(GTK_WIDGET(hbox), button);
4165 gtk_widget_set_can_default(button, TRUE);
4166 gtk_widget_show(button);
4168 button = pref_button_new(nullptr, GQ_ICON_OK, "OK",
4169 G_CALLBACK(config_window_ok_cb), notebook);
4170 gq_gtk_container_add(GTK_WIDGET(hbox), button);
4171 gtk_widget_set_can_default(button, TRUE);
4172 gtk_widget_grab_default(button);
4173 gtk_widget_show(button);
4177 button = pref_button_new(nullptr, GQ_ICON_CANCEL, _("Cancel"),
4178 G_CALLBACK(config_window_close_cb), nullptr);
4179 gq_gtk_container_add(GTK_WIDGET(hbox), button);
4180 gtk_widget_set_can_default(button, TRUE);
4181 gtk_widget_show(button);
4183 if (!generic_dialog_get_alternative_button_order(configwindow))
4185 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
4188 gtk_widget_show(notebook);
4190 gtk_widget_show(configwindow);
4194 *-----------------------------------------------------------------------------
4195 * config window show (public)
4196 *-----------------------------------------------------------------------------
4199 void show_config_window(LayoutWindow *lw)
4203 gtk_window_present(GTK_WINDOW(configwindow));
4207 config_window_create(lw);
4216 void show_about_window(LayoutWindow *lw)
4218 GDataInputStream *data_stream;
4219 GInputStream *in_stream_authors;
4220 GInputStream *in_stream_translators;
4222 GdkPixbuf *pixbuf_icon;
4223 GdkPixbuf *pixbuf_logo;
4227 gchar *authors[1000];
4229 gchar *timezone_path;
4238 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"));
4240 timezone_path = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
4241 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
4243 cd = ZDOpenDatabase(timezone_path);
4246 copyright = g_string_append(copyright, ZDGetNotice(cd));
4250 log_printf("Error: Init of timezone database %s failed\n", timezone_path);
4252 ZDCloseDatabase(cd);
4254 g_free(timezone_path);
4256 copyright = g_string_append(copyright, _("\n\nSome icons by https://www.flaticon.com"));
4258 in_stream_authors = g_resources_open_stream(GQ_RESOURCE_PATH_CREDITS "/authors", G_RESOURCE_LOOKUP_FLAGS_NONE, nullptr);
4260 data_stream = g_data_input_stream_new(in_stream_authors);
4262 authors[0] = nullptr;
4263 while ((author_line = g_data_input_stream_read_line(G_DATA_INPUT_STREAM(data_stream), &length, nullptr, nullptr)))
4265 authors[i_authors] = g_strdup(author_line);
4267 g_free(author_line);
4269 authors[i_authors] = nullptr;
4271 g_input_stream_close(in_stream_authors, nullptr, nullptr);
4273 constexpr auto translators_path = GQ_RESOURCE_PATH_CREDITS "/translators";
4275 g_resources_get_info(translators_path, G_RESOURCE_LOOKUP_FLAGS_NONE, &size, &flags, nullptr);
4277 in_stream_translators = g_resources_open_stream(translators_path, G_RESOURCE_LOOKUP_FLAGS_NONE, nullptr);
4278 translators = static_cast<gchar *>(g_malloc0(size));
4279 g_input_stream_read_all(in_stream_translators, translators, size, &bytes_read, nullptr, nullptr);
4280 g_input_stream_close(in_stream_translators, nullptr, nullptr);
4282 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);
4284 artists[0] = g_strdup("Néstor Díaz Valencia <nestor@estudionexos.com>");
4285 artists[1] = nullptr;
4287 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
4288 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
4289 gtk_show_about_dialog(GTK_WINDOW(lw->window),
4290 "title", _("About Geeqie"),
4292 "program-name", GQ_APPNAME,
4294 "logo", pixbuf_logo,
4295 "icon", pixbuf_icon,
4296 "website", GQ_WEBSITE,
4297 "website-label", _("Website"),
4298 "comments", comment,
4301 "translator-credits", translators,
4302 "wrap-license", TRUE,
4303 "license", copyright->str,
4306 g_string_free(copyright, TRUE);
4308 while(n < i_authors)
4316 g_free(translators);
4317 g_object_unref(data_stream);
4318 g_object_unref(in_stream_authors);
4319 g_object_unref(in_stream_translators);
4322 static void image_overlay_set_text_colors()
4324 c_options->image_overlay.text_red = options->image_overlay.text_red;
4325 c_options->image_overlay.text_green = options->image_overlay.text_green;
4326 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
4327 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
4328 c_options->image_overlay.background_red = options->image_overlay.background_red;
4329 c_options->image_overlay.background_green = options->image_overlay.background_green;
4330 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
4331 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
4335 *-----------------------------------------------------------------------------
4336 * timezone database routines
4337 *-----------------------------------------------------------------------------
4340 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
4342 GError *error = nullptr;
4343 auto tz = static_cast<TZData *>(data);
4344 gchar *tmp_filename;
4345 gchar *timezone_bin;
4346 gchar *tmp_dir = nullptr;
4349 if (!g_cancellable_is_cancelled(tz->cancellable))
4351 generic_dialog_close(tz->gd);
4355 if (g_file_copy_finish(G_FILE(source_object), res, &error))
4357 tmp_filename = g_file_get_path(tz->tmp_g_file);
4358 fd = file_data_new_simple(tmp_filename);
4359 tmp_dir = open_archive(fd);
4363 timezone_bin = g_build_filename(tmp_dir, TIMEZONE_DATABASE_VERSION, TIMEZONE_DATABASE_FILE, NULL);
4364 if (isfile(timezone_bin))
4366 move_file(timezone_bin, tz->timezone_database_user);
4370 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GQ_ICON_DIALOG_WARNING, nullptr);
4373 g_free(timezone_bin);
4374 g_free(tmp_dir); // The folder in /tmp is deleted in exit_program_final()
4378 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GQ_ICON_DIALOG_WARNING, nullptr);
4380 g_free(tmp_filename);
4381 file_data_unref(fd);
4385 file_util_warning_dialog(_("Error: Timezone database download failed"), error->message, GQ_ICON_DIALOG_ERROR, nullptr);
4388 g_file_delete(tz->tmp_g_file, nullptr, &error);
4389 g_object_unref(tz->tmp_g_file);
4390 tz->tmp_g_file = nullptr;
4391 g_object_unref(tz->cancellable);
4392 g_object_unref(tz->timezone_database_gq);
4395 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
4397 auto tz = static_cast<TZData *>(data);
4399 if (!g_cancellable_is_cancelled(tz->cancellable))
4401 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), static_cast<gdouble>(current_num_bytes) / total_num_bytes);
4405 static void timezone_cancel_button_cb(GenericDialog *, gpointer data)
4407 auto tz = static_cast<TZData *>(data);
4409 g_cancellable_cancel(tz->cancellable);
4412 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
4414 auto tz = static_cast<TZData *>(data);
4415 GError *error = nullptr;
4416 GFileIOStream *io_stream;
4423 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
4427 file_util_warning_dialog(_("Timezone database download failed"), error->message, GQ_ICON_DIALOG_ERROR, nullptr);
4428 log_printf("Error: Download timezone database failed:\n%s", error->message);
4429 g_error_free(error);
4430 g_object_unref(tz->tmp_g_file);
4434 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE_WEB);
4436 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", nullptr, TRUE, timezone_cancel_button_cb, tz);
4438 generic_dialog_add_message(tz->gd, GQ_ICON_DIALOG_INFO, _("Downloading timezone database"), nullptr, FALSE);
4440 tz->progress = gtk_progress_bar_new();
4441 gq_gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
4442 gtk_widget_show(tz->progress);
4444 gtk_widget_show(tz->gd->dialog);
4445 tz->cancellable = g_cancellable_new();
4446 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);
4448 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
4451 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */