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 ActionItem *action_item = nullptr;
825 auto option = static_cast<gchar **>(data);
830 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
832 list = get_action_items();
837 action_item = static_cast<ActionItem *>(work->data);
838 if (g_strcmp0(action_item->label, label) == 0)
846 *option = g_strdup(action_item->name);
848 action_items_free(list);
851 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, gchar *option, gchar **option_c)
853 ActionItem *action_item;
862 pref_table_label(table, column, row, text, GTK_ALIGN_START);
864 combo = gtk_combo_box_text_new();
866 list = get_action_items();
870 action_item = static_cast<ActionItem *>(work->data);
871 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), action_item->label);
873 if (g_strcmp0(action_item->name, option) == 0)
881 action_items_free(list);
883 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
885 g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
887 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
888 gtk_widget_show(combo);
891 static void thumb_size_menu_cb(GtkWidget *combo, gpointer)
895 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
898 if (static_cast<guint>(n) < sizeof(thumb_size_list) / sizeof(ThumbSize))
900 c_options->thumbnails.max_width = thumb_size_list[n].w;
901 c_options->thumbnails.max_height = thumb_size_list[n].h;
905 c_options->thumbnails.max_width = options->thumbnails.max_width;
906 c_options->thumbnails.max_height = options->thumbnails.max_height;
910 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
916 c_options->thumbnails.max_width = options->thumbnails.max_width;
917 c_options->thumbnails.max_height = options->thumbnails.max_height;
919 pref_table_label(table, column, row, text, GTK_ALIGN_START);
921 combo = gtk_combo_box_text_new();
924 for (i = 0; static_cast<guint>(i) < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
930 w = thumb_size_list[i].w;
931 h = thumb_size_list[i].h;
933 buf = g_strdup_printf("%d x %d", w, h);
934 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
937 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
944 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
945 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
951 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
952 g_signal_connect(G_OBJECT(combo), "changed",
953 G_CALLBACK(thumb_size_menu_cb), NULL);
955 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
956 gtk_widget_show(combo);
959 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
961 auto option = static_cast<gint *>(data);
963 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
967 *option = PR_STEREO_NONE;
970 *option = PR_STEREO_ANAGLYPH_RC;
973 *option = PR_STEREO_ANAGLYPH_GM;
976 *option = PR_STEREO_ANAGLYPH_YB;
979 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
982 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
985 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
988 *option = PR_STEREO_ANAGLYPH_DB_RC;
991 *option = PR_STEREO_ANAGLYPH_DB_GM;
994 *option = PR_STEREO_ANAGLYPH_DB_YB;
997 *option = PR_STEREO_HORIZ;
1000 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
1003 *option = PR_STEREO_VERT;
1006 *option = PR_STEREO_VERT | PR_STEREO_HALF;
1009 *option = PR_STEREO_FIXED;
1014 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1015 gint option, gint *option_c, gboolean add_fixed)
1022 pref_table_label(table, column, row, text, GTK_ALIGN_START);
1024 combo = gtk_combo_box_text_new();
1026 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
1028 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
1029 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
1030 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
1031 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
1032 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
1033 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
1034 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
1035 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
1036 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
1037 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
1038 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
1039 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
1040 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
1041 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
1042 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
1043 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
1044 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
1045 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
1047 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
1048 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
1049 if (option & PR_STEREO_HORIZ)
1052 if (option & PR_STEREO_HALF) current = 11;
1055 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
1056 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
1057 if (option & PR_STEREO_VERT)
1060 if (option & PR_STEREO_HALF) current = 13;
1065 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
1066 if (option & PR_STEREO_FIXED) current = 14;
1069 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1071 g_signal_connect(G_OBJECT(combo), "changed",
1072 G_CALLBACK(stereo_mode_menu_cb), option_c);
1074 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
1075 gtk_widget_show(combo);
1078 static void video_menu_cb(GtkWidget *combo, gpointer data)
1080 auto option = static_cast<gchar **>(data);
1082 auto ed = static_cast<EditorDescription *>(g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo))));
1086 static void video_menu_populate(gpointer data, gpointer user_data)
1088 auto combo = static_cast<GtkWidget *>(user_data);
1089 auto ed = static_cast<EditorDescription *>(data);
1091 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1094 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1095 gchar *option, gchar **option_c)
1099 /* use lists since they are sorted */
1100 GList *eds = editor_list_get();
1104 pref_table_label(table, column, row, text, GTK_ALIGN_START);
1106 combo = gtk_combo_box_text_new();
1107 g_list_foreach(eds,video_menu_populate,combo);
1108 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1110 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1112 g_signal_connect(G_OBJECT(combo), "changed",
1113 G_CALLBACK(video_menu_cb), option_c);
1115 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
1116 gtk_widget_show(combo);
1119 static void filter_store_populate()
1123 if (!filter_store) return;
1125 gtk_list_store_clear(filter_store);
1127 work = filter_get_list();
1133 fe = static_cast<FilterEntry *>(work->data);
1136 gtk_list_store_append(filter_store, &iter);
1137 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1141 static void filter_store_ext_edit_cb(GtkCellRendererText *, gchar *path_str, gchar *new_text, gpointer data)
1143 auto model = static_cast<GtkWidget *>(data);
1144 auto fe = static_cast<FilterEntry *>(data);
1148 if (!new_text || strlen(new_text) < 1) return;
1150 tpath = gtk_tree_path_new_from_string(path_str);
1151 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1152 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1154 g_free(fe->extensions);
1155 fe->extensions = g_strdup(new_text);
1157 gtk_tree_path_free(tpath);
1161 static void filter_store_class_edit_cb(GtkCellRendererText *, gchar *path_str, gchar *new_text, gpointer data)
1163 auto model = static_cast<GtkWidget *>(data);
1164 auto fe = static_cast<FilterEntry *>(data);
1169 if (!new_text || !new_text[0]) return;
1171 tpath = gtk_tree_path_new_from_string(path_str);
1172 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1173 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1175 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1177 if (strcmp(new_text, _(format_class_list[i])) == 0)
1179 fe->file_class = static_cast<FileFormatClass>(i);
1184 gtk_tree_path_free(tpath);
1188 static void filter_store_desc_edit_cb(GtkCellRendererText *, gchar *path_str, gchar *new_text, gpointer data)
1190 auto model = static_cast<GtkWidget *>(data);
1195 if (!new_text || !new_text[0]) return;
1197 tpath = gtk_tree_path_new_from_string(path_str);
1198 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1199 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1201 g_free(fe->description);
1202 fe->description = g_strdup(new_text);
1204 gtk_tree_path_free(tpath);
1207 static void filter_store_enable_cb(GtkCellRendererToggle *, gchar *path_str, gpointer data)
1209 auto model = static_cast<GtkWidget *>(data);
1214 tpath = gtk_tree_path_new_from_string(path_str);
1215 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1216 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1218 fe->enabled = !fe->enabled;
1220 gtk_tree_path_free(tpath);
1224 static void filter_store_writable_cb(GtkCellRendererToggle *, gchar *path_str, gpointer data)
1226 auto model = static_cast<GtkWidget *>(data);
1231 tpath = gtk_tree_path_new_from_string(path_str);
1232 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1233 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1235 fe->writable = !fe->writable;
1236 if (fe->writable) fe->allow_sidecar = FALSE;
1238 gtk_tree_path_free(tpath);
1242 static void filter_store_sidecar_cb(GtkCellRendererToggle *, gchar *path_str, gpointer data)
1244 auto model = static_cast<GtkWidget *>(data);
1249 tpath = gtk_tree_path_new_from_string(path_str);
1250 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1251 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1253 fe->allow_sidecar = !fe->allow_sidecar;
1254 if (fe->allow_sidecar) fe->writable = FALSE;
1256 gtk_tree_path_free(tpath);
1260 static void filter_set_func(GtkTreeViewColumn *, GtkCellRenderer *cell,
1261 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1265 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1267 switch (GPOINTER_TO_INT(data))
1270 g_object_set(GTK_CELL_RENDERER(cell),
1271 "active", fe->enabled, NULL);
1274 g_object_set(GTK_CELL_RENDERER(cell),
1275 "text", fe->extensions, NULL);
1277 case FE_DESCRIPTION:
1278 g_object_set(GTK_CELL_RENDERER(cell),
1279 "text", fe->description, NULL);
1282 g_object_set(GTK_CELL_RENDERER(cell),
1283 "text", _(format_class_list[fe->file_class]), NULL);
1286 g_object_set(GTK_CELL_RENDERER(cell),
1287 "active", fe->writable, NULL);
1289 case FE_ALLOW_SIDECAR:
1290 g_object_set(GTK_CELL_RENDERER(cell),
1291 "active", fe->allow_sidecar, NULL);
1296 static gboolean filter_add_scroll(gpointer data)
1300 GtkCellRenderer *cell;
1301 GtkTreeViewColumn *column;
1304 GtkTreeModel *store;
1306 FilterEntry *filter;
1308 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), nullptr);
1309 path = gtk_tree_path_new_from_indices(rows-1, -1);
1311 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1313 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1314 cell = static_cast<GtkCellRenderer *>(g_list_last(list_cells)->data);
1316 store = gtk_tree_view_get_model(GTK_TREE_VIEW(data));
1317 valid = gtk_tree_model_get_iter_first(store, &iter);
1321 gtk_tree_model_get(store, &iter, 0, &filter, -1);
1323 if (g_strcmp0(filter->extensions, ".new") == 0)
1325 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
1329 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1332 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1333 path, column, FALSE, 0.0, 0.0 );
1334 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1335 path, column, cell, TRUE);
1337 gtk_tree_path_free(path);
1338 g_list_free(list_cells);
1340 return(G_SOURCE_REMOVE);
1343 static void filter_add_cb(GtkWidget *, gpointer data)
1345 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1346 filter_store_populate();
1348 g_idle_add(static_cast<GSourceFunc>(filter_add_scroll), data);
1351 static void filter_remove_cb(GtkWidget *, gpointer data)
1353 auto filter_view = static_cast<GtkWidget *>(data);
1354 GtkTreeSelection *selection;
1358 if (!filter_store) return;
1359 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1360 if (!gtk_tree_selection_get_selected(selection, nullptr, &iter)) return;
1361 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1364 filter_remove_entry(fe);
1366 filter_store_populate();
1369 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1373 GtkTreeViewColumn *column;
1375 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1376 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1377 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1379 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1383 gtk_tree_path_free(path);
1385 return(G_SOURCE_REMOVE);
1388 static void filter_default_ok_cb(GenericDialog *gd, gpointer)
1391 filter_add_defaults();
1393 filter_store_populate();
1395 g_idle_add(reinterpret_cast<GSourceFunc>(filter_default_ok_scroll), gd->data);
1398 static void dummy_cancel_cb(GenericDialog *, gpointer)
1400 /* no op, only so cancel button appears */
1403 static void filter_default_cb(GtkWidget *widget, gpointer data)
1407 gd = generic_dialog_new(_("Reset filters"),
1408 "reset_filter", widget, TRUE,
1409 dummy_cancel_cb, data);
1410 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Reset filters"),
1411 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1412 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", filter_default_ok_cb, TRUE);
1413 gtk_widget_show(gd->dialog);
1416 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1418 auto frame = static_cast<GtkWidget *>(data);
1420 gtk_widget_set_sensitive(frame,
1421 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1424 static void safe_delete_view_cb(GtkWidget *, gpointer)
1426 layout_set_path(nullptr, gq_gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1429 static void safe_delete_clear_ok_cb(GenericDialog *, gpointer)
1431 file_util_trash_clear();
1434 static void safe_delete_clear_cb(GtkWidget *widget, gpointer)
1438 gd = generic_dialog_new(_("Clear trash"),
1439 "clear_trash", widget, TRUE,
1440 dummy_cancel_cb, nullptr);
1441 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Clear trash"),
1442 _("This will remove the trash contents."), FALSE);
1443 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", safe_delete_clear_ok_cb, TRUE);
1444 entry = gtk_entry_new();
1445 gtk_widget_set_can_focus(entry, FALSE);
1446 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1447 if (options->file_ops.safe_delete_path) gq_gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1448 gq_gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1449 gtk_widget_show(entry);
1450 gtk_widget_show(gd->dialog);
1453 static void image_overlay_template_view_changed_cb(GtkWidget *, gpointer data)
1455 GtkWidget *pTextView;
1456 GtkTextBuffer *pTextBuffer;
1460 pTextView = GTK_WIDGET(data);
1462 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1463 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1464 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1466 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1467 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1470 static void image_overlay_default_template_ok_cb(GenericDialog *, gpointer data)
1472 auto text_view = static_cast<GtkTextView *>(data);
1473 GtkTextBuffer *buffer;
1475 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1476 if (!configwindow) return;
1478 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1479 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1482 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1486 gd = generic_dialog_new(_("Reset image overlay template string"),
1487 "reset_image_overlay_template_string", widget, TRUE,
1488 dummy_cancel_cb, data);
1489 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Reset image overlay template string"),
1490 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1491 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", image_overlay_default_template_ok_cb, TRUE);
1492 gtk_widget_show(gd->dialog);
1495 static void image_overlay_help_cb(GtkWidget *, gpointer)
1497 help_window_show("GuideOptionsOSD.html");
1500 static void font_activated_cb(GtkFontChooser *widget, gchar *fontname, gpointer)
1502 g_free(c_options->image_overlay.font);
1503 c_options->image_overlay.font = g_strdup(fontname);
1506 gq_gtk_widget_destroy(GTK_WIDGET(widget));
1509 static void font_response_cb(GtkDialog *dialog, gint response_id, gpointer)
1513 g_free(c_options->image_overlay.font);
1514 c_options->image_overlay.font = g_strdup(options->image_overlay.font);
1516 if (response_id == GTK_RESPONSE_OK)
1518 font = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(dialog));
1519 g_free(c_options->image_overlay.font);
1520 c_options->image_overlay.font = g_strdup(font);
1524 gq_gtk_widget_destroy(GTK_WIDGET(dialog));
1527 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer)
1531 dialog = gtk_font_chooser_dialog_new(_("Image Overlay Font"), GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1532 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1533 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1535 g_signal_connect(dialog, "font-activated", G_CALLBACK(font_activated_cb), nullptr);
1536 g_signal_connect(dialog, "response", G_CALLBACK(font_response_cb), nullptr);
1538 gtk_widget_show(dialog);
1541 static void text_color_activated_cb(GtkColorChooser *chooser, GdkRGBA *color, gpointer)
1543 c_options->image_overlay.text_red = color->red * 255;
1544 c_options->image_overlay.text_green = color->green * 255;
1545 c_options->image_overlay.text_blue = color->blue * 255;
1546 c_options->image_overlay.text_alpha = color->alpha * 255;
1548 gq_gtk_widget_destroy(GTK_WIDGET(chooser));
1551 static void text_color_response_cb(GtkDialog *dialog, gint response_id, gpointer)
1555 c_options->image_overlay.text_red = options->image_overlay.text_red;
1556 c_options->image_overlay.text_green = options->image_overlay.text_green;
1557 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
1558 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
1560 if (response_id == GTK_RESPONSE_OK)
1562 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &color);
1563 c_options->image_overlay.text_red = color.red * 255;
1564 c_options->image_overlay.text_green = color.green * 255;
1565 c_options->image_overlay.text_blue = color.blue * 255;
1566 c_options->image_overlay.text_alpha = color.alpha * 255;
1569 gq_gtk_widget_destroy(GTK_WIDGET(dialog));
1572 static void image_overlay_set_text_color_cb(GtkWidget *widget, gpointer)
1577 dialog = gtk_color_chooser_dialog_new(_("Image Overlay Text Color"), GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1578 color.red = options->image_overlay.text_red;
1579 color.green = options->image_overlay.text_green;
1580 color.blue = options->image_overlay.text_blue;
1581 color.alpha = options->image_overlay.text_alpha;
1582 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &color);
1583 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1585 g_signal_connect(dialog, "color-activated", G_CALLBACK(text_color_activated_cb), nullptr);
1586 g_signal_connect(dialog, "response", G_CALLBACK(text_color_response_cb), nullptr);
1588 gtk_widget_show(dialog);
1591 static void bg_color_activated_cb(GtkColorChooser *chooser, GdkRGBA *color, gpointer)
1593 c_options->image_overlay.background_red = color->red * 255;
1594 c_options->image_overlay.background_green = color->green * 255;
1595 c_options->image_overlay.background_blue = color->blue * 255;
1596 c_options->image_overlay.background_alpha = color->alpha * 255;
1598 gq_gtk_widget_destroy(GTK_WIDGET(chooser));
1601 static void bg_color_response_cb(GtkDialog *dialog, gint response_id, gpointer)
1605 c_options->image_overlay.background_red = options->image_overlay.background_red;
1606 c_options->image_overlay.background_green = options->image_overlay.background_green;
1607 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
1608 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
1610 if (response_id == GTK_RESPONSE_OK)
1612 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &color);
1613 c_options->image_overlay.background_red = color.red * 255;
1614 c_options->image_overlay.background_green = color.green * 255;
1615 c_options->image_overlay.background_blue = color.blue * 255;
1616 c_options->image_overlay.background_alpha = color.alpha * 255;
1618 gq_gtk_widget_destroy(GTK_WIDGET(dialog));
1621 static void image_overlay_set_background_color_cb(GtkWidget *widget, gpointer)
1626 dialog = gtk_color_chooser_dialog_new(_("Image Overlay Background Color"), GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1627 color.red = options->image_overlay.background_red;
1628 color.green = options->image_overlay.background_green;
1629 color.blue = options->image_overlay.background_blue;
1630 color.alpha = options->image_overlay.background_alpha;
1631 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &color);
1632 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1634 g_signal_connect(dialog, "color-activated", G_CALLBACK(bg_color_activated_cb), nullptr);
1635 g_signal_connect(dialog, "response", G_CALLBACK(bg_color_response_cb), nullptr);
1637 gtk_widget_show(dialog);
1640 static void accel_store_populate()
1646 const gchar *accel_path;
1647 const gchar *icon_name;
1651 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1653 gtk_tree_store_clear(accel_store);
1654 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 */
1656 g_assert(lw && lw->ui_manager);
1657 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1660 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1663 action = GTK_ACTION(actions->data);
1664 accel_path = gtk_action_get_accel_path(action);
1665 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1671 g_object_get(action,
1672 "tooltip", &tooltip,
1676 if (pango_parse_markup(label, -1, '_', nullptr, &label2, nullptr, nullptr) && label2)
1682 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1683 icon_name = gtk_action_get_icon_name(action);
1687 gtk_tree_store_append(accel_store, &iter, nullptr);
1688 gtk_tree_store_set(accel_store, &iter,
1691 AE_TOOLTIP, tooltip ? tooltip : "",
1692 AE_ACCEL, accel_path,
1701 actions = actions->next;
1704 groups = groups->next;
1708 static void accel_store_cleared_cb(GtkCellRendererAccel *, gchar *, gpointer)
1713 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *, GtkTreeIter *iter, gpointer data)
1715 auto accel1 = static_cast<gchar *>(data);
1720 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1722 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1723 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1725 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1727 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1728 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1737 static void accel_store_edited_cb(GtkCellRendererAccel *, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint, gpointer)
1739 auto model = reinterpret_cast<GtkTreeModel *>(accel_store);
1743 GtkAccelKey old_key;
1745 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1747 gtk_tree_model_get_iter(model, &iter, path);
1748 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1750 /* test if the accelerator can be stored without conflicts*/
1751 gtk_accel_map_lookup_entry(accel_path, &old_key);
1753 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1754 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1755 gtk_accel_map_lookup_entry(accel_path, &key);
1757 /* restore the original for now, the key will be really changed when the changes are confirmed */
1758 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1760 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1761 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1763 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1764 gtk_tree_path_free(path);
1768 static gboolean accel_default_scroll(GtkTreeView *data)
1772 GtkTreeViewColumn *column;
1774 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1775 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1776 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1778 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1782 gtk_tree_path_free(path);
1784 return(G_SOURCE_REMOVE);
1787 static void accel_default_cb(GtkWidget *, gpointer data)
1789 accel_store_populate();
1791 g_idle_add(reinterpret_cast<GSourceFunc>(accel_default_scroll), data);
1794 void accel_clear_selection(GtkTreeModel *, GtkTreePath *, GtkTreeIter *iter, gpointer)
1796 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1799 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *, GtkTreeIter *iter, gpointer)
1805 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1806 gtk_accel_map_lookup_entry(accel_path, &key);
1807 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1809 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1811 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1816 static void accel_clear_cb(GtkWidget *, gpointer data)
1818 GtkTreeSelection *selection;
1820 if (!accel_store) return;
1821 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1822 gtk_tree_selection_selected_foreach(selection, &accel_clear_selection, nullptr);
1825 static void accel_reset_cb(GtkWidget *, gpointer data)
1827 GtkTreeSelection *selection;
1829 if (!accel_store) return;
1830 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1831 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, nullptr);
1836 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1840 GtkWidget *scrolled;
1841 GtkWidget *viewport;
1843 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
1844 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1845 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1846 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1847 label = gtk_label_new(title);
1848 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1849 gtk_widget_show(scrolled);
1851 viewport = gtk_viewport_new(nullptr, nullptr);
1852 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1853 gq_gtk_container_add(GTK_WIDGET(scrolled), viewport);
1854 gtk_widget_show(viewport);
1856 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
1857 gq_gtk_container_add(GTK_WIDGET(viewport), vbox);
1858 gtk_widget_show(vbox);
1863 static void cache_standard_cb(GtkWidget *widget, gpointer)
1865 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1867 c_options->thumbnails.spec_standard =TRUE;
1868 c_options->thumbnails.cache_into_dirs = FALSE;
1872 static void cache_geeqie_cb(GtkWidget *widget, gpointer)
1874 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1876 c_options->thumbnails.spec_standard =FALSE;
1877 c_options->thumbnails.cache_into_dirs = FALSE;
1881 static void cache_local_cb(GtkWidget *widget, gpointer)
1883 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1885 c_options->thumbnails.cache_into_dirs = TRUE;
1886 c_options->thumbnails.spec_standard =FALSE;
1890 static void help_search_engine_entry_icon_cb(GtkEntry *, GtkEntryIconPosition pos, GdkEvent *, gpointer userdata)
1892 if (pos == GTK_ENTRY_ICON_PRIMARY)
1894 gq_gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1898 gq_gtk_entry_set_text(GTK_ENTRY(userdata), "");
1902 static void star_rating_star_icon_cb(GtkEntry *, GtkEntryIconPosition pos, GdkEvent *, gpointer userdata)
1904 gchar *rating_symbol;
1906 if (pos == GTK_ENTRY_ICON_PRIMARY)
1908 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1909 gq_gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1910 g_free(rating_symbol);
1914 gq_gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1915 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1916 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1920 static void star_rating_rejected_icon_cb(GtkEntry *, GtkEntryIconPosition pos, GdkEvent *, gpointer userdata)
1922 gchar *rating_symbol;
1924 if (pos == GTK_ENTRY_ICON_PRIMARY)
1926 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1927 gq_gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1928 g_free(rating_symbol);
1932 gq_gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1933 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1934 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1938 static guint star_rating_symbol_test(GtkWidget *, gpointer data)
1940 auto hbox = static_cast<GtkContainer *>(data);
1941 GString *str = g_string_new(nullptr);
1942 GtkEntry *hex_code_entry;
1943 gchar *hex_code_full;
1946 guint64 hex_value = 0;
1948 list = gtk_container_get_children(hbox);
1950 hex_code_entry = static_cast<GtkEntry *>(g_list_nth_data(list, 2));
1951 hex_code_full = g_strdup(gq_gtk_entry_get_text(hex_code_entry));
1953 hex_code = g_strsplit(hex_code_full, "+", 2);
1954 if (hex_code[0] && hex_code[1])
1956 hex_value = strtoull(hex_code[1], nullptr, 16);
1958 if (!hex_value || hex_value > 0x10FFFF)
1960 hex_value = 0x003F; // Unicode 'Question Mark'
1962 str = g_string_append_unichar(str, static_cast<gunichar>(hex_value));
1963 gtk_label_set_text(static_cast<GtkLabel *>(g_list_nth_data(list, 1)), str->str);
1965 g_strfreev(hex_code);
1966 g_string_free(str, TRUE);
1967 g_free(hex_code_full);
1972 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1974 guint64 star_symbol;
1976 star_symbol = star_rating_symbol_test(widget, data);
1977 c_options->star_rating.star = star_symbol;
1980 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1982 guint64 rejected_symbol;
1984 rejected_symbol = star_rating_symbol_test(widget, data);
1985 c_options->star_rating.rejected = rejected_symbol;
1988 /* general options tab */
1989 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1993 GCancellable *cancellable;
1995 GtkWidget *progress;
1997 GFile *timezone_database_gq;
1998 gchar *timezone_database_user;
2001 static void config_tab_general(GtkWidget *notebook)
2006 GtkWidget *group_frame;
2007 GtkWidget *subgroup;
2009 GtkWidget *ct_button;
2016 GtkWidget *star_rating_entry;
2018 gchar *rating_symbol;
2021 gchar *download_locn;
2022 GNetworkMonitor *net_mon;
2023 GSocketConnectable *tz_org;
2024 gboolean internet_available = FALSE;
2027 vbox = scrolled_notebook_page(notebook, _("General"));
2029 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
2031 table = pref_table_new(group, 2, 2, FALSE, FALSE);
2032 add_thumb_size_menu(table, 0, 0, _("Size:"));
2033 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
2035 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2036 pref_label_new(hbox, _("Custom size: "));
2037 pref_spin_new_int(hbox, _("Width:"), nullptr, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
2038 pref_spin_new_int(hbox, _("Height:"), nullptr, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
2040 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
2041 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
2043 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2044 pref_checkbox_link_sensitivity(ct_button, subgroup);
2046 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
2047 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
2048 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
2049 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2050 button = pref_radiobutton_new(group_frame, nullptr, get_thumbnails_cache_dir(),
2051 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2052 G_CALLBACK(cache_geeqie_cb), nullptr);
2054 group_frame = pref_frame_new(subgroup, TRUE,
2055 _("Store thumbnails local to image folder (non-standard)"),
2056 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2057 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
2058 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
2059 G_CALLBACK(cache_local_cb), nullptr);
2061 group_frame = pref_frame_new(subgroup, TRUE,
2062 _("Use standard thumbnail style and cache, shared with other applications"),
2063 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2064 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
2065 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2066 G_CALLBACK(cache_standard_cb), nullptr);
2068 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
2069 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
2071 pref_checkbox_new_int(group, _("Thumbnail color management"),
2072 options->thumbnails.use_color_management, &c_options->thumbnails.use_color_management);
2074 spin = pref_spin_new_int(group, _("Collection preview:"), nullptr,
2076 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
2077 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
2079 #if HAVE_FFMPEGTHUMBNAILER_METADATA
2080 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
2081 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
2084 pref_spacer(group, PREF_PAD_GROUP);
2086 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
2088 c_options->star_rating.star = options->star_rating.star;
2089 c_options->star_rating.rejected = options->star_rating.rejected;
2091 str = g_string_new(nullptr);
2092 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2093 pref_label_new(hbox, _("Star character: "));
2094 str = g_string_append_unichar(str, options->star_rating.star);
2095 pref_label_new(hbox, g_strdup(str->str));
2096 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
2097 star_rating_entry = gtk_entry_new();
2098 gq_gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2099 gq_gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2100 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2101 gtk_widget_show(star_rating_entry);
2102 button = pref_button_new(nullptr, nullptr, _("Set"),
2103 G_CALLBACK(star_rating_star_test_cb), hbox);
2104 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2105 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2106 gtk_widget_show(button);
2107 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."));
2108 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2109 GTK_ENTRY_ICON_SECONDARY, GQ_ICON_CLEAR);
2110 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2111 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2112 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2113 GTK_ENTRY_ICON_PRIMARY, GQ_ICON_REVERT);
2114 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2115 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2116 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2117 G_CALLBACK(star_rating_star_icon_cb),
2120 g_string_free(str, TRUE);
2121 g_free(rating_symbol);
2123 str = g_string_new(nullptr);
2124 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2125 pref_label_new(hbox, _("Rejected character: "));
2126 str = g_string_append_unichar(str, options->star_rating.rejected);
2127 pref_label_new(hbox, g_strdup(str->str));
2128 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2129 star_rating_entry = gtk_entry_new();
2130 gq_gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2131 gq_gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2132 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2133 gtk_widget_show(star_rating_entry);
2134 button = pref_button_new(nullptr, nullptr, _("Set"),
2135 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2136 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2137 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2138 gtk_widget_show(button);
2139 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."));
2140 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2141 GTK_ENTRY_ICON_SECONDARY, GQ_ICON_CLEAR);
2142 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2143 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2144 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2145 GTK_ENTRY_ICON_PRIMARY, GQ_ICON_REVERT);
2146 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2147 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2148 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2149 G_CALLBACK(star_rating_rejected_icon_cb),
2152 g_string_free(str, TRUE);
2153 g_free(rating_symbol);
2155 pref_spacer(group, PREF_PAD_GROUP);
2157 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2159 c_options->slideshow.delay = options->slideshow.delay;
2160 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2161 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2162 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2163 seconds = static_cast<gdouble>(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2164 SLIDESHOW_SUBSECOND_PRECISION;
2166 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2168 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), nullptr,
2170 options->slideshow.delay ? hours : 0.0,
2171 G_CALLBACK(slideshow_delay_hours_cb), nullptr);
2172 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2173 spin = pref_spin_new(hbox, ":" , nullptr,
2175 options->slideshow.delay ? minutes: 0.0,
2176 G_CALLBACK(slideshow_delay_minutes_cb), nullptr);
2177 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2178 spin = pref_spin_new(hbox, ":", nullptr,
2179 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2180 options->slideshow.delay ? seconds : 10.0,
2181 G_CALLBACK(slideshow_delay_seconds_cb), nullptr);
2182 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2184 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2185 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2187 pref_spacer(group, PREF_PAD_GROUP);
2189 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2191 pref_spin_new_int(group, _("Decoded image cache size (MiB):"), nullptr,
2192 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2193 pref_checkbox_new_int(group, _("Preload next image"),
2194 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2196 pref_checkbox_new_int(group, _("Refresh on file change"),
2197 options->update_on_time_change, &c_options->update_on_time_change);
2200 pref_spacer(group, PREF_PAD_GROUP);
2202 group = pref_group_new(vbox, FALSE, _("Menu style"), GTK_ORIENTATION_VERTICAL);
2204 pref_checkbox_new_int(group, _("☰ style menu button (NOTE! Geeqie must be restarted for change to take effect)"),
2205 options->hamburger_menu, &c_options->hamburger_menu);
2206 gtk_widget_set_tooltip_text(group, _("Use a ☰ style menu button instead of the classic style across the top of the frame"));
2208 pref_spacer(group, PREF_PAD_GROUP);
2210 group = pref_group_new(vbox, FALSE, _("Expand toolbar"), GTK_ORIENTATION_VERTICAL);
2212 pref_checkbox_new_int(group, _("Expand menu/toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2213 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2214 gtk_widget_set_tooltip_text(group, _("Expand the menu/toolbar to the full width of the window"));
2216 pref_spacer(group, PREF_PAD_GROUP);
2218 group = pref_group_new(vbox, FALSE, _("Hide Selectable Bars"), GTK_ORIENTATION_VERTICAL);
2220 pref_checkbox_new_int(group, _("Menu bar"),
2221 options->selectable_bars.menu_bar, &c_options->selectable_bars.menu_bar);
2223 pref_checkbox_new_int(group, _("Tool bar"),
2224 options->selectable_bars.tool_bar, &c_options->selectable_bars.tool_bar);
2226 pref_checkbox_new_int(group, _("Status bar"),
2227 options->selectable_bars.status_bar, &c_options->selectable_bars.status_bar);
2228 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"));
2230 pref_spacer(group, PREF_PAD_GROUP);
2232 if ((g_getenv("APPDIR") && strstr(g_getenv("APPDIR"), "/tmp/.mount_Geeqie")) || (g_strstr_len(gq_executable_path, -1, "squashfs-root")))
2234 group = pref_group_new(vbox, FALSE, _("AppImage updates notifications"), GTK_ORIENTATION_VERTICAL);
2235 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2236 pref_checkbox_new_int(group, _("Enable"), options->appimage_notifications, &c_options->appimage_notifications);
2237 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"));
2239 pref_spacer(group, PREF_PAD_GROUP);
2243 net_mon = g_network_monitor_get_default();
2244 tz_org = g_network_address_parse_uri(TIMEZONE_DATABASE_WEB, 80, nullptr);
2247 internet_available = g_network_monitor_can_reach(net_mon, tz_org, nullptr, nullptr);
2248 g_object_unref(tz_org);
2251 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2252 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2254 if (!internet_available)
2256 gtk_widget_set_sensitive(group, FALSE);
2259 tz = g_new0(TZData, 1);
2261 path = path_from_utf8(TIMEZONE_DATABASE_WEB);
2262 basename = g_path_get_basename(path);
2263 tz->timezone_database_user = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
2267 if (isfile(tz->timezone_database_user))
2269 button = pref_button_new(GTK_WIDGET(hbox), nullptr, _("Update"), G_CALLBACK(timezone_database_install_cb), tz);
2273 button = pref_button_new(GTK_WIDGET(hbox), nullptr, _("Install"), G_CALLBACK(timezone_database_install_cb), tz);
2276 download_locn = g_strconcat(_("Download database from: "), TIMEZONE_DATABASE_WEB, NULL);
2277 pref_label_new(GTK_WIDGET(hbox), download_locn);
2278 g_free(download_locn);
2280 if (!internet_available)
2282 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"));
2286 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"));
2288 gtk_widget_show(button);
2290 pref_spacer(group, PREF_PAD_GROUP);
2292 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2294 help_search_engine_entry = gtk_entry_new();
2295 gq_gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2296 gq_gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2297 gtk_widget_show(help_search_engine_entry);
2299 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"));
2301 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(help_search_engine_entry),
2302 GTK_ENTRY_ICON_SECONDARY, GQ_ICON_CLEAR);
2303 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2304 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2305 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(help_search_engine_entry),
2306 GTK_ENTRY_ICON_PRIMARY, GQ_ICON_REVERT);
2307 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2308 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2309 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2310 G_CALLBACK(help_search_engine_entry_icon_cb),
2311 help_search_engine_entry);
2315 static void config_tab_image(GtkWidget *notebook)
2320 GtkWidget *ct_button;
2321 GtkWidget *enlargement_button;
2325 vbox = scrolled_notebook_page(notebook, _("Image"));
2327 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2329 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2330 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2332 pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2333 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2335 c_options->image.zoom_increment = options->image.zoom_increment;
2336 spin = pref_spin_new(group, _("Zoom increment:"), nullptr,
2337 0.01, 4.0, 0.01, 2, static_cast<gdouble>(options->image.zoom_increment) / 100.0,
2338 G_CALLBACK(zoom_increment_cb), nullptr);
2339 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2341 c_options->image.zoom_style = options->image.zoom_style;
2342 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2343 add_zoom_style_selection_menu(table, 0, 0, _("Zoom style:"), options->image.zoom_style, &c_options->image.zoom_style);
2345 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2347 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2348 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2349 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2350 spin = pref_spin_new_int(hbox, nullptr, nullptr,
2352 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2353 pref_checkbox_link_sensitivity(enlargement_button, spin);
2354 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."));
2356 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2357 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (%% of actual window):"),
2358 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2359 spin = pref_spin_new_int(hbox, nullptr, nullptr,
2361 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2362 pref_checkbox_link_sensitivity(ct_button, spin);
2363 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."));
2365 group = pref_group_new(vbox, FALSE, _("Tile size"), GTK_ORIENTATION_VERTICAL);
2367 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2368 spin = pref_spin_new_int(hbox, _("Pixels"), _("(Requires restart)"),
2370 options->image.tile_size, &c_options->image.tile_size);
2371 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."));
2373 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2375 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2376 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2378 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2379 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2381 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2382 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2384 c_options->image.border_color = options->image.border_color;
2386 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2387 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2389 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2390 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2392 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2393 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2398 static void save_default_window_layout_cb(GtkWidget *, gpointer)
2400 LayoutWindow *lw = nullptr;
2401 gchar *default_path;
2404 /* Get current lw */
2407 tmp_id = lw->options.id;
2408 lw->options.id = g_strdup("");
2410 default_path = g_build_filename(get_rc_dir(), DEFAULT_WINDOW_LAYOUT, NULL);
2411 save_default_layout_options_to_file(default_path, options, lw);
2412 g_free(lw->options.id);
2413 lw->options.id = tmp_id;
2414 g_free(default_path);
2417 static gboolean popover_cb(gpointer data)
2419 auto popover = static_cast<GtkPopover *>(data);
2421 gtk_popover_popdown(popover);
2426 static void default_layout_changed_cb(GtkWidget *, GtkPopover *popover)
2428 gtk_popover_popup(popover);
2430 g_timeout_add(2000, popover_cb, popover);
2433 static GtkWidget *create_popover(GtkWidget *parent, GtkWidget *child, GtkPositionType pos)
2437 popover = gtk_popover_new(parent);
2438 gtk_popover_set_position(GTK_POPOVER (popover), pos);
2439 gq_gtk_container_add(GTK_WIDGET(popover), child);
2440 gtk_container_set_border_width(GTK_CONTAINER (popover), 6);
2441 gtk_widget_show (child);
2446 static void config_tab_windows(GtkWidget *notebook)
2451 GtkWidget *subgroup;
2453 GtkWidget *checkbox;
2454 GtkWidget *ct_button;
2458 vbox = scrolled_notebook_page(notebook, _("Windows"));
2460 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2462 ct_button = pref_checkbox_new_int(group, _("Remember session"),
2463 options->save_window_positions, &c_options->save_window_positions);
2465 checkbox = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2466 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2467 pref_checkbox_link_sensitivity(ct_button, checkbox);
2469 checkbox = pref_checkbox_new_int(group, _("Remember window workspace"),
2470 options->save_window_workspace, &c_options->save_window_workspace);
2471 pref_checkbox_link_sensitivity(ct_button, checkbox);
2473 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2474 options->tools_restore_state, &c_options->tools_restore_state);
2476 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2477 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2479 widget = pref_checkbox_new_int(group, _("Hide window decorations"),
2480 options->hide_window_decorations, &c_options->hide_window_decorations);
2481 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");
2483 pref_checkbox_new_int(group, _("Show window IDs"),
2484 options->show_window_ids, &c_options->show_window_ids);
2486 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2487 pref_label_new(subgroup, _("Use current layout for default: "));
2488 button = pref_button_new(subgroup, nullptr, _("Set"), G_CALLBACK(save_default_window_layout_cb), nullptr);
2492 popover = create_popover(button, gtk_label_new(_("Current window layout\nhas been set as default")), GTK_POS_TOP);
2493 gtk_popover_set_modal(GTK_POPOVER (popover), FALSE);
2494 g_signal_connect(button, "clicked", G_CALLBACK(default_layout_changed_cb), popover);
2496 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2498 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2499 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2501 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2502 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2503 options->image.limit_window_size, &c_options->image.limit_window_size);
2504 spin = pref_spin_new_int(hbox, nullptr, nullptr,
2506 options->image.max_window_size, &c_options->image.max_window_size);
2507 pref_checkbox_link_sensitivity(ct_button, spin);
2509 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2511 c_options->fullscreen.screen = options->fullscreen.screen;
2512 c_options->fullscreen.above = options->fullscreen.above;
2513 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2514 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2515 gtk_widget_show(hbox);
2517 pref_checkbox_new_int(group, _("Smooth image flip"),
2518 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2519 pref_checkbox_new_int(group, _("Disable screen saver"),
2520 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2523 static void config_tab_osd(GtkWidget *notebook)
2529 GtkWidget *image_overlay_template_view;
2530 GtkWidget *scrolled;
2531 GtkWidget *scrolled_pre_formatted;
2532 GtkTextBuffer *buffer;
2534 GtkWidget *subgroup;
2536 vbox = scrolled_notebook_page(notebook, _("OSD"));
2538 image_overlay_template_view = gtk_text_view_new();
2540 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2542 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2544 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2545 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2546 gq_gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2547 gtk_widget_show(scrolled_pre_formatted);
2548 gtk_widget_show(subgroup);
2550 pref_line(group, PREF_PAD_GAP);
2552 pref_label_new(group, _("Image overlay template"));
2554 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
2555 gtk_widget_set_size_request(scrolled, 200, 150);
2556 gq_gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2557 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2558 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2559 gq_gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2560 gtk_widget_show(scrolled);
2562 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2563 _("Extensive formatting options are shown in the Help file"));
2565 gq_gtk_container_add(GTK_WIDGET(scrolled), image_overlay_template_view);
2566 gtk_widget_show(image_overlay_template_view);
2568 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2570 button = pref_button_new(nullptr, GQ_ICON_SELECT_FONT, _("Font"),
2571 G_CALLBACK(image_overlay_set_font_cb), notebook);
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, _("Text"), G_CALLBACK(image_overlay_set_text_color_cb), nullptr);
2577 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2578 gtk_widget_show(button);
2580 button = pref_button_new(nullptr, GQ_ICON_SELECT_COLOR, _("Background"), G_CALLBACK(image_overlay_set_background_color_cb), nullptr);
2581 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2582 gtk_widget_show(button);
2583 image_overlay_set_text_colors();
2585 button = pref_button_new(nullptr, nullptr, _("Defaults"),
2586 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2587 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2588 gtk_widget_show(button);
2590 button = pref_button_new(nullptr, GQ_ICON_HELP, _("Help"),
2591 G_CALLBACK(image_overlay_help_cb), nullptr);
2592 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2593 gtk_widget_show(button);
2595 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2596 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2597 g_signal_connect(G_OBJECT(buffer), "changed",
2598 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2600 pref_line(group, PREF_PAD_GAP);
2602 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2603 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2604 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2605 gtk_widget_show(hbox);
2606 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2607 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2608 gtk_widget_show(label);
2609 pref_spacer(group,TRUE);
2611 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2612 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2613 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2614 gtk_widget_show(hbox);
2615 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2616 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2617 gtk_widget_show(label);
2618 pref_spacer(group,TRUE);
2620 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2621 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2622 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2623 gtk_widget_show(hbox);
2624 label = gtk_label_new(_("%path:39%"));
2625 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2626 gtk_widget_show(label);
2627 pref_spacer(group,TRUE);
2629 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2630 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2631 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2632 gtk_widget_show(hbox);
2633 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%"));
2634 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2635 gtk_widget_show(label);
2636 pref_spacer(group,TRUE);
2638 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2639 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2640 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2641 gtk_widget_show(hbox);
2642 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2643 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2644 gtk_widget_show(label);
2647 static GtkTreeModel *create_class_model()
2649 GtkListStore *model;
2653 /* create list store */
2654 model = gtk_list_store_new(1, G_TYPE_STRING);
2655 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2657 gtk_list_store_append(model, &iter);
2658 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2660 return GTK_TREE_MODEL (model);
2665 static gint filter_table_sort_cb(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data)
2667 gint n = GPOINTER_TO_INT(data);
2669 FilterEntry *filter_a;
2670 FilterEntry *filter_b;
2672 gtk_tree_model_get(model, a, 0, &filter_a, -1);
2673 gtk_tree_model_get(model, b, 0, &filter_b, -1);
2677 case FILETYPES_COLUMN_ENABLED:
2679 ret = filter_a->enabled - filter_b->enabled;
2682 case FILETYPES_COLUMN_FILTER:
2684 ret = g_utf8_collate(filter_a->extensions, filter_b->extensions);
2687 case FILETYPES_COLUMN_DESCRIPTION:
2689 ret = g_utf8_collate(filter_a->description, filter_b->description);
2692 case FILETYPES_COLUMN_CLASS:
2694 ret = g_strcmp0(format_class_list[filter_a->file_class], format_class_list[filter_b->file_class]);
2697 case FILETYPES_COLUMN_WRITABLE:
2699 ret = filter_a->writable - filter_b->writable;
2702 case FILETYPES_COLUMN_SIDECAR:
2704 ret = filter_a->allow_sidecar - filter_b->allow_sidecar;
2708 g_return_val_if_reached(0);
2714 static gboolean search_function_cb(GtkTreeModel *model, gint, const gchar *key, GtkTreeIter *iter, gpointer)
2717 gboolean ret = TRUE;
2719 gtk_tree_model_get(model, iter, 0, &fe, -1);
2721 if (g_strstr_len(fe->extensions, -1, key))
2729 static void config_tab_files(GtkWidget *notebook)
2736 GtkWidget *ct_button;
2737 GtkWidget *scrolled;
2738 GtkWidget *filter_view;
2739 GtkCellRenderer *renderer;
2740 GtkTreeSelection *selection;
2741 GtkTreeViewColumn *column;
2743 vbox = scrolled_notebook_page(notebook, _("File Filters"));
2745 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2747 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2748 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2749 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2750 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2751 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);
2752 pref_checkbox_new_int(group, _("Disable file extension checks"),
2753 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2755 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2756 options->file_filter.disable, &c_options->file_filter.disable);
2759 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2761 sidecar_ext_entry = gtk_entry_new();
2762 gq_gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2763 gq_gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2764 gtk_widget_show(sidecar_ext_entry);
2766 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2768 frame = pref_group_parent(group);
2769 g_signal_connect(G_OBJECT(ct_button), "toggled",
2770 G_CALLBACK(filter_disable_cb), frame);
2771 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2773 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
2774 gq_gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2775 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2776 gq_gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2777 gtk_widget_show(scrolled);
2779 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2780 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2781 g_object_unref(filter_store);
2782 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2783 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2785 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2787 column = gtk_tree_view_column_new();
2788 gtk_tree_view_column_set_title(column, _("Enabled"));
2789 gtk_tree_view_column_set_resizable(column, TRUE);
2791 renderer = gtk_cell_renderer_toggle_new();
2792 g_signal_connect(G_OBJECT(renderer), "toggled",
2793 G_CALLBACK(filter_store_enable_cb), filter_store);
2794 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2795 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2796 GINT_TO_POINTER(FE_ENABLE), nullptr);
2797 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);
2798 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_ENABLED);
2799 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2801 column = gtk_tree_view_column_new();
2802 gtk_tree_view_column_set_title(column, _("Filter"));
2803 gtk_tree_view_column_set_resizable(column, TRUE);
2804 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);
2805 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_FILTER);
2807 renderer = gtk_cell_renderer_text_new();
2808 g_signal_connect(G_OBJECT(renderer), "edited",
2809 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2810 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2811 g_object_set(G_OBJECT(renderer), "editable", static_cast<gboolean>TRUE, NULL);
2812 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2813 GINT_TO_POINTER(FE_EXTENSION), nullptr);
2814 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2816 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), TRUE);
2817 gtk_tree_view_set_search_column(GTK_TREE_VIEW(filter_view), FILETYPES_COLUMN_FILTER);
2818 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(filter_view), search_function_cb, nullptr, nullptr);
2820 column = gtk_tree_view_column_new();
2821 gtk_tree_view_column_set_title(column, _("Description"));
2822 gtk_tree_view_column_set_resizable(column, TRUE);
2823 gtk_tree_view_column_set_fixed_width(column, 200);
2824 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2826 renderer = gtk_cell_renderer_text_new();
2827 g_signal_connect(G_OBJECT(renderer), "edited",
2828 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2829 g_object_set(G_OBJECT(renderer), "editable", static_cast<gboolean>TRUE, NULL);
2830 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2831 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2832 GINT_TO_POINTER(FE_DESCRIPTION), nullptr);
2833 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2834 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);
2835 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_DESCRIPTION);
2837 column = gtk_tree_view_column_new();
2838 gtk_tree_view_column_set_title(column, _("Class"));
2839 gtk_tree_view_column_set_resizable(column, TRUE);
2840 renderer = gtk_cell_renderer_combo_new();
2841 g_object_set(G_OBJECT(renderer), "editable", static_cast<gboolean>TRUE,
2842 "model", create_class_model(),
2847 g_signal_connect(G_OBJECT(renderer), "edited",
2848 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2849 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2850 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2851 GINT_TO_POINTER(FE_CLASS), nullptr);
2852 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2853 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);
2854 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_CLASS);
2856 column = gtk_tree_view_column_new();
2857 gtk_tree_view_column_set_title(column, _("Writable"));
2858 gtk_tree_view_column_set_resizable(column, FALSE);
2859 renderer = gtk_cell_renderer_toggle_new();
2860 g_signal_connect(G_OBJECT(renderer), "toggled",
2861 G_CALLBACK(filter_store_writable_cb), filter_store);
2862 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2863 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2864 GINT_TO_POINTER(FE_WRITABLE), nullptr);
2865 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2866 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);
2867 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_WRITABLE);
2869 column = gtk_tree_view_column_new();
2870 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2871 gtk_tree_view_column_set_resizable(column, FALSE);
2872 renderer = gtk_cell_renderer_toggle_new();
2873 g_signal_connect(G_OBJECT(renderer), "toggled",
2874 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2875 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2876 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2877 GINT_TO_POINTER(FE_ALLOW_SIDECAR), nullptr);
2878 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2879 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);
2880 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_SIDECAR);
2882 filter_store_populate();
2883 gq_gtk_container_add(GTK_WIDGET(scrolled), filter_view);
2884 gtk_widget_show(filter_view);
2886 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2888 button = pref_button_new(nullptr, nullptr, _("Defaults"),
2889 G_CALLBACK(filter_default_cb), filter_view);
2890 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2891 gtk_widget_show(button);
2893 button = pref_button_new(nullptr, GQ_ICON_REMOVE, _("Remove"),
2894 G_CALLBACK(filter_remove_cb), filter_view);
2895 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2896 gtk_widget_show(button);
2898 button = pref_button_new(nullptr, GQ_ICON_ADD, _("Add"),
2899 G_CALLBACK(filter_add_cb), filter_view);
2900 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2901 gtk_widget_show(button);
2905 static void config_tab_metadata(GtkWidget *notebook)
2910 GtkWidget *ct_button;
2912 GtkWidget *tmp_widget;
2914 GtkWidget *text_label;
2916 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2919 group = pref_group_new(vbox, FALSE, _("Metadata writing sequence"), GTK_ORIENTATION_VERTICAL);
2921 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2923 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."));
2924 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2925 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2927 gtk_widget_set_tooltip_text(label, _("A flowchart of the sequence is shown in the Help file"));
2929 ct_button = pref_checkbox_new_int(group, "", options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2930 text_label = gtk_bin_get_child(GTK_BIN(ct_button));
2931 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"));
2932 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2934 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)"));
2935 gtk_widget_set_tooltip_markup(ct_button, markup);
2939 gtk_widget_set_sensitive(ct_button, FALSE);
2942 tmp_widget = pref_checkbox_new_int(group, "", options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2943 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2944 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)"));
2945 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2948 label = pref_label_new(group, "");
2949 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(), "/");
2950 gtk_label_set_markup (GTK_LABEL(label), markup);
2953 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2954 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2955 gtk_widget_set_margin_start(label, 22);
2956 pref_spacer(group, PREF_PAD_GROUP);
2958 group = pref_group_new(vbox, FALSE, _("Step 1 Options:"), GTK_ORIENTATION_VERTICAL);
2960 gtk_widget_set_sensitive(group, FALSE);
2963 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2964 pref_checkbox_link_sensitivity(ct_button, hbox);
2966 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);
2967 gtk_widget_set_tooltip_text(tmp_widget, _("A simplified conversion list is in the Help file"));
2969 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);
2971 pref_checkbox_new_int(hbox, _("Ask before writing to image files"), options->metadata.confirm_write, &c_options->metadata.confirm_write);
2973 tmp_widget= pref_checkbox_new_int(hbox, "", options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2974 gtk_widget_set_tooltip_text(tmp_widget, _("This file naming convention is used by Darktable"));
2975 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2976 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", ")");
2977 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2980 pref_spacer(group, PREF_PAD_GROUP);
2982 group = pref_group_new(vbox, FALSE, _("Steps 2 and 3 Option:"), GTK_ORIENTATION_VERTICAL);
2984 gtk_widget_set_sensitive(group, FALSE);
2987 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);
2989 pref_spacer(group, PREF_PAD_GROUP);
2991 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2992 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);
2993 gtk_widget_set_tooltip_text(tmp_widget, _("See the Help file for a list of the tags used"));
2995 tmp_widget = pref_checkbox_new_int(group, _("Permit Keywords to be case-sensitive"), options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2996 gtk_widget_set_tooltip_text(tmp_widget, _("When selected, \"Place\" and \"place\" are two different keywords"));
2998 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"), options->metadata.write_orientation, &c_options->metadata.write_orientation);
2999 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"));
3002 gtk_widget_set_sensitive(ct_button, FALSE);
3005 pref_spacer(group, PREF_PAD_GROUP);
3007 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
3009 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"), options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
3011 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3012 pref_checkbox_link_sensitivity(ct_button, hbox);
3014 pref_spin_new_int(hbox, _("Timeout (seconds):"), nullptr, 0, 900, 1, options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
3016 pref_checkbox_new_int(group, _("Write metadata on image change"), options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
3018 pref_checkbox_new_int(group, _("Write metadata on directory change"), options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
3020 pref_spacer(group, PREF_PAD_GROUP);
3023 group = pref_group_new(vbox, FALSE, _("Spelling checks"), GTK_ORIENTATION_VERTICAL);
3025 ct_button = pref_checkbox_new_int(group, _("Check spelling - Requires restart"), options->metadata.check_spelling, &c_options->metadata.check_spelling);
3026 gtk_widget_set_tooltip_text(ct_button, _("Spelling checks are performed on info sidebar panes Comment, Headline and Title"));
3029 pref_spacer(group, PREF_PAD_GROUP);
3031 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
3033 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"), options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
3034 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");
3039 struct KeywordFindData
3046 GtkWidget *button_close;
3047 GtkWidget *button_stop;
3048 GtkWidget *button_start;
3049 GtkWidget *progress;
3057 guint idle_id; /* event source id */
3060 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
3062 GList *list_d = nullptr;
3063 GList *list_f = nullptr;
3067 filelist_read(dir_fd, &list_f, &list_d);
3071 filelist_read(dir_fd, &list_f, nullptr);
3074 list_f = filelist_filter(list_f, FALSE);
3075 list_d = filelist_filter(list_d, TRUE);
3077 kfd->list = g_list_concat(list_f, kfd->list);
3078 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
3081 static void keywords_find_reset(KeywordFindData *kfd)
3083 filelist_free(kfd->list);
3084 kfd->list = nullptr;
3086 filelist_free(kfd->list_dir);
3087 kfd->list_dir = nullptr;
3090 static void keywords_find_close_cb(GenericDialog *, gpointer data)
3092 auto kfd = static_cast<KeywordFindData *>(data);
3094 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
3096 keywords_find_reset(kfd);
3097 generic_dialog_close(kfd->gd);
3101 static void keywords_find_finish(KeywordFindData *kfd)
3103 keywords_find_reset(kfd);
3105 gq_gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
3106 gtk_spinner_stop(GTK_SPINNER(kfd->spinner));
3108 gtk_widget_set_sensitive(kfd->group, TRUE);
3109 gtk_widget_set_sensitive(kfd->button_start, TRUE);
3110 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3111 gtk_widget_set_sensitive(kfd->button_close, TRUE);
3114 static void keywords_find_stop_cb(GenericDialog *, gpointer data)
3116 auto kfd = static_cast<KeywordFindData *>(data);
3118 g_idle_remove_by_data(kfd);
3120 keywords_find_finish(kfd);
3123 static gboolean keywords_find_file(gpointer data)
3125 auto kfd = static_cast<KeywordFindData *>(data);
3127 GtkTextBuffer *buffer;
3135 fd = static_cast<FileData *>(kfd->list->data);
3136 kfd->list = g_list_remove(kfd->list, fd);
3138 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
3139 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3143 gtk_text_buffer_get_end_iter(buffer, &iter);
3144 tmp = g_strconcat(static_cast<const gchar *>(keywords->data), "\n", NULL);
3145 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3147 keywords = keywords->next;
3150 gq_gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
3151 file_data_unref(fd);
3152 g_list_free_full(keywords, g_free);
3154 return (G_SOURCE_CONTINUE);
3161 fd = static_cast<FileData *>(kfd->list_dir->data);
3162 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
3164 keywords_find_folder(kfd, fd);
3166 file_data_unref(fd);
3168 return G_SOURCE_CONTINUE;
3171 keywords_find_finish(kfd);
3173 return G_SOURCE_REMOVE;
3176 static void keywords_find_start_cb(GenericDialog *, gpointer data)
3178 auto kfd = static_cast<KeywordFindData *>(data);
3181 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
3183 path = remove_trailing_slash((gq_gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
3184 parse_out_relatives(path);
3188 warning_dialog(_("Invalid folder"),
3189 _("The specified folder can not be found."),
3190 GQ_ICON_DIALOG_WARNING, kfd->gd->dialog);
3196 gtk_widget_set_sensitive(kfd->group, FALSE);
3197 gtk_widget_set_sensitive(kfd->button_start, FALSE);
3198 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
3199 gtk_widget_set_sensitive(kfd->button_close, FALSE);
3200 gtk_spinner_start(GTK_SPINNER(kfd->spinner));
3202 dir_fd = file_data_new_dir(path);
3203 keywords_find_folder(kfd, dir_fd);
3204 file_data_unref(dir_fd);
3205 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
3211 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
3213 KeywordFindData *kfd;
3217 kfd = g_new0(KeywordFindData, 1);
3219 kfd->gd = generic_dialog_new(_("Search for keywords"),
3220 "search_for_keywords",
3223 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
3224 kfd->gd->cancel_cb = keywords_find_close_cb;
3225 kfd->button_close = generic_dialog_add_button(kfd->gd, GQ_ICON_CLOSE, _("Close"),
3226 keywords_find_close_cb, FALSE);
3227 kfd->button_start = generic_dialog_add_button(kfd->gd, GQ_ICON_OK, _("S_tart"),
3228 keywords_find_start_cb, FALSE);
3229 kfd->button_stop = generic_dialog_add_button(kfd->gd, GQ_ICON_STOP, _("Stop"),
3230 keywords_find_stop_cb, FALSE);
3231 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3233 generic_dialog_add_message(kfd->gd, nullptr, _("Search for keywords"), nullptr, FALSE);
3235 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
3236 pref_spacer(hbox, PREF_PAD_INDENT);
3237 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
3239 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3240 pref_label_new(hbox, _("Folder:"));
3242 label = tab_completion_new(&kfd->entry, path, nullptr, nullptr, nullptr, nullptr);
3243 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
3244 gq_gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
3245 gtk_widget_show(label);
3247 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
3249 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
3250 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3252 kfd->progress = gtk_entry_new();
3253 gtk_widget_set_can_focus(kfd->progress, FALSE);
3254 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
3255 gq_gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
3256 gq_gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
3257 gtk_widget_show(kfd->progress);
3259 kfd->spinner = gtk_spinner_new();
3260 gq_gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
3261 gtk_widget_show(kfd->spinner);
3263 kfd->list = nullptr;
3265 gtk_widget_show(kfd->gd->dialog);
3268 static void keywords_find_cb(GtkWidget *widget, gpointer)
3270 const gchar *path = layout_get_path(nullptr);
3272 if (!path || !*path) path = homedir();
3273 keywords_find_dialog(widget, path);
3276 static void config_tab_keywords_save()
3280 GtkTextBuffer *buffer;
3281 GList *kw_list = nullptr;
3287 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3288 gtk_text_buffer_get_bounds(buffer, &start, &end);
3290 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3292 kw_split = strtok(buffer_text, "\n");
3293 while (kw_split != nullptr)
3299 if (g_strcmp0(static_cast<const gchar *>(work->data), kw_split) == 0)
3308 kw_list = g_list_append(kw_list, g_strdup(kw_split));
3310 kw_split = strtok(nullptr, "\n");
3313 keyword_list_set(kw_list);
3315 g_list_free_full(kw_list, g_free);
3316 g_free(buffer_text);
3319 static void config_tab_keywords(GtkWidget *notebook)
3325 GtkWidget *scrolled;
3327 GtkTextBuffer *buffer;
3330 GspellTextView *gspell_view;
3333 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3335 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3337 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3339 button = pref_button_new(hbox, GQ_ICON_RUN, _("Search"),
3340 G_CALLBACK(keywords_find_cb), keyword_text);
3341 gtk_widget_set_tooltip_text(button, _("Search for existing keywords"));
3344 keyword_text = gtk_text_view_new();
3345 gtk_widget_set_size_request(keyword_text, 20, 20);
3346 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
3347 gq_gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3348 gtk_widget_show(scrolled);
3351 if (options->metadata.check_spelling)
3353 gspell_view = gspell_text_view_get_from_gtk_text_view(GTK_TEXT_VIEW(keyword_text));
3354 gspell_text_view_basic_setup(gspell_view);
3358 gq_gtk_container_add(GTK_WIDGET(scrolled), keyword_text);
3359 gtk_widget_show(keyword_text);
3361 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3363 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3364 gtk_text_buffer_create_tag(buffer, "monospace",
3365 "family", "monospace", NULL);
3367 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3368 gtk_text_buffer_get_start_iter(buffer, &iter);
3369 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3372 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3374 GList *kwl = keyword_list_get();
3375 kwl = g_list_first(kwl);
3378 gtk_text_buffer_get_end_iter (buffer, &iter);
3379 tmp = g_strconcat(static_cast<const gchar *>(kwl->data), "\n", NULL);
3380 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3385 gtk_text_buffer_set_modified(buffer, FALSE);
3392 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3394 auto option = static_cast<gint *>(data);
3396 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3400 *option = INTENT_PERCEPTUAL;
3403 *option = INTENT_RELATIVE_COLORIMETRIC;
3406 *option = INTENT_SATURATION;
3409 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3414 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3415 gint option, gint *option_c)
3422 pref_table_label(table, column, row, text, GTK_ALIGN_START);
3424 combo = gtk_combo_box_text_new();
3426 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3427 if (option == INTENT_PERCEPTUAL) current = 0;
3428 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3429 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3430 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3431 if (option == INTENT_SATURATION) current = 2;
3432 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3433 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3435 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3437 gtk_widget_set_tooltip_text(combo,_("Refer to the lcms documentation for the defaults used when the selected Intent is not available"));
3439 g_signal_connect(G_OBJECT(combo), "changed",
3440 G_CALLBACK(intent_menu_cb), option_c);
3442 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
3443 gtk_widget_show(combo);
3447 static void config_tab_color(GtkWidget *notebook)
3456 vbox = scrolled_notebook_page(notebook, _("Color management"));
3458 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3460 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3463 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3464 gtk_grid_set_column_spacing(GTK_GRID(table), PREF_PAD_GAP);
3466 label = pref_table_label(table, 0, 0, _("Type"), GTK_ALIGN_START);
3467 pref_label_bold(label, TRUE, FALSE);
3469 label = pref_table_label(table, 1, 0, _("Menu name"), GTK_ALIGN_START);
3470 pref_label_bold(label, TRUE, FALSE);
3472 label = pref_table_label(table, 2, 0, _("File"), GTK_ALIGN_START);
3473 pref_label_bold(label, TRUE, FALSE);
3475 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3480 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3481 pref_table_label(table, 0, i + 1, buf, GTK_ALIGN_END);
3484 entry = gtk_entry_new();
3485 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3486 if (options->color_profile.input_name[i])
3488 gq_gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3490 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);
3491 gtk_widget_show(entry);
3492 color_profile_input_name_entry[i] = entry;
3494 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], nullptr, ".icc", "ICC Files", nullptr);
3495 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3496 gtk_widget_set_size_request(entry, 160, -1);
3497 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);
3498 gtk_widget_show(tabcomp);
3499 color_profile_input_file_entry[i] = entry;
3502 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3504 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3506 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3507 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3509 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3511 pref_table_label(table, 0, 0, _("Screen:"), GTK_ALIGN_END);
3512 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3513 options->color_profile.screen_file, nullptr, ".icc", "ICC Files", nullptr);
3514 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3515 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3517 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3519 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);
3521 gtk_widget_show(tabcomp);
3524 /* advanced entry tab */
3525 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer)
3527 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3529 c_options->file_ops.use_system_trash = FALSE;
3530 c_options->file_ops.no_trash = FALSE;
3534 static void use_system_trash_cb(GtkWidget *widget, gpointer)
3536 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3538 c_options->file_ops.use_system_trash = TRUE;
3539 c_options->file_ops.no_trash = FALSE;
3543 static void use_no_cache_cb(GtkWidget *widget, gpointer)
3545 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3547 c_options->file_ops.no_trash = TRUE;
3551 static void config_tab_behavior(GtkWidget *notebook)
3558 GtkWidget *ct_button;
3562 GtkWidget *with_rename;
3563 GtkWidget *collections_on_top;
3564 GtkWidget *hide_window_in_fullscreen;
3565 GtkWidget *hide_osd_in_fullscreen;
3566 GtkWidget *checkbox;
3569 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3571 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3573 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3574 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3575 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3576 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3577 pref_checkbox_new_int(group, _("Enable Delete key"),
3578 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3580 ct_button = pref_radiobutton_new(group, nullptr, _("Use Geeqie trash location"),
3581 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),nullptr);
3583 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3584 pref_checkbox_link_sensitivity(ct_button, hbox);
3586 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3587 pref_label_new(hbox, _("Folder:"));
3589 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, nullptr, nullptr, nullptr, nullptr);
3590 tab_completion_add_select_button(safe_delete_path_entry, nullptr, TRUE);
3591 gq_gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3592 gtk_widget_show(tabcomp);
3594 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3595 pref_checkbox_link_sensitivity(ct_button, hbox);
3597 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3598 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MiB"),
3599 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3600 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3601 button = pref_button_new(nullptr, nullptr, _("View"),
3602 G_CALLBACK(safe_delete_view_cb), nullptr);
3603 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3604 gtk_widget_show(button);
3606 button = pref_button_new(nullptr, GQ_ICON_CLEAR, nullptr,
3607 G_CALLBACK(safe_delete_clear_cb), nullptr);
3608 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3610 c_options->file_ops.no_trash = options->file_ops.no_trash;
3611 c_options->file_ops.use_system_trash = options->file_ops.use_system_trash;
3613 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3614 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), nullptr);
3616 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3617 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), nullptr);
3619 gtk_widget_show(button);
3621 pref_spacer(group, PREF_PAD_GROUP);
3624 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3626 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3627 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3629 pref_checkbox_new_int(group, _("In place renaming"),
3630 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3632 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3633 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3635 tmp = pref_checkbox_new_int(group, _("Circular selection lists"),
3636 options->circular_selection_lists, &c_options->circular_selection_lists);
3637 gtk_widget_set_tooltip_text(tmp, _("Traverse selection lists in a circular manner"));
3639 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3640 options->marks_save, &c_options->marks_save);
3641 gtk_widget_set_tooltip_text(marks,_("Note that marks linked to a keyword will be saved irrespective of this setting"));
3643 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3644 options->with_rename, &c_options->with_rename);
3645 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3647 collections_on_top = pref_checkbox_new_int(group, _("Permit duplicates in Collections"),
3648 options->collections_duplicates, &c_options->collections_duplicates);
3649 gtk_widget_set_tooltip_text(collections_on_top, _("Allow the same image to be in a Collection more than once"));
3651 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3652 options->collections_on_top, &c_options->collections_on_top);
3653 gtk_widget_set_tooltip_text(collections_on_top, _("Open collections window on top"));
3655 hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3656 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3657 gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice");
3659 hide_osd_in_fullscreen = pref_checkbox_new_int(group, _("Hide OSD in fullscreen"),
3660 options->hide_osd_in_fullscreen, &c_options->hide_osd_in_fullscreen);
3661 gtk_widget_set_tooltip_text(hide_osd_in_fullscreen,"Hide Overlay Screen Display in fullscreen mode");
3663 pref_spin_new_int(group, _("Recent folder list maximum size"), nullptr,
3664 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3666 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);
3667 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."));
3669 pref_spin_new_int(group, _("Drag'n drop icon size"), nullptr,
3670 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3672 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3673 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3675 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3676 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3678 pref_spacer(group, PREF_PAD_GROUP);
3680 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3682 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3683 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3684 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), nullptr,
3685 1, 32, 1, options->keyboard_scroll_step, reinterpret_cast<int *>(&c_options->keyboard_scroll_step));
3686 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3687 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3688 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3689 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3690 pref_checkbox_new_int(group, _("Open archive by left click on image"),
3691 options->image_l_click_archive, &c_options->image_l_click_archive);
3692 pref_checkbox_new_int(group, _("Play video by left click on image"),
3693 options->image_l_click_video, &c_options->image_l_click_video);
3694 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3695 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3697 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3698 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3699 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3700 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3701 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3703 pref_spacer(group, PREF_PAD_GROUP);
3705 group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3707 checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3708 options->override_disable_gpu, &c_options->override_disable_gpu);
3709 gtk_widget_set_tooltip_text(checkbox, _("Contact the developers for usage"));
3712 pref_spacer(group, PREF_PAD_GROUP);
3714 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3716 pref_spin_new_int(group, _("Debug level:"), nullptr,
3717 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3719 pref_checkbox_new_int(group, _("Timer data"),
3720 options->log_window.timer_data, &c_options->log_window.timer_data);
3722 pref_spin_new_int(group, _("Log Window max. lines:"), nullptr,
3723 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3725 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3726 pref_label_new(hbox, _("Log Window F1 command: "));
3727 log_window_f1_entry = gtk_entry_new();
3728 gq_gtk_entry_set_text(GTK_ENTRY(log_window_f1_entry), options->log_window.action);
3729 gq_gtk_box_pack_start(GTK_BOX(hbox), log_window_f1_entry, FALSE, FALSE, 0);
3730 gtk_entry_set_width_chars(GTK_ENTRY(log_window_f1_entry), 15);
3731 gtk_widget_show(log_window_f1_entry);
3735 /* accelerators tab */
3737 static gboolean accel_search_function_cb(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer)
3739 gboolean ret = TRUE;
3744 gtk_tree_model_get(model, iter, column, &text, -1);
3745 text_nocase = g_utf8_casefold(text, -1);
3746 key_nocase = g_utf8_casefold(key, -1);
3748 if (g_strstr_len(text_nocase, -1, key_nocase))
3755 g_free(text_nocase);
3760 static void accel_row_activated_cb(GtkTreeView *tree_view, GtkTreePath *, GtkTreeViewColumn *column, gpointer)
3765 list = gtk_tree_view_get_columns(tree_view);
3766 col_num = g_list_index(list, column);
3770 gtk_tree_view_set_search_column(tree_view, col_num);
3773 static void config_tab_accelerators(GtkWidget *notebook)
3779 GtkWidget *scrolled;
3780 GtkWidget *accel_view;
3781 GtkCellRenderer *renderer;
3782 GtkTreeSelection *selection;
3783 GtkTreeViewColumn *column;
3785 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3787 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3789 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
3790 gq_gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3791 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3792 gq_gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3793 gtk_widget_show(scrolled);
3795 accel_store = gtk_tree_store_new(5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3797 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3798 g_object_unref(accel_store);
3799 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3800 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3802 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3804 renderer = gtk_cell_renderer_text_new();
3806 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3811 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3812 gtk_tree_view_column_set_resizable(column, TRUE);
3813 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3816 renderer = gtk_cell_renderer_accel_new();
3817 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3818 G_CALLBACK(accel_store_cleared_cb), accel_store);
3819 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3820 G_CALLBACK(accel_store_edited_cb), accel_store);
3823 g_object_set (renderer,
3825 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3828 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3833 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3834 gtk_tree_view_column_set_resizable(column, TRUE);
3835 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3837 renderer = gtk_cell_renderer_text_new();
3839 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3844 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3845 gtk_tree_view_column_set_resizable(column, TRUE);
3846 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3848 renderer = gtk_cell_renderer_text_new();
3850 column = gtk_tree_view_column_new_with_attributes("Accel",
3855 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3856 gtk_tree_view_column_set_resizable(column, TRUE);
3857 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3859 column = gtk_tree_view_column_new_with_attributes("Icon",
3864 gtk_tree_view_column_set_sort_column_id(column, AE_ICON);
3865 gtk_tree_view_column_set_resizable(column, TRUE);
3866 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3868 /* Search on text in column */
3869 gtk_tree_view_set_activate_on_single_click(GTK_TREE_VIEW(accel_view), TRUE);
3870 g_signal_connect(accel_view, "row_activated", G_CALLBACK(accel_row_activated_cb), accel_store);
3871 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), TRUE);
3872 gtk_tree_view_set_search_column(GTK_TREE_VIEW(accel_view), AE_TOOLTIP);
3873 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(accel_view), accel_search_function_cb, nullptr, nullptr);
3875 accel_store_populate();
3876 gq_gtk_container_add(GTK_WIDGET(scrolled), accel_view);
3877 gtk_widget_show(accel_view);
3879 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3881 button = pref_button_new(nullptr, nullptr, _("Defaults"),
3882 G_CALLBACK(accel_default_cb), accel_view);
3883 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3884 gtk_widget_show(button);
3886 button = pref_button_new(nullptr, nullptr, _("Reset selected"),
3887 G_CALLBACK(accel_reset_cb), accel_view);
3888 gtk_widget_set_tooltip_text(button, _("Will only reset changes made before the settings are saved"));
3889 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3890 gtk_widget_show(button);
3892 button = pref_button_new(nullptr, nullptr, _("Clear selected"),
3893 G_CALLBACK(accel_clear_cb), accel_view);
3894 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3895 gtk_widget_show(button);
3898 /* toolbar main tab */
3899 static void config_tab_toolbar_main(GtkWidget *notebook)
3902 GtkWidget *toolbardata;
3905 lw = static_cast<LayoutWindow *>(layout_window_list->data);
3907 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3909 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3910 gq_gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3911 gtk_widget_show(vbox);
3914 /* toolbar status tab */
3915 static void config_tab_toolbar_status(GtkWidget *notebook)
3918 GtkWidget *toolbardata;
3921 lw = static_cast<LayoutWindow *>(layout_window_list->data);
3923 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3925 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3926 gq_gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3927 gtk_widget_show(vbox);
3931 static gint extension_sort_cb(gconstpointer a, gconstpointer b)
3933 return g_strcmp0(static_cast<const gchar *>(a), static_cast<const gchar *>(b));
3936 static void config_tab_advanced(GtkWidget *notebook)
3939 GdkPixbufFormat *fm;
3941 GList *extensions_list = nullptr;
3942 GSList *formats_list;
3943 GString *types_string = g_string_new(nullptr);
3944 GtkWidget *alternate_checkbox;
3945 GtkWidget *dupes_threads_spin;
3947 GtkWidget *subgroup;
3949 GtkWidget *threads_string_label;
3950 GtkWidget *types_string_label;
3953 vbox = scrolled_notebook_page(notebook, _("Advanced"));
3954 group = pref_group_new(vbox, FALSE, _("External preview extraction"), GTK_ORIENTATION_VERTICAL);
3956 pref_checkbox_new_int(group, _("Use external preview extraction - Requires restart"), options->external_preview.enable, &c_options->external_preview.enable);
3958 pref_spacer(group, PREF_PAD_GROUP);
3960 formats_list = gdk_pixbuf_get_formats();
3962 while (formats_list)
3964 fm = static_cast<GdkPixbufFormat *>(formats_list->data);
3965 extensions = gdk_pixbuf_format_get_extensions(fm);
3968 while (extensions[i])
3970 extensions_list = g_list_insert_sorted(extensions_list, g_strdup(extensions[i]), extension_sort_cb);
3974 g_strfreev(extensions);
3975 formats_list = formats_list->next;
3978 while (extensions_list)
3980 if (types_string->len == 0)
3982 types_string = g_string_append(types_string, static_cast<const gchar *>(extensions_list->data));
3986 types_string = g_string_append(types_string, ", ");
3987 types_string = g_string_append(types_string, static_cast<const gchar *>(extensions_list->data));
3990 extensions_list = extensions_list->next;
3993 types_string = g_string_prepend(types_string, _("Usable file types:\n"));
3994 types_string_label = pref_label_new(group, types_string->str);
3995 gtk_label_set_line_wrap(GTK_LABEL(types_string_label), TRUE);
3997 pref_spacer(group, PREF_PAD_GROUP);
3999 group = pref_group_new(vbox, FALSE, _("File identification tool"), GTK_ORIENTATION_VERTICAL);
4000 external_preview_select_entry = gtk_entry_new();
4001 tabcomp = tab_completion_new(&external_preview_select_entry, options->external_preview.select, nullptr, nullptr, nullptr, nullptr);
4002 tab_completion_add_select_button(external_preview_select_entry, _("Select file identification tool"), FALSE);
4003 gq_gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
4004 gtk_widget_show(tabcomp);
4006 group = pref_group_new(vbox, FALSE, _("Preview extraction tool"), GTK_ORIENTATION_VERTICAL);
4007 external_preview_extract_entry = gtk_entry_new();
4008 tabcomp = tab_completion_new(&external_preview_extract_entry, options->external_preview.extract, nullptr, nullptr, nullptr, nullptr);
4009 tab_completion_add_select_button(external_preview_extract_entry, _("Select preview extraction tool"), FALSE);
4010 gq_gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
4011 gtk_widget_show(tabcomp);
4013 gtk_widget_show(vbox);
4015 g_slist_free(formats_list);
4016 g_list_free_full(extensions_list, g_free);
4017 g_string_free(types_string, TRUE);
4019 pref_spacer(group, PREF_PAD_GROUP);
4021 pref_line(vbox, PREF_PAD_SPACE);
4022 group = pref_group_new(vbox, FALSE, _("Thread pool limits"), GTK_ORIENTATION_VERTICAL);
4024 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."));
4025 gtk_label_set_line_wrap(GTK_LABEL(threads_string_label), TRUE);
4027 pref_spacer(vbox, PREF_PAD_GROUP);
4029 dupes_threads_spin = pref_spin_new_int(vbox, _("Duplicate check:"), _("max. threads"), 0, get_cpu_cores(), 1, options->threads.duplicates, &c_options->threads.duplicates);
4030 gtk_widget_set_tooltip_markup(dupes_threads_spin, _("Set to 0 for unlimited"));
4032 pref_spacer(group, PREF_PAD_GROUP);
4034 pref_line(vbox, PREF_PAD_SPACE);
4036 group = pref_group_new(vbox, FALSE, _("Alternate similarity alogorithm"), GTK_ORIENTATION_VERTICAL);
4038 alternate_checkbox = pref_checkbox_new_int(group, _("Enable alternate similarity algorithm"), options->alternate_similarity_algorithm.enabled, &c_options->alternate_similarity_algorithm.enabled);
4040 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
4041 pref_checkbox_link_sensitivity(alternate_checkbox, subgroup);
4043 alternate_checkbox = pref_checkbox_new_int(subgroup, _("Use grayscale"), options->alternate_similarity_algorithm.grayscale, &c_options->alternate_similarity_algorithm.grayscale);
4044 gtk_widget_set_tooltip_text(alternate_checkbox, _("Reduce fingerprint to grayscale"));
4048 static void config_tab_stereo(GtkWidget *notebook)
4056 GtkWidget *fs_button;
4057 vbox = scrolled_notebook_page(notebook, _("Stereo"));
4059 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
4061 table = pref_table_new(group, 2, 1, FALSE, FALSE);
4062 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
4064 table = pref_table_new(group, 2, 2, TRUE, FALSE);
4065 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
4066 pref_checkbox_new_int(box, _("Mirror left image"),
4067 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
4068 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
4069 pref_checkbox_new_int(box, _("Flip left image"),
4070 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
4071 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
4072 pref_checkbox_new_int(box, _("Mirror right image"),
4073 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
4074 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
4075 pref_checkbox_new_int(box, _("Flip right image"),
4076 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
4077 pref_checkbox_new_int(group, _("Swap left and right images"),
4078 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
4079 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
4080 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
4082 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
4083 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
4084 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
4085 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
4086 pref_checkbox_link_sensitivity(fs_button, box2);
4087 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
4088 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
4089 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
4090 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
4091 pref_checkbox_new_int(box, _("Mirror left image"),
4092 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
4093 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
4094 pref_checkbox_new_int(box, _("Flip left image"),
4095 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
4096 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
4097 pref_checkbox_new_int(box, _("Mirror right image"),
4098 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
4099 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
4100 pref_checkbox_new_int(box, _("Flip right image"),
4101 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
4102 pref_checkbox_new_int(box2, _("Swap left and right images"),
4103 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
4104 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
4105 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
4107 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
4108 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
4109 pref_table_spin_new_int(table, 0, 0, _("Width"), nullptr,
4110 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
4111 pref_table_spin_new_int(table, 3, 0, _("Height"), nullptr,
4112 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
4113 pref_table_spin_new_int(table, 0, 1, _("Left X"), nullptr,
4114 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
4115 pref_table_spin_new_int(table, 3, 1, _("Left Y"), nullptr,
4116 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
4117 pref_table_spin_new_int(table, 0, 2, _("Right X"), nullptr,
4118 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
4119 pref_table_spin_new_int(table, 3, 2, _("Right Y"), nullptr,
4120 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
4124 /* Main preferences window */
4125 static void config_window_create(LayoutWindow *lw)
4127 GtkWidget *win_vbox;
4129 GtkWidget *notebook;
4131 GtkWidget *ct_button;
4133 if (!c_options) c_options = init_options(nullptr);
4135 configwindow = window_new("preferences", PIXBUF_INLINE_ICON_CONFIG, nullptr, _("Preferences"));
4136 DEBUG_NAME(configwindow);
4137 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
4138 g_signal_connect(G_OBJECT(configwindow), "delete_event",
4139 G_CALLBACK(config_window_delete), NULL);
4140 if (options->save_dialog_window_positions)
4142 gtk_window_resize(GTK_WINDOW(configwindow), lw->options.preferences_window.w, lw->options.preferences_window.h);
4143 gq_gtk_window_move(GTK_WINDOW(configwindow), lw->options.preferences_window.x, lw->options.preferences_window.y);
4147 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
4149 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
4150 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
4152 win_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
4153 gq_gtk_container_add(GTK_WIDGET(configwindow), win_vbox);
4154 gtk_widget_show(win_vbox);
4156 notebook = gtk_notebook_new();
4157 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
4158 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
4159 gq_gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
4161 config_tab_general(notebook);
4162 config_tab_image(notebook);
4163 config_tab_osd(notebook);
4164 config_tab_windows(notebook);
4165 config_tab_accelerators(notebook);
4166 config_tab_files(notebook);
4167 config_tab_metadata(notebook);
4168 config_tab_keywords(notebook);
4169 config_tab_color(notebook);
4170 config_tab_stereo(notebook);
4171 config_tab_behavior(notebook);
4172 config_tab_toolbar_main(notebook);
4173 config_tab_toolbar_status(notebook);
4174 config_tab_advanced(notebook);
4176 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), lw->options.preferences_window.page_number);
4178 hbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
4179 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
4180 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
4181 gq_gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
4182 gtk_widget_show(hbox);
4184 button = pref_button_new(nullptr, GQ_ICON_HELP, _("Help"),
4185 G_CALLBACK(config_window_help_cb), notebook);
4186 gq_gtk_container_add(GTK_WIDGET(hbox), button);
4187 gtk_widget_set_can_default(button, TRUE);
4188 gtk_widget_show(button);
4190 button = pref_button_new(nullptr, GQ_ICON_OK, "OK",
4191 G_CALLBACK(config_window_ok_cb), notebook);
4192 gq_gtk_container_add(GTK_WIDGET(hbox), button);
4193 gtk_widget_set_can_default(button, TRUE);
4194 gtk_widget_grab_default(button);
4195 gtk_widget_show(button);
4199 button = pref_button_new(nullptr, GQ_ICON_CANCEL, _("Cancel"),
4200 G_CALLBACK(config_window_close_cb), nullptr);
4201 gq_gtk_container_add(GTK_WIDGET(hbox), button);
4202 gtk_widget_set_can_default(button, TRUE);
4203 gtk_widget_show(button);
4205 if (!generic_dialog_get_alternative_button_order(configwindow))
4207 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
4210 gtk_widget_show(notebook);
4212 gtk_widget_show(configwindow);
4216 *-----------------------------------------------------------------------------
4217 * config window show (public)
4218 *-----------------------------------------------------------------------------
4221 void show_config_window(LayoutWindow *lw)
4225 gtk_window_present(GTK_WINDOW(configwindow));
4229 config_window_create(lw);
4238 void show_about_window(LayoutWindow *lw)
4240 GDataInputStream *data_stream;
4241 GInputStream *in_stream_authors;
4242 GInputStream *in_stream_translators;
4244 GdkPixbuf *pixbuf_icon;
4245 GdkPixbuf *pixbuf_logo;
4249 gchar *authors[1000];
4251 gchar *timezone_path;
4260 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"));
4262 timezone_path = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
4263 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
4265 cd = ZDOpenDatabase(timezone_path);
4268 copyright = g_string_append(copyright, ZDGetNotice(cd));
4272 log_printf("Error: Init of timezone database %s failed\n", timezone_path);
4274 ZDCloseDatabase(cd);
4276 g_free(timezone_path);
4278 copyright = g_string_append(copyright, _("\n\nSome icons by https://www.flaticon.com"));
4280 in_stream_authors = g_resources_open_stream(GQ_RESOURCE_PATH_CREDITS "/authors", G_RESOURCE_LOOKUP_FLAGS_NONE, nullptr);
4282 data_stream = g_data_input_stream_new(in_stream_authors);
4284 authors[0] = nullptr;
4285 while ((author_line = g_data_input_stream_read_line(G_DATA_INPUT_STREAM(data_stream), &length, nullptr, nullptr)))
4287 authors[i_authors] = g_strdup(author_line);
4289 g_free(author_line);
4291 authors[i_authors] = nullptr;
4293 g_input_stream_close(in_stream_authors, nullptr, nullptr);
4295 constexpr auto translators_path = GQ_RESOURCE_PATH_CREDITS "/translators";
4297 g_resources_get_info(translators_path, G_RESOURCE_LOOKUP_FLAGS_NONE, &size, &flags, nullptr);
4299 in_stream_translators = g_resources_open_stream(translators_path, G_RESOURCE_LOOKUP_FLAGS_NONE, nullptr);
4300 translators = static_cast<gchar *>(g_malloc0(size));
4301 g_input_stream_read_all(in_stream_translators, translators, size, &bytes_read, nullptr, nullptr);
4302 g_input_stream_close(in_stream_translators, nullptr, nullptr);
4304 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);
4306 artists[0] = g_strdup("Néstor Díaz Valencia <nestor@estudionexos.com>");
4307 artists[1] = nullptr;
4309 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
4310 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
4311 gtk_show_about_dialog(GTK_WINDOW(lw->window),
4312 "title", _("About Geeqie"),
4314 "program-name", GQ_APPNAME,
4316 "logo", pixbuf_logo,
4317 "icon", pixbuf_icon,
4318 "website", GQ_WEBSITE,
4319 "website-label", _("Website"),
4320 "comments", comment,
4323 "translator-credits", translators,
4324 "wrap-license", TRUE,
4325 "license", copyright->str,
4328 g_string_free(copyright, TRUE);
4330 while(n < i_authors)
4338 g_free(translators);
4339 g_object_unref(data_stream);
4340 g_object_unref(in_stream_authors);
4341 g_object_unref(in_stream_translators);
4344 static void image_overlay_set_text_colors()
4346 c_options->image_overlay.text_red = options->image_overlay.text_red;
4347 c_options->image_overlay.text_green = options->image_overlay.text_green;
4348 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
4349 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
4350 c_options->image_overlay.background_red = options->image_overlay.background_red;
4351 c_options->image_overlay.background_green = options->image_overlay.background_green;
4352 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
4353 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
4357 *-----------------------------------------------------------------------------
4358 * timezone database routines
4359 *-----------------------------------------------------------------------------
4362 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
4364 GError *error = nullptr;
4365 auto tz = static_cast<TZData *>(data);
4366 gchar *tmp_filename;
4367 gchar *timezone_bin;
4368 gchar *tmp_dir = nullptr;
4371 if (!g_cancellable_is_cancelled(tz->cancellable))
4373 generic_dialog_close(tz->gd);
4377 if (g_file_copy_finish(G_FILE(source_object), res, &error))
4379 tmp_filename = g_file_get_path(tz->tmp_g_file);
4380 fd = file_data_new_simple(tmp_filename);
4381 tmp_dir = open_archive(fd);
4385 timezone_bin = g_build_filename(tmp_dir, TIMEZONE_DATABASE_VERSION, TIMEZONE_DATABASE_FILE, NULL);
4386 if (isfile(timezone_bin))
4388 move_file(timezone_bin, tz->timezone_database_user);
4392 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GQ_ICON_DIALOG_WARNING, nullptr);
4395 g_free(timezone_bin);
4396 g_free(tmp_dir); // The folder in /tmp is deleted in exit_program_final()
4400 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GQ_ICON_DIALOG_WARNING, nullptr);
4402 g_free(tmp_filename);
4403 file_data_unref(fd);
4407 file_util_warning_dialog(_("Error: Timezone database download failed"), error->message, GQ_ICON_DIALOG_ERROR, nullptr);
4410 g_file_delete(tz->tmp_g_file, nullptr, &error);
4411 g_object_unref(tz->tmp_g_file);
4412 tz->tmp_g_file = nullptr;
4413 g_object_unref(tz->cancellable);
4414 g_object_unref(tz->timezone_database_gq);
4417 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
4419 auto tz = static_cast<TZData *>(data);
4421 if (!g_cancellable_is_cancelled(tz->cancellable))
4423 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), static_cast<gdouble>(current_num_bytes) / total_num_bytes);
4427 static void timezone_cancel_button_cb(GenericDialog *, gpointer data)
4429 auto tz = static_cast<TZData *>(data);
4431 g_cancellable_cancel(tz->cancellable);
4434 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
4436 auto tz = static_cast<TZData *>(data);
4437 GError *error = nullptr;
4438 GFileIOStream *io_stream;
4445 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
4449 file_util_warning_dialog(_("Timezone database download failed"), error->message, GQ_ICON_DIALOG_ERROR, nullptr);
4450 log_printf("Error: Download timezone database failed:\n%s", error->message);
4451 g_error_free(error);
4452 g_object_unref(tz->tmp_g_file);
4456 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE_WEB);
4458 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", nullptr, TRUE, timezone_cancel_button_cb, tz);
4460 generic_dialog_add_message(tz->gd, GQ_ICON_DIALOG_INFO, _("Downloading timezone database"), nullptr, FALSE);
4462 tz->progress = gtk_progress_bar_new();
4463 gq_gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
4464 gtk_widget_show(tz->progress);
4466 gtk_widget_show(tz->gd->dialog);
4467 tz->cancellable = g_cancellable_new();
4468 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);
4470 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
4473 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */