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->show_window_ids = c_options->show_window_ids;
328 options->image.scroll_reset_method = c_options->image.scroll_reset_method;
329 options->image.zoom_2pass = c_options->image.zoom_2pass;
330 options->image.fit_window_to_image = c_options->image.fit_window_to_image;
331 options->image.limit_window_size = c_options->image.limit_window_size;
332 options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
333 options->image.max_window_size = c_options->image.max_window_size;
334 options->image.limit_autofit_size = c_options->image.limit_autofit_size;
335 options->image.max_autofit_size = c_options->image.max_autofit_size;
336 options->image.max_enlargement_size = c_options->image.max_enlargement_size;
337 options->image.tile_size = c_options->image.tile_size;
338 options->progressive_key_scrolling = c_options->progressive_key_scrolling;
339 options->keyboard_scroll_step = c_options->keyboard_scroll_step;
341 if (options->thumbnails.max_width != c_options->thumbnails.max_width
342 || options->thumbnails.max_height != c_options->thumbnails.max_height
343 || options->thumbnails.quality != c_options->thumbnails.quality)
345 thumb_format_changed = TRUE;
347 options->thumbnails.max_width = c_options->thumbnails.max_width;
348 options->thumbnails.max_height = c_options->thumbnails.max_height;
349 options->thumbnails.quality = c_options->thumbnails.quality;
351 options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
352 options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
353 options->thumbnails.use_exif = c_options->thumbnails.use_exif;
354 options->thumbnails.use_color_management = c_options->thumbnails.use_color_management;
355 options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
356 options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
357 options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
358 options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
359 options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
360 options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
361 options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
362 options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
364 options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
365 options->file_filter.disable = c_options->file_filter.disable;
367 config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, nullptr);
368 sidecar_ext_parse(options->sidecar.ext);
370 options->slideshow.random = c_options->slideshow.random;
371 options->slideshow.repeat = c_options->slideshow.repeat;
372 options->slideshow.delay = c_options->slideshow.delay;
374 options->mousewheel_scrolls = c_options->mousewheel_scrolls;
375 options->image_lm_click_nav = c_options->image_lm_click_nav;
376 options->image_l_click_archive = c_options->image_l_click_archive;
377 options->image_l_click_video = c_options->image_l_click_video;
378 options->image_l_click_video_editor = c_options->image_l_click_video_editor;
380 options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
382 options->image.tile_cache_max = c_options->image.tile_cache_max;
383 options->image.image_cache_max = c_options->image.image_cache_max;
385 options->image.zoom_quality = c_options->image.zoom_quality;
387 options->image.zoom_increment = c_options->image.zoom_increment;
389 options->image.zoom_style = c_options->image.zoom_style;
391 options->image.enable_read_ahead = c_options->image.enable_read_ahead;
393 options->appimage_notifications = c_options->appimage_notifications;
396 if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
397 || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
398 || !gdk_rgba_equal(&options->image.border_color, &c_options->image.border_color))
400 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
401 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
402 options->image.border_color = c_options->image.border_color;
403 layout_colors_update();
404 view_window_colors_update();
407 options->image.alpha_color_1 = c_options->image.alpha_color_1;
408 options->image.alpha_color_2 = c_options->image.alpha_color_2;
410 options->fullscreen.screen = c_options->fullscreen.screen;
411 options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
412 options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
413 options->fullscreen.above = c_options->fullscreen.above;
414 if (c_options->image_overlay.template_string)
415 set_image_overlay_template_string(&options->image_overlay.template_string,
416 c_options->image_overlay.template_string);
417 if (c_options->image_overlay.font)
418 set_image_overlay_font_string(&options->image_overlay.font,
419 c_options->image_overlay.font);
420 options->image_overlay.text_red = c_options->image_overlay.text_red;
421 options->image_overlay.text_green = c_options->image_overlay.text_green;
422 options->image_overlay.text_blue = c_options->image_overlay.text_blue;
423 options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
424 options->image_overlay.background_red = c_options->image_overlay.background_red;
425 options->image_overlay.background_green = c_options->image_overlay.background_green;
426 options->image_overlay.background_blue = c_options->image_overlay.background_blue;
427 options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
428 options->image_overlay.font = c_options->image_overlay.font;
429 options->update_on_time_change = c_options->update_on_time_change;
431 options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
432 options->rot_invariant_sim = c_options->rot_invariant_sim;
434 options->tree_descend_subdirs = c_options->tree_descend_subdirs;
436 options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
437 options->circular_selection_lists = c_options->circular_selection_lists;
439 options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
440 options->recent_folder_image_list_maxsize = c_options->recent_folder_image_list_maxsize;
441 options->dnd_icon_size = c_options->dnd_icon_size;
442 options->clipboard_selection = c_options->clipboard_selection;
443 options->dnd_default_action = c_options->dnd_default_action;
445 options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
446 options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
447 options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
448 options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
449 options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
450 options->metadata.confirm_write = c_options->metadata.confirm_write;
451 options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
452 options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
453 options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
454 options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
455 options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
456 options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
457 options->metadata.write_orientation = c_options->metadata.write_orientation;
458 options->metadata.check_spelling = c_options->metadata.check_spelling;
459 options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
460 (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
461 (c_options->stereo.tmp.flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
462 (c_options->stereo.tmp.mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
463 (c_options->stereo.tmp.flip_left ? PR_STEREO_FLIP_LEFT : 0) |
464 (c_options->stereo.tmp.swap ? PR_STEREO_SWAP : 0) |
465 (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
466 options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
467 (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
468 (c_options->stereo.tmp.fs_flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
469 (c_options->stereo.tmp.fs_mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
470 (c_options->stereo.tmp.fs_flip_left ? PR_STEREO_FLIP_LEFT : 0) |
471 (c_options->stereo.tmp.fs_swap ? PR_STEREO_SWAP : 0) |
472 (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
473 options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
474 options->stereo.fixed_w = c_options->stereo.fixed_w;
475 options->stereo.fixed_h = c_options->stereo.fixed_h;
476 options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
477 options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
478 options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
479 options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
481 options->info_keywords.height = c_options->info_keywords.height;
482 options->info_title.height = c_options->info_title.height;
483 options->info_comment.height = c_options->info_comment.height;
484 options->info_rating.height = c_options->info_rating.height;
486 options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
487 options->expand_menu_toolbar = c_options->expand_menu_toolbar;
488 options->hamburger_menu = c_options->hamburger_menu;
490 options->selectable_bars.menu_bar = c_options->selectable_bars.menu_bar;
491 options->selectable_bars.tool_bar = c_options->selectable_bars.tool_bar;
492 options->selectable_bars.status_bar = c_options->selectable_bars.status_bar;
494 options->marks_save = c_options->marks_save;
495 options->with_rename = c_options->with_rename;
496 options->collections_duplicates = c_options->collections_duplicates;
497 options->collections_on_top = c_options->collections_on_top;
498 options->hide_window_in_fullscreen = c_options->hide_window_in_fullscreen;
499 options->hide_osd_in_fullscreen = c_options->hide_osd_in_fullscreen;
500 config_entry_to_option(help_search_engine_entry, &options->help_search_engine, nullptr);
502 options->external_preview.enable = c_options->external_preview.enable;
503 config_entry_to_option(external_preview_select_entry, &options->external_preview.select, nullptr);
504 config_entry_to_option(external_preview_extract_entry, &options->external_preview.extract, nullptr);
506 options->read_metadata_in_idle = c_options->read_metadata_in_idle;
508 options->star_rating.star = c_options->star_rating.star;
509 options->star_rating.rejected = c_options->star_rating.rejected;
511 options->threads.duplicates = c_options->threads.duplicates > 0 ? c_options->threads.duplicates : -1;
513 options->alternate_similarity_algorithm.enabled = c_options->alternate_similarity_algorithm.enabled;
514 options->alternate_similarity_algorithm.grayscale = c_options->alternate_similarity_algorithm.grayscale;
517 set_debug_level(debug_c);
518 config_entry_to_option(log_window_f1_entry, &options->log_window.action, nullptr);
522 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
524 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], nullptr);
525 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], nullptr);
527 config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, nullptr);
528 options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
529 if (options->color_profile.render_intent != c_options->color_profile.render_intent)
531 options->color_profile.render_intent = c_options->color_profile.render_intent;
536 options->mouse_button_8 = c_options->mouse_button_8;
537 options->mouse_button_9 = c_options->mouse_button_9;
539 options->override_disable_gpu = c_options->override_disable_gpu;
541 config_tab_keywords_save();
543 image_options_sync();
548 layout_refresh(nullptr);
551 if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, nullptr);
553 toolbar_apply(TOOLBAR_MAIN);
554 toolbar_apply(TOOLBAR_STATUS);
558 *-----------------------------------------------------------------------------
559 * config window main button callbacks (private)
560 *-----------------------------------------------------------------------------
563 static void config_window_close_cb(GtkWidget *, gpointer)
565 gq_gtk_widget_destroy(configwindow);
566 configwindow = nullptr;
567 filter_store = nullptr;
570 static void config_window_help_cb(GtkWidget *, gpointer data)
572 auto notebook = static_cast<GtkWidget *>(data);
575 static const gchar *html_section[] =
577 "GuideOptionsGeneral.html",
578 "GuideOptionsImage.html",
579 "GuideOptionsOSD.html",
580 "GuideOptionsWindow.html",
581 "GuideOptionsKeyboard.html",
582 "GuideOptionsFiltering.html",
583 "GuideOptionsMetadata.html",
584 "GuideOptionsKeywords.html",
585 "GuideOptionsColor.html",
586 "GuideOptionsStereo.html",
587 "GuideOptionsBehavior.html",
588 "GuideOptionsToolbar.html",
589 "GuideOptionsToolbar.html",
590 "GuideOptionsAdvanced.html"
593 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
594 help_window_show(html_section[i]);
597 static gboolean config_window_delete(GtkWidget *, GdkEventAny *, gpointer)
599 config_window_close_cb(nullptr, nullptr);
603 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
606 auto notebook = static_cast<GtkNotebook *>(data);
614 lw = static_cast<LayoutWindow *>(layout_window_list->data);
616 window = gtk_widget_get_window(widget);
617 gdk_window_get_root_origin(window, &x, &y);
618 w = gdk_window_get_width(window);
619 h = gdk_window_get_height(window);
620 page_number = gtk_notebook_get_current_page(notebook);
622 lw->options.preferences_window.x = x;
623 lw->options.preferences_window.y = y;
624 lw->options.preferences_window.w = w;
625 lw->options.preferences_window.h = h;
626 lw->options.preferences_window.page_number = page_number;
628 config_window_apply();
629 layout_util_sync(lw);
630 save_options(options);
631 config_window_close_cb(nullptr, nullptr);
635 *-----------------------------------------------------------------------------
636 * config window setup (private)
637 *-----------------------------------------------------------------------------
640 static void quality_menu_cb(GtkWidget *combo, gpointer data)
642 auto option = static_cast<gint *>(data);
644 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
648 *option = GDK_INTERP_NEAREST;
651 *option = GDK_INTERP_TILES;
654 *option = GDK_INTERP_BILINEAR;
659 static void dnd_default_action_selection_menu_cb(GtkWidget *combo, gpointer data)
661 auto option = static_cast<gint *>(data);
663 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
667 *option = DND_ACTION_ASK;
670 *option = DND_ACTION_COPY;
673 *option = DND_ACTION_MOVE;
677 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
679 auto option = static_cast<gint *>(data);
681 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
684 *option = CLIPBOARD_PRIMARY;
687 *option = CLIPBOARD_CLIPBOARD;
690 *option = CLIPBOARD_BOTH;
693 *option = CLIPBOARD_BOTH;
697 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
698 guint option, guint *option_c)
705 pref_table_label(table, column, row, text, GTK_ALIGN_START);
707 combo = gtk_combo_box_text_new();
709 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
710 if (option == GDK_INTERP_NEAREST) current = 0;
711 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
712 if (option == GDK_INTERP_TILES) current = 1;
713 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear (best, but slowest)"));
714 if (option == GDK_INTERP_BILINEAR) current = 2;
716 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
718 g_signal_connect(G_OBJECT(combo), "changed",
719 G_CALLBACK(quality_menu_cb), option_c);
721 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
722 gtk_widget_show(combo);
725 static void add_dnd_default_action_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, DnDAction option, DnDAction *option_c)
732 pref_table_label(table, column, row, text, GTK_ALIGN_START);
734 combo = gtk_combo_box_text_new();
736 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Ask"));
737 if (option == DND_ACTION_ASK) current = 0;
738 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Copy"));
739 if (option == DND_ACTION_COPY) current = 1;
740 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Move"));
741 if (option == DND_ACTION_MOVE) current = 2;
743 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
745 g_signal_connect(G_OBJECT(combo), "changed",
746 G_CALLBACK(dnd_default_action_selection_menu_cb), option_c);
748 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
749 gtk_widget_show(combo);
752 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
753 gint option, gint *option_c)
760 pref_table_label(table, column, row, text, GTK_ALIGN_START);
762 combo = gtk_combo_box_text_new();
764 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Primary"));
765 if (option == CLIPBOARD_PRIMARY) current = 0;
766 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Clipboard"));
767 if (option == CLIPBOARD_CLIPBOARD) current = 1;
768 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Both"));
769 if (option == CLIPBOARD_BOTH) current = 2;
771 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
773 g_signal_connect(G_OBJECT(combo), "changed",
774 G_CALLBACK(clipboard_selection_menu_cb), option_c);
776 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
777 gtk_widget_show(combo);
780 static void zoom_style_selection_menu_cb(GtkWidget *combo, gpointer data)
782 auto option = static_cast<gint *>(data);
784 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
787 *option = ZOOM_GEOMETRIC;
790 *option = ZOOM_ARITHMETIC;
793 *option = ZOOM_GEOMETRIC;
797 static void add_zoom_style_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, ZoomStyle option, ZoomStyle *option_c)
804 pref_table_label(table, column, row, text, GTK_ALIGN_START);
806 combo = gtk_combo_box_text_new();
808 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Geometric"));
809 if (option == ZOOM_GEOMETRIC) current = 0;
810 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Arithmetic"));
811 if (option == ZOOM_ARITHMETIC) current = 1;
813 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
815 g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(zoom_style_selection_menu_cb), option_c);
817 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
818 gtk_widget_show(combo);
821 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
823 ActionItem *action_item = nullptr;
824 auto option = static_cast<gchar **>(data);
829 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
831 list = get_action_items();
836 action_item = static_cast<ActionItem *>(work->data);
837 if (g_strcmp0(action_item->label, label) == 0)
845 *option = g_strdup(action_item->name);
847 action_items_free(list);
850 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, gchar *option, gchar **option_c)
852 ActionItem *action_item;
861 pref_table_label(table, column, row, text, GTK_ALIGN_START);
863 combo = gtk_combo_box_text_new();
865 list = get_action_items();
869 action_item = static_cast<ActionItem *>(work->data);
870 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), action_item->label);
872 if (g_strcmp0(action_item->name, option) == 0)
880 action_items_free(list);
882 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
884 g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
886 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
887 gtk_widget_show(combo);
890 static void thumb_size_menu_cb(GtkWidget *combo, gpointer)
894 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
897 if (static_cast<guint>(n) < sizeof(thumb_size_list) / sizeof(ThumbSize))
899 c_options->thumbnails.max_width = thumb_size_list[n].w;
900 c_options->thumbnails.max_height = thumb_size_list[n].h;
904 c_options->thumbnails.max_width = options->thumbnails.max_width;
905 c_options->thumbnails.max_height = options->thumbnails.max_height;
909 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
915 c_options->thumbnails.max_width = options->thumbnails.max_width;
916 c_options->thumbnails.max_height = options->thumbnails.max_height;
918 pref_table_label(table, column, row, text, GTK_ALIGN_START);
920 combo = gtk_combo_box_text_new();
923 for (i = 0; static_cast<guint>(i) < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
929 w = thumb_size_list[i].w;
930 h = thumb_size_list[i].h;
932 buf = g_strdup_printf("%d x %d", w, h);
933 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
936 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
943 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
944 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
950 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
951 g_signal_connect(G_OBJECT(combo), "changed",
952 G_CALLBACK(thumb_size_menu_cb), NULL);
954 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
955 gtk_widget_show(combo);
958 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
960 auto option = static_cast<gint *>(data);
962 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
966 *option = PR_STEREO_NONE;
969 *option = PR_STEREO_ANAGLYPH_RC;
972 *option = PR_STEREO_ANAGLYPH_GM;
975 *option = PR_STEREO_ANAGLYPH_YB;
978 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
981 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
984 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
987 *option = PR_STEREO_ANAGLYPH_DB_RC;
990 *option = PR_STEREO_ANAGLYPH_DB_GM;
993 *option = PR_STEREO_ANAGLYPH_DB_YB;
996 *option = PR_STEREO_HORIZ;
999 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
1002 *option = PR_STEREO_VERT;
1005 *option = PR_STEREO_VERT | PR_STEREO_HALF;
1008 *option = PR_STEREO_FIXED;
1013 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1014 gint option, gint *option_c, gboolean add_fixed)
1021 pref_table_label(table, column, row, text, GTK_ALIGN_START);
1023 combo = gtk_combo_box_text_new();
1025 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
1027 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
1028 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
1029 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
1030 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
1031 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
1032 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
1033 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
1034 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
1035 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
1036 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
1037 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
1038 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
1039 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
1040 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
1041 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
1042 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
1043 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
1044 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
1046 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
1047 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
1048 if (option & PR_STEREO_HORIZ)
1051 if (option & PR_STEREO_HALF) current = 11;
1054 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
1055 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
1056 if (option & PR_STEREO_VERT)
1059 if (option & PR_STEREO_HALF) current = 13;
1064 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
1065 if (option & PR_STEREO_FIXED) current = 14;
1068 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1070 g_signal_connect(G_OBJECT(combo), "changed",
1071 G_CALLBACK(stereo_mode_menu_cb), option_c);
1073 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
1074 gtk_widget_show(combo);
1077 static void video_menu_cb(GtkWidget *combo, gpointer data)
1079 auto option = static_cast<gchar **>(data);
1081 auto ed = static_cast<EditorDescription *>(g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo))));
1085 static void video_menu_populate(gpointer data, gpointer user_data)
1087 auto combo = static_cast<GtkWidget *>(user_data);
1088 auto ed = static_cast<EditorDescription *>(data);
1090 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1093 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1094 gchar *option, gchar **option_c)
1098 /* use lists since they are sorted */
1099 GList *eds = editor_list_get();
1103 pref_table_label(table, column, row, text, GTK_ALIGN_START);
1105 combo = gtk_combo_box_text_new();
1106 g_list_foreach(eds,video_menu_populate,combo);
1107 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1109 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1111 g_signal_connect(G_OBJECT(combo), "changed",
1112 G_CALLBACK(video_menu_cb), option_c);
1114 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
1115 gtk_widget_show(combo);
1118 static void filter_store_populate()
1122 if (!filter_store) return;
1124 gtk_list_store_clear(filter_store);
1126 work = filter_get_list();
1132 fe = static_cast<FilterEntry *>(work->data);
1135 gtk_list_store_append(filter_store, &iter);
1136 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1140 static void filter_store_ext_edit_cb(GtkCellRendererText *, gchar *path_str, gchar *new_text, gpointer data)
1142 auto model = static_cast<GtkWidget *>(data);
1143 auto fe = static_cast<FilterEntry *>(data);
1147 if (!new_text || strlen(new_text) < 1) return;
1149 tpath = gtk_tree_path_new_from_string(path_str);
1150 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1151 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1153 g_free(fe->extensions);
1154 fe->extensions = g_strdup(new_text);
1156 gtk_tree_path_free(tpath);
1160 static void filter_store_class_edit_cb(GtkCellRendererText *, gchar *path_str, gchar *new_text, gpointer data)
1162 auto model = static_cast<GtkWidget *>(data);
1163 auto fe = static_cast<FilterEntry *>(data);
1168 if (!new_text || !new_text[0]) return;
1170 tpath = gtk_tree_path_new_from_string(path_str);
1171 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1172 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1174 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1176 if (strcmp(new_text, _(format_class_list[i])) == 0)
1178 fe->file_class = static_cast<FileFormatClass>(i);
1183 gtk_tree_path_free(tpath);
1187 static void filter_store_desc_edit_cb(GtkCellRendererText *, gchar *path_str, gchar *new_text, gpointer data)
1189 auto model = static_cast<GtkWidget *>(data);
1194 if (!new_text || !new_text[0]) return;
1196 tpath = gtk_tree_path_new_from_string(path_str);
1197 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1198 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1200 g_free(fe->description);
1201 fe->description = g_strdup(new_text);
1203 gtk_tree_path_free(tpath);
1206 static void filter_store_enable_cb(GtkCellRendererToggle *, gchar *path_str, gpointer data)
1208 auto model = static_cast<GtkWidget *>(data);
1213 tpath = gtk_tree_path_new_from_string(path_str);
1214 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1215 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1217 fe->enabled = !fe->enabled;
1219 gtk_tree_path_free(tpath);
1223 static void filter_store_writable_cb(GtkCellRendererToggle *, gchar *path_str, gpointer data)
1225 auto model = static_cast<GtkWidget *>(data);
1230 tpath = gtk_tree_path_new_from_string(path_str);
1231 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1232 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1234 fe->writable = !fe->writable;
1235 if (fe->writable) fe->allow_sidecar = FALSE;
1237 gtk_tree_path_free(tpath);
1241 static void filter_store_sidecar_cb(GtkCellRendererToggle *, gchar *path_str, gpointer data)
1243 auto model = static_cast<GtkWidget *>(data);
1248 tpath = gtk_tree_path_new_from_string(path_str);
1249 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1250 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1252 fe->allow_sidecar = !fe->allow_sidecar;
1253 if (fe->allow_sidecar) fe->writable = FALSE;
1255 gtk_tree_path_free(tpath);
1259 static void filter_set_func(GtkTreeViewColumn *, GtkCellRenderer *cell,
1260 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1264 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1266 switch (GPOINTER_TO_INT(data))
1269 g_object_set(GTK_CELL_RENDERER(cell),
1270 "active", fe->enabled, NULL);
1273 g_object_set(GTK_CELL_RENDERER(cell),
1274 "text", fe->extensions, NULL);
1276 case FE_DESCRIPTION:
1277 g_object_set(GTK_CELL_RENDERER(cell),
1278 "text", fe->description, NULL);
1281 g_object_set(GTK_CELL_RENDERER(cell),
1282 "text", _(format_class_list[fe->file_class]), NULL);
1285 g_object_set(GTK_CELL_RENDERER(cell),
1286 "active", fe->writable, NULL);
1288 case FE_ALLOW_SIDECAR:
1289 g_object_set(GTK_CELL_RENDERER(cell),
1290 "active", fe->allow_sidecar, NULL);
1295 static gboolean filter_add_scroll(gpointer data)
1299 GtkCellRenderer *cell;
1300 GtkTreeViewColumn *column;
1303 GtkTreeModel *store;
1305 FilterEntry *filter;
1307 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), nullptr);
1308 path = gtk_tree_path_new_from_indices(rows-1, -1);
1310 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1312 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1313 cell = static_cast<GtkCellRenderer *>(g_list_last(list_cells)->data);
1315 store = gtk_tree_view_get_model(GTK_TREE_VIEW(data));
1316 valid = gtk_tree_model_get_iter_first(store, &iter);
1320 gtk_tree_model_get(store, &iter, 0, &filter, -1);
1322 if (g_strcmp0(filter->extensions, ".new") == 0)
1324 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
1328 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1331 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1332 path, column, FALSE, 0.0, 0.0 );
1333 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1334 path, column, cell, TRUE);
1336 gtk_tree_path_free(path);
1337 g_list_free(list_cells);
1339 return(G_SOURCE_REMOVE);
1342 static void filter_add_cb(GtkWidget *, gpointer data)
1344 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1345 filter_store_populate();
1347 g_idle_add(static_cast<GSourceFunc>(filter_add_scroll), data);
1350 static void filter_remove_cb(GtkWidget *, gpointer data)
1352 auto filter_view = static_cast<GtkWidget *>(data);
1353 GtkTreeSelection *selection;
1357 if (!filter_store) return;
1358 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1359 if (!gtk_tree_selection_get_selected(selection, nullptr, &iter)) return;
1360 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1363 filter_remove_entry(fe);
1365 filter_store_populate();
1368 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1372 GtkTreeViewColumn *column;
1374 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1375 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1376 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1378 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1382 gtk_tree_path_free(path);
1384 return(G_SOURCE_REMOVE);
1387 static void filter_default_ok_cb(GenericDialog *gd, gpointer)
1390 filter_add_defaults();
1392 filter_store_populate();
1394 g_idle_add(reinterpret_cast<GSourceFunc>(filter_default_ok_scroll), gd->data);
1397 static void dummy_cancel_cb(GenericDialog *, gpointer)
1399 /* no op, only so cancel button appears */
1402 static void filter_default_cb(GtkWidget *widget, gpointer data)
1406 gd = generic_dialog_new(_("Reset filters"),
1407 "reset_filter", widget, TRUE,
1408 dummy_cancel_cb, data);
1409 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Reset filters"),
1410 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1411 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", filter_default_ok_cb, TRUE);
1412 gtk_widget_show(gd->dialog);
1415 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1417 auto frame = static_cast<GtkWidget *>(data);
1419 gtk_widget_set_sensitive(frame,
1420 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1423 static void safe_delete_view_cb(GtkWidget *, gpointer)
1425 layout_set_path(nullptr, gq_gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1428 static void safe_delete_clear_ok_cb(GenericDialog *, gpointer)
1430 file_util_trash_clear();
1433 static void safe_delete_clear_cb(GtkWidget *widget, gpointer)
1437 gd = generic_dialog_new(_("Clear trash"),
1438 "clear_trash", widget, TRUE,
1439 dummy_cancel_cb, nullptr);
1440 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Clear trash"),
1441 _("This will remove the trash contents."), FALSE);
1442 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", safe_delete_clear_ok_cb, TRUE);
1443 entry = gtk_entry_new();
1444 gtk_widget_set_can_focus(entry, FALSE);
1445 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1446 if (options->file_ops.safe_delete_path) gq_gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1447 gq_gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1448 gtk_widget_show(entry);
1449 gtk_widget_show(gd->dialog);
1452 static void image_overlay_template_view_changed_cb(GtkWidget *, gpointer data)
1454 GtkWidget *pTextView;
1455 GtkTextBuffer *pTextBuffer;
1459 pTextView = GTK_WIDGET(data);
1461 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1462 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1463 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1465 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1466 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1469 static void image_overlay_default_template_ok_cb(GenericDialog *, gpointer data)
1471 auto text_view = static_cast<GtkTextView *>(data);
1472 GtkTextBuffer *buffer;
1474 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1475 if (!configwindow) return;
1477 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1478 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1481 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1485 gd = generic_dialog_new(_("Reset image overlay template string"),
1486 "reset_image_overlay_template_string", widget, TRUE,
1487 dummy_cancel_cb, data);
1488 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Reset image overlay template string"),
1489 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1490 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", image_overlay_default_template_ok_cb, TRUE);
1491 gtk_widget_show(gd->dialog);
1494 static void image_overlay_help_cb(GtkWidget *, gpointer)
1496 help_window_show("GuideOptionsOSD.html");
1499 static void font_activated_cb(GtkFontChooser *widget, gchar *fontname, gpointer)
1501 g_free(c_options->image_overlay.font);
1502 c_options->image_overlay.font = g_strdup(fontname);
1505 gq_gtk_widget_destroy(GTK_WIDGET(widget));
1508 static void font_response_cb(GtkDialog *dialog, gint response_id, gpointer)
1512 g_free(c_options->image_overlay.font);
1513 c_options->image_overlay.font = g_strdup(options->image_overlay.font);
1515 if (response_id == GTK_RESPONSE_OK)
1517 font = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(dialog));
1518 g_free(c_options->image_overlay.font);
1519 c_options->image_overlay.font = g_strdup(font);
1523 gq_gtk_widget_destroy(GTK_WIDGET(dialog));
1526 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer)
1530 dialog = gtk_font_chooser_dialog_new(_("Image Overlay Font"), GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1531 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1532 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1534 g_signal_connect(dialog, "font-activated", G_CALLBACK(font_activated_cb), nullptr);
1535 g_signal_connect(dialog, "response", G_CALLBACK(font_response_cb), nullptr);
1537 gtk_widget_show(dialog);
1540 static void text_color_activated_cb(GtkColorChooser *chooser, GdkRGBA *color, gpointer)
1542 c_options->image_overlay.text_red = color->red * 255;
1543 c_options->image_overlay.text_green = color->green * 255;
1544 c_options->image_overlay.text_blue = color->blue * 255;
1545 c_options->image_overlay.text_alpha = color->alpha * 255;
1547 gq_gtk_widget_destroy(GTK_WIDGET(chooser));
1550 static void text_color_response_cb(GtkDialog *dialog, gint response_id, gpointer)
1554 c_options->image_overlay.text_red = options->image_overlay.text_red;
1555 c_options->image_overlay.text_green = options->image_overlay.text_green;
1556 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
1557 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
1559 if (response_id == GTK_RESPONSE_OK)
1561 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &color);
1562 c_options->image_overlay.text_red = color.red * 255;
1563 c_options->image_overlay.text_green = color.green * 255;
1564 c_options->image_overlay.text_blue = color.blue * 255;
1565 c_options->image_overlay.text_alpha = color.alpha * 255;
1568 gq_gtk_widget_destroy(GTK_WIDGET(dialog));
1571 static void image_overlay_set_text_color_cb(GtkWidget *widget, gpointer)
1576 dialog = gtk_color_chooser_dialog_new(_("Image Overlay Text Color"), GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1577 color.red = options->image_overlay.text_red;
1578 color.green = options->image_overlay.text_green;
1579 color.blue = options->image_overlay.text_blue;
1580 color.alpha = options->image_overlay.text_alpha;
1581 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &color);
1582 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1584 g_signal_connect(dialog, "color-activated", G_CALLBACK(text_color_activated_cb), nullptr);
1585 g_signal_connect(dialog, "response", G_CALLBACK(text_color_response_cb), nullptr);
1587 gtk_widget_show(dialog);
1590 static void bg_color_activated_cb(GtkColorChooser *chooser, GdkRGBA *color, gpointer)
1592 c_options->image_overlay.background_red = color->red * 255;
1593 c_options->image_overlay.background_green = color->green * 255;
1594 c_options->image_overlay.background_blue = color->blue * 255;
1595 c_options->image_overlay.background_alpha = color->alpha * 255;
1597 gq_gtk_widget_destroy(GTK_WIDGET(chooser));
1600 static void bg_color_response_cb(GtkDialog *dialog, gint response_id, gpointer)
1604 c_options->image_overlay.background_red = options->image_overlay.background_red;
1605 c_options->image_overlay.background_green = options->image_overlay.background_green;
1606 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
1607 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
1609 if (response_id == GTK_RESPONSE_OK)
1611 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &color);
1612 c_options->image_overlay.background_red = color.red * 255;
1613 c_options->image_overlay.background_green = color.green * 255;
1614 c_options->image_overlay.background_blue = color.blue * 255;
1615 c_options->image_overlay.background_alpha = color.alpha * 255;
1617 gq_gtk_widget_destroy(GTK_WIDGET(dialog));
1620 static void image_overlay_set_background_color_cb(GtkWidget *widget, gpointer)
1625 dialog = gtk_color_chooser_dialog_new(_("Image Overlay Background Color"), GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1626 color.red = options->image_overlay.background_red;
1627 color.green = options->image_overlay.background_green;
1628 color.blue = options->image_overlay.background_blue;
1629 color.alpha = options->image_overlay.background_alpha;
1630 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &color);
1631 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1633 g_signal_connect(dialog, "color-activated", G_CALLBACK(bg_color_activated_cb), nullptr);
1634 g_signal_connect(dialog, "response", G_CALLBACK(bg_color_response_cb), nullptr);
1636 gtk_widget_show(dialog);
1639 static void accel_store_populate()
1645 const gchar *accel_path;
1646 const gchar *icon_name;
1650 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1652 gtk_tree_store_clear(accel_store);
1653 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 */
1655 g_assert(lw && lw->ui_manager);
1656 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1659 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1662 action = GTK_ACTION(actions->data);
1663 accel_path = gtk_action_get_accel_path(action);
1664 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1670 g_object_get(action,
1671 "tooltip", &tooltip,
1675 if (pango_parse_markup(label, -1, '_', nullptr, &label2, nullptr, nullptr) && label2)
1681 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1682 icon_name = gtk_action_get_icon_name(action);
1686 gtk_tree_store_append(accel_store, &iter, nullptr);
1687 gtk_tree_store_set(accel_store, &iter,
1690 AE_TOOLTIP, tooltip ? tooltip : "",
1691 AE_ACCEL, accel_path,
1700 actions = actions->next;
1703 groups = groups->next;
1707 static void accel_store_cleared_cb(GtkCellRendererAccel *, gchar *, gpointer)
1712 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *, GtkTreeIter *iter, gpointer data)
1714 auto accel1 = static_cast<gchar *>(data);
1719 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1721 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1722 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1724 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1726 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1727 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1736 static void accel_store_edited_cb(GtkCellRendererAccel *, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint, gpointer)
1738 auto model = reinterpret_cast<GtkTreeModel *>(accel_store);
1742 GtkAccelKey old_key;
1744 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1746 gtk_tree_model_get_iter(model, &iter, path);
1747 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1749 /* test if the accelerator can be stored without conflicts*/
1750 gtk_accel_map_lookup_entry(accel_path, &old_key);
1752 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1753 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1754 gtk_accel_map_lookup_entry(accel_path, &key);
1756 /* restore the original for now, the key will be really changed when the changes are confirmed */
1757 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1759 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1760 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1762 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1763 gtk_tree_path_free(path);
1767 static gboolean accel_default_scroll(GtkTreeView *data)
1771 GtkTreeViewColumn *column;
1773 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1774 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1775 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1777 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1781 gtk_tree_path_free(path);
1783 return(G_SOURCE_REMOVE);
1786 static void accel_default_cb(GtkWidget *, gpointer data)
1788 accel_store_populate();
1790 g_idle_add(reinterpret_cast<GSourceFunc>(accel_default_scroll), data);
1793 void accel_clear_selection(GtkTreeModel *, GtkTreePath *, GtkTreeIter *iter, gpointer)
1795 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1798 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *, GtkTreeIter *iter, gpointer)
1804 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1805 gtk_accel_map_lookup_entry(accel_path, &key);
1806 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1808 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1810 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1815 static void accel_clear_cb(GtkWidget *, gpointer data)
1817 GtkTreeSelection *selection;
1819 if (!accel_store) return;
1820 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1821 gtk_tree_selection_selected_foreach(selection, &accel_clear_selection, nullptr);
1824 static void accel_reset_cb(GtkWidget *, gpointer data)
1826 GtkTreeSelection *selection;
1828 if (!accel_store) return;
1829 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1830 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, nullptr);
1835 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1839 GtkWidget *scrolled;
1840 GtkWidget *viewport;
1842 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
1843 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1844 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1845 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1846 label = gtk_label_new(title);
1847 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1848 gtk_widget_show(scrolled);
1850 viewport = gtk_viewport_new(nullptr, nullptr);
1851 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1852 gq_gtk_container_add(GTK_WIDGET(scrolled), viewport);
1853 gtk_widget_show(viewport);
1855 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
1856 gq_gtk_container_add(GTK_WIDGET(viewport), vbox);
1857 gtk_widget_show(vbox);
1862 static void cache_standard_cb(GtkWidget *widget, gpointer)
1864 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1866 c_options->thumbnails.spec_standard =TRUE;
1867 c_options->thumbnails.cache_into_dirs = FALSE;
1871 static void cache_geeqie_cb(GtkWidget *widget, gpointer)
1873 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1875 c_options->thumbnails.spec_standard =FALSE;
1876 c_options->thumbnails.cache_into_dirs = FALSE;
1880 static void cache_local_cb(GtkWidget *widget, gpointer)
1882 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1884 c_options->thumbnails.cache_into_dirs = TRUE;
1885 c_options->thumbnails.spec_standard =FALSE;
1889 static void help_search_engine_entry_icon_cb(GtkEntry *, GtkEntryIconPosition pos, GdkEvent *, gpointer userdata)
1891 if (pos == GTK_ENTRY_ICON_PRIMARY)
1893 gq_gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1897 gq_gtk_entry_set_text(GTK_ENTRY(userdata), "");
1901 static void star_rating_star_icon_cb(GtkEntry *, GtkEntryIconPosition pos, GdkEvent *, gpointer userdata)
1903 gchar *rating_symbol;
1905 if (pos == GTK_ENTRY_ICON_PRIMARY)
1907 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1908 gq_gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1909 g_free(rating_symbol);
1913 gq_gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1914 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1915 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1919 static void star_rating_rejected_icon_cb(GtkEntry *, GtkEntryIconPosition pos, GdkEvent *, gpointer userdata)
1921 gchar *rating_symbol;
1923 if (pos == GTK_ENTRY_ICON_PRIMARY)
1925 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1926 gq_gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1927 g_free(rating_symbol);
1931 gq_gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1932 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1933 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1937 static guint star_rating_symbol_test(GtkWidget *, gpointer data)
1939 auto hbox = static_cast<GtkContainer *>(data);
1940 GString *str = g_string_new(nullptr);
1941 GtkEntry *hex_code_entry;
1942 gchar *hex_code_full;
1945 guint64 hex_value = 0;
1947 list = gtk_container_get_children(hbox);
1949 hex_code_entry = static_cast<GtkEntry *>(g_list_nth_data(list, 2));
1950 hex_code_full = g_strdup(gq_gtk_entry_get_text(hex_code_entry));
1952 hex_code = g_strsplit(hex_code_full, "+", 2);
1953 if (hex_code[0] && hex_code[1])
1955 hex_value = strtoull(hex_code[1], nullptr, 16);
1957 if (!hex_value || hex_value > 0x10FFFF)
1959 hex_value = 0x003F; // Unicode 'Question Mark'
1961 str = g_string_append_unichar(str, static_cast<gunichar>(hex_value));
1962 gtk_label_set_text(static_cast<GtkLabel *>(g_list_nth_data(list, 1)), str->str);
1964 g_strfreev(hex_code);
1965 g_string_free(str, TRUE);
1966 g_free(hex_code_full);
1971 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1973 guint64 star_symbol;
1975 star_symbol = star_rating_symbol_test(widget, data);
1976 c_options->star_rating.star = star_symbol;
1979 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1981 guint64 rejected_symbol;
1983 rejected_symbol = star_rating_symbol_test(widget, data);
1984 c_options->star_rating.rejected = rejected_symbol;
1987 /* general options tab */
1988 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1992 GCancellable *cancellable;
1994 GtkWidget *progress;
1996 GFile *timezone_database_gq;
1997 gchar *timezone_database_user;
2000 static void config_tab_general(GtkWidget *notebook)
2005 GtkWidget *group_frame;
2006 GtkWidget *subgroup;
2008 GtkWidget *ct_button;
2015 GtkWidget *star_rating_entry;
2017 gchar *rating_symbol;
2020 gchar *download_locn;
2021 GNetworkMonitor *net_mon;
2022 GSocketConnectable *tz_org;
2023 gboolean internet_available = FALSE;
2026 vbox = scrolled_notebook_page(notebook, _("General"));
2028 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
2030 table = pref_table_new(group, 2, 2, FALSE, FALSE);
2031 add_thumb_size_menu(table, 0, 0, _("Size:"));
2032 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
2034 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2035 pref_label_new(hbox, _("Custom size: "));
2036 pref_spin_new_int(hbox, _("Width:"), nullptr, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
2037 pref_spin_new_int(hbox, _("Height:"), nullptr, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
2039 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
2040 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
2042 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2043 pref_checkbox_link_sensitivity(ct_button, subgroup);
2045 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
2046 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
2047 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
2048 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2049 button = pref_radiobutton_new(group_frame, nullptr, get_thumbnails_cache_dir(),
2050 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2051 G_CALLBACK(cache_geeqie_cb), nullptr);
2053 group_frame = pref_frame_new(subgroup, TRUE,
2054 _("Store thumbnails local to image folder (non-standard)"),
2055 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2056 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
2057 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
2058 G_CALLBACK(cache_local_cb), nullptr);
2060 group_frame = pref_frame_new(subgroup, TRUE,
2061 _("Use standard thumbnail style and cache, shared with other applications"),
2062 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2063 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
2064 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2065 G_CALLBACK(cache_standard_cb), nullptr);
2067 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
2068 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
2070 pref_checkbox_new_int(group, _("Thumbnail color management"),
2071 options->thumbnails.use_color_management, &c_options->thumbnails.use_color_management);
2073 spin = pref_spin_new_int(group, _("Collection preview:"), nullptr,
2075 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
2076 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
2078 #if HAVE_FFMPEGTHUMBNAILER_METADATA
2079 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
2080 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
2083 pref_spacer(group, PREF_PAD_GROUP);
2085 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
2087 c_options->star_rating.star = options->star_rating.star;
2088 c_options->star_rating.rejected = options->star_rating.rejected;
2090 str = g_string_new(nullptr);
2091 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2092 pref_label_new(hbox, _("Star character: "));
2093 str = g_string_append_unichar(str, options->star_rating.star);
2094 pref_label_new(hbox, g_strdup(str->str));
2095 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
2096 star_rating_entry = gtk_entry_new();
2097 gq_gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2098 gq_gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2099 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2100 gtk_widget_show(star_rating_entry);
2101 button = pref_button_new(nullptr, nullptr, _("Set"),
2102 G_CALLBACK(star_rating_star_test_cb), hbox);
2103 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2104 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2105 gtk_widget_show(button);
2106 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."));
2107 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2108 GTK_ENTRY_ICON_SECONDARY, GQ_ICON_CLEAR);
2109 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2110 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2111 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2112 GTK_ENTRY_ICON_PRIMARY, GQ_ICON_REVERT);
2113 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2114 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2115 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2116 G_CALLBACK(star_rating_star_icon_cb),
2119 g_string_free(str, TRUE);
2120 g_free(rating_symbol);
2122 str = g_string_new(nullptr);
2123 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2124 pref_label_new(hbox, _("Rejected character: "));
2125 str = g_string_append_unichar(str, options->star_rating.rejected);
2126 pref_label_new(hbox, g_strdup(str->str));
2127 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2128 star_rating_entry = gtk_entry_new();
2129 gq_gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2130 gq_gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2131 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2132 gtk_widget_show(star_rating_entry);
2133 button = pref_button_new(nullptr, nullptr, _("Set"),
2134 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2135 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2136 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2137 gtk_widget_show(button);
2138 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."));
2139 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2140 GTK_ENTRY_ICON_SECONDARY, GQ_ICON_CLEAR);
2141 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2142 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2143 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2144 GTK_ENTRY_ICON_PRIMARY, GQ_ICON_REVERT);
2145 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2146 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2147 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2148 G_CALLBACK(star_rating_rejected_icon_cb),
2151 g_string_free(str, TRUE);
2152 g_free(rating_symbol);
2154 pref_spacer(group, PREF_PAD_GROUP);
2156 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2158 c_options->slideshow.delay = options->slideshow.delay;
2159 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2160 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2161 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2162 seconds = static_cast<gdouble>(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2163 SLIDESHOW_SUBSECOND_PRECISION;
2165 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2167 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), nullptr,
2169 options->slideshow.delay ? hours : 0.0,
2170 G_CALLBACK(slideshow_delay_hours_cb), nullptr);
2171 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2172 spin = pref_spin_new(hbox, ":" , nullptr,
2174 options->slideshow.delay ? minutes: 0.0,
2175 G_CALLBACK(slideshow_delay_minutes_cb), nullptr);
2176 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2177 spin = pref_spin_new(hbox, ":", nullptr,
2178 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2179 options->slideshow.delay ? seconds : 10.0,
2180 G_CALLBACK(slideshow_delay_seconds_cb), nullptr);
2181 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2183 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2184 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2186 pref_spacer(group, PREF_PAD_GROUP);
2188 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2190 pref_spin_new_int(group, _("Decoded image cache size (MiB):"), nullptr,
2191 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2192 pref_checkbox_new_int(group, _("Preload next image"),
2193 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2195 pref_checkbox_new_int(group, _("Refresh on file change"),
2196 options->update_on_time_change, &c_options->update_on_time_change);
2199 pref_spacer(group, PREF_PAD_GROUP);
2201 group = pref_group_new(vbox, FALSE, _("Menu style"), GTK_ORIENTATION_VERTICAL);
2203 pref_checkbox_new_int(group, _("☰ style menu button (NOTE! Geeqie must be restarted for change to take effect)"),
2204 options->hamburger_menu, &c_options->hamburger_menu);
2205 gtk_widget_set_tooltip_text(group, _("Use a ☰ style menu button instead of the classic style across the top of the frame"));
2207 pref_spacer(group, PREF_PAD_GROUP);
2209 group = pref_group_new(vbox, FALSE, _("Expand toolbar"), GTK_ORIENTATION_VERTICAL);
2211 pref_checkbox_new_int(group, _("Expand menu/toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2212 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2213 gtk_widget_set_tooltip_text(group, _("Expand the menu/toolbar to the full width of the window"));
2215 pref_spacer(group, PREF_PAD_GROUP);
2217 group = pref_group_new(vbox, FALSE, _("Hide Selectable Bars"), GTK_ORIENTATION_VERTICAL);
2219 pref_checkbox_new_int(group, _("Menu bar"),
2220 options->selectable_bars.menu_bar, &c_options->selectable_bars.menu_bar);
2222 pref_checkbox_new_int(group, _("Tool bar"),
2223 options->selectable_bars.tool_bar, &c_options->selectable_bars.tool_bar);
2225 pref_checkbox_new_int(group, _("Status bar"),
2226 options->selectable_bars.status_bar, &c_options->selectable_bars.status_bar);
2227 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"));
2229 pref_spacer(group, PREF_PAD_GROUP);
2231 if (g_getenv("APPDIR") && strstr(g_getenv("APPDIR"), "/tmp/.mount_Geeqie"))
2233 group = pref_group_new(vbox, FALSE, _("AppImage updates notifications"), GTK_ORIENTATION_VERTICAL);
2234 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2235 pref_checkbox_new_int(group, _("Enable"), options->appimage_notifications, &c_options->appimage_notifications);
2236 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"));
2238 pref_spacer(group, PREF_PAD_GROUP);
2242 net_mon = g_network_monitor_get_default();
2243 tz_org = g_network_address_parse_uri(TIMEZONE_DATABASE_WEB, 80, nullptr);
2246 internet_available = g_network_monitor_can_reach(net_mon, tz_org, nullptr, nullptr);
2247 g_object_unref(tz_org);
2250 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2251 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2253 if (!internet_available)
2255 gtk_widget_set_sensitive(group, FALSE);
2258 tz = g_new0(TZData, 1);
2260 path = path_from_utf8(TIMEZONE_DATABASE_WEB);
2261 basename = g_path_get_basename(path);
2262 tz->timezone_database_user = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
2266 if (isfile(tz->timezone_database_user))
2268 button = pref_button_new(GTK_WIDGET(hbox), nullptr, _("Update"), G_CALLBACK(timezone_database_install_cb), tz);
2272 button = pref_button_new(GTK_WIDGET(hbox), nullptr, _("Install"), G_CALLBACK(timezone_database_install_cb), tz);
2275 download_locn = g_strconcat(_("Download database from: "), TIMEZONE_DATABASE_WEB, NULL);
2276 pref_label_new(GTK_WIDGET(hbox), download_locn);
2277 g_free(download_locn);
2279 if (!internet_available)
2281 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"));
2285 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"));
2287 gtk_widget_show(button);
2289 pref_spacer(group, PREF_PAD_GROUP);
2291 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2293 help_search_engine_entry = gtk_entry_new();
2294 gq_gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2295 gq_gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2296 gtk_widget_show(help_search_engine_entry);
2298 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"));
2300 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(help_search_engine_entry),
2301 GTK_ENTRY_ICON_SECONDARY, GQ_ICON_CLEAR);
2302 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2303 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2304 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(help_search_engine_entry),
2305 GTK_ENTRY_ICON_PRIMARY, GQ_ICON_REVERT);
2306 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2307 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2308 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2309 G_CALLBACK(help_search_engine_entry_icon_cb),
2310 help_search_engine_entry);
2314 static void config_tab_image(GtkWidget *notebook)
2319 GtkWidget *ct_button;
2320 GtkWidget *enlargement_button;
2324 vbox = scrolled_notebook_page(notebook, _("Image"));
2326 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2328 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2329 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2331 pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2332 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2334 c_options->image.zoom_increment = options->image.zoom_increment;
2335 spin = pref_spin_new(group, _("Zoom increment:"), nullptr,
2336 0.01, 4.0, 0.01, 2, static_cast<gdouble>(options->image.zoom_increment) / 100.0,
2337 G_CALLBACK(zoom_increment_cb), nullptr);
2338 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2340 c_options->image.zoom_style = options->image.zoom_style;
2341 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2342 add_zoom_style_selection_menu(table, 0, 0, _("Zoom style:"), options->image.zoom_style, &c_options->image.zoom_style);
2344 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2346 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2347 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2348 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2349 spin = pref_spin_new_int(hbox, nullptr, nullptr,
2351 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2352 pref_checkbox_link_sensitivity(enlargement_button, spin);
2353 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."));
2355 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2356 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (%% of actual window):"),
2357 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2358 spin = pref_spin_new_int(hbox, nullptr, nullptr,
2360 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2361 pref_checkbox_link_sensitivity(ct_button, spin);
2362 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."));
2364 group = pref_group_new(vbox, FALSE, _("Tile size"), GTK_ORIENTATION_VERTICAL);
2366 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2367 spin = pref_spin_new_int(hbox, _("Pixels"), _("(Requires restart)"),
2369 options->image.tile_size, &c_options->image.tile_size);
2370 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."));
2372 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2374 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2375 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2377 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2378 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2380 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2381 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2383 c_options->image.border_color = options->image.border_color;
2385 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2386 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2388 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2389 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2391 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2392 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2397 static void save_default_window_layout_cb(GtkWidget *, gpointer)
2399 LayoutWindow *lw = nullptr;
2400 gchar *default_path;
2403 /* Get current lw */
2406 tmp_id = lw->options.id;
2407 lw->options.id = g_strdup("");
2409 default_path = g_build_filename(get_rc_dir(), DEFAULT_WINDOW_LAYOUT, NULL);
2410 save_default_layout_options_to_file(default_path, options, lw);
2411 g_free(lw->options.id);
2412 lw->options.id = tmp_id;
2413 g_free(default_path);
2416 static gboolean popover_cb(gpointer data)
2418 auto popover = static_cast<GtkPopover *>(data);
2420 gtk_popover_popdown(popover);
2425 static void default_layout_changed_cb(GtkWidget *, GtkPopover *popover)
2427 gtk_popover_popup(popover);
2429 g_timeout_add(2000, popover_cb, popover);
2432 static GtkWidget *create_popover(GtkWidget *parent, GtkWidget *child, GtkPositionType pos)
2436 popover = gtk_popover_new(parent);
2437 gtk_popover_set_position(GTK_POPOVER (popover), pos);
2438 gq_gtk_container_add(GTK_WIDGET(popover), child);
2439 gtk_container_set_border_width(GTK_CONTAINER (popover), 6);
2440 gtk_widget_show (child);
2445 static void config_tab_windows(GtkWidget *notebook)
2450 GtkWidget *subgroup;
2452 GtkWidget *checkbox;
2453 GtkWidget *ct_button;
2456 vbox = scrolled_notebook_page(notebook, _("Windows"));
2458 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2460 ct_button = pref_checkbox_new_int(group, _("Remember session"),
2461 options->save_window_positions, &c_options->save_window_positions);
2463 checkbox = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2464 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2465 pref_checkbox_link_sensitivity(ct_button, checkbox);
2467 checkbox = pref_checkbox_new_int(group, _("Remember window workspace"),
2468 options->save_window_workspace, &c_options->save_window_workspace);
2469 pref_checkbox_link_sensitivity(ct_button, checkbox);
2471 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2472 options->tools_restore_state, &c_options->tools_restore_state);
2474 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2475 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2477 pref_checkbox_new_int(group, _("Show window IDs"),
2478 options->show_window_ids, &c_options->show_window_ids);
2480 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2481 pref_label_new(subgroup, _("Use current layout for default: "));
2482 button = pref_button_new(subgroup, nullptr, _("Set"), G_CALLBACK(save_default_window_layout_cb), nullptr);
2486 popover = create_popover(button, gtk_label_new(_("Current window layout\nhas been set as default")), GTK_POS_TOP);
2487 gtk_popover_set_modal(GTK_POPOVER (popover), FALSE);
2488 g_signal_connect(button, "clicked", G_CALLBACK(default_layout_changed_cb), popover);
2490 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2492 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2493 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2495 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2496 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2497 options->image.limit_window_size, &c_options->image.limit_window_size);
2498 spin = pref_spin_new_int(hbox, nullptr, nullptr,
2500 options->image.max_window_size, &c_options->image.max_window_size);
2501 pref_checkbox_link_sensitivity(ct_button, spin);
2503 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2505 c_options->fullscreen.screen = options->fullscreen.screen;
2506 c_options->fullscreen.above = options->fullscreen.above;
2507 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2508 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2509 gtk_widget_show(hbox);
2511 pref_checkbox_new_int(group, _("Smooth image flip"),
2512 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2513 pref_checkbox_new_int(group, _("Disable screen saver"),
2514 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2517 static void config_tab_osd(GtkWidget *notebook)
2523 GtkWidget *image_overlay_template_view;
2524 GtkWidget *scrolled;
2525 GtkWidget *scrolled_pre_formatted;
2526 GtkTextBuffer *buffer;
2528 GtkWidget *subgroup;
2530 vbox = scrolled_notebook_page(notebook, _("OSD"));
2532 image_overlay_template_view = gtk_text_view_new();
2534 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2536 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2538 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2539 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2540 gq_gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2541 gtk_widget_show(scrolled_pre_formatted);
2542 gtk_widget_show(subgroup);
2544 pref_line(group, PREF_PAD_GAP);
2546 pref_label_new(group, _("Image overlay template"));
2548 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
2549 gtk_widget_set_size_request(scrolled, 200, 150);
2550 gq_gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2551 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2552 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2553 gq_gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2554 gtk_widget_show(scrolled);
2556 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2557 _("Extensive formatting options are shown in the Help file"));
2559 gq_gtk_container_add(GTK_WIDGET(scrolled), image_overlay_template_view);
2560 gtk_widget_show(image_overlay_template_view);
2562 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2564 button = pref_button_new(nullptr, GQ_ICON_SELECT_FONT, _("Font"),
2565 G_CALLBACK(image_overlay_set_font_cb), notebook);
2567 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2568 gtk_widget_show(button);
2570 button = pref_button_new(nullptr, GQ_ICON_SELECT_COLOR, _("Text"), G_CALLBACK(image_overlay_set_text_color_cb), nullptr);
2571 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2572 gtk_widget_show(button);
2574 button = pref_button_new(nullptr, GQ_ICON_SELECT_COLOR, _("Background"), G_CALLBACK(image_overlay_set_background_color_cb), nullptr);
2575 gq_gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2576 gtk_widget_show(button);
2577 image_overlay_set_text_colors();
2579 button = pref_button_new(nullptr, nullptr, _("Defaults"),
2580 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2581 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2582 gtk_widget_show(button);
2584 button = pref_button_new(nullptr, GQ_ICON_HELP, _("Help"),
2585 G_CALLBACK(image_overlay_help_cb), nullptr);
2586 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2587 gtk_widget_show(button);
2589 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2590 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2591 g_signal_connect(G_OBJECT(buffer), "changed",
2592 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2594 pref_line(group, PREF_PAD_GAP);
2596 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2597 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2598 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2599 gtk_widget_show(hbox);
2600 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2601 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2602 gtk_widget_show(label);
2603 pref_spacer(group,TRUE);
2605 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2606 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2607 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2608 gtk_widget_show(hbox);
2609 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2610 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2611 gtk_widget_show(label);
2612 pref_spacer(group,TRUE);
2614 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2615 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2616 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2617 gtk_widget_show(hbox);
2618 label = gtk_label_new(_("%path:39%"));
2619 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2620 gtk_widget_show(label);
2621 pref_spacer(group,TRUE);
2623 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2624 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2625 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2626 gtk_widget_show(hbox);
2627 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%"));
2628 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2629 gtk_widget_show(label);
2630 pref_spacer(group,TRUE);
2632 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2633 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2634 gq_gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2635 gtk_widget_show(hbox);
2636 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2637 gq_gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2638 gtk_widget_show(label);
2641 static GtkTreeModel *create_class_model()
2643 GtkListStore *model;
2647 /* create list store */
2648 model = gtk_list_store_new(1, G_TYPE_STRING);
2649 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2651 gtk_list_store_append(model, &iter);
2652 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2654 return GTK_TREE_MODEL (model);
2659 static gint filter_table_sort_cb(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data)
2661 gint n = GPOINTER_TO_INT(data);
2663 FilterEntry *filter_a;
2664 FilterEntry *filter_b;
2666 gtk_tree_model_get(model, a, 0, &filter_a, -1);
2667 gtk_tree_model_get(model, b, 0, &filter_b, -1);
2671 case FILETYPES_COLUMN_ENABLED:
2673 ret = filter_a->enabled - filter_b->enabled;
2676 case FILETYPES_COLUMN_FILTER:
2678 ret = g_utf8_collate(filter_a->extensions, filter_b->extensions);
2681 case FILETYPES_COLUMN_DESCRIPTION:
2683 ret = g_utf8_collate(filter_a->description, filter_b->description);
2686 case FILETYPES_COLUMN_CLASS:
2688 ret = g_strcmp0(format_class_list[filter_a->file_class], format_class_list[filter_b->file_class]);
2691 case FILETYPES_COLUMN_WRITABLE:
2693 ret = filter_a->writable - filter_b->writable;
2696 case FILETYPES_COLUMN_SIDECAR:
2698 ret = filter_a->allow_sidecar - filter_b->allow_sidecar;
2702 g_return_val_if_reached(0);
2708 static gboolean search_function_cb(GtkTreeModel *model, gint, const gchar *key, GtkTreeIter *iter, gpointer)
2711 gboolean ret = TRUE;
2713 gtk_tree_model_get(model, iter, 0, &fe, -1);
2715 if (g_strstr_len(fe->extensions, -1, key))
2723 static void config_tab_files(GtkWidget *notebook)
2730 GtkWidget *ct_button;
2731 GtkWidget *scrolled;
2732 GtkWidget *filter_view;
2733 GtkCellRenderer *renderer;
2734 GtkTreeSelection *selection;
2735 GtkTreeViewColumn *column;
2737 vbox = scrolled_notebook_page(notebook, _("File Filters"));
2739 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2741 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2742 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2743 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2744 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2745 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);
2746 pref_checkbox_new_int(group, _("Disable file extension checks"),
2747 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2749 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2750 options->file_filter.disable, &c_options->file_filter.disable);
2753 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2755 sidecar_ext_entry = gtk_entry_new();
2756 gq_gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2757 gq_gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2758 gtk_widget_show(sidecar_ext_entry);
2760 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2762 frame = pref_group_parent(group);
2763 g_signal_connect(G_OBJECT(ct_button), "toggled",
2764 G_CALLBACK(filter_disable_cb), frame);
2765 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2767 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
2768 gq_gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2769 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2770 gq_gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2771 gtk_widget_show(scrolled);
2773 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2774 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2775 g_object_unref(filter_store);
2776 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2777 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2779 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2781 column = gtk_tree_view_column_new();
2782 gtk_tree_view_column_set_title(column, _("Enabled"));
2783 gtk_tree_view_column_set_resizable(column, TRUE);
2785 renderer = gtk_cell_renderer_toggle_new();
2786 g_signal_connect(G_OBJECT(renderer), "toggled",
2787 G_CALLBACK(filter_store_enable_cb), filter_store);
2788 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2789 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2790 GINT_TO_POINTER(FE_ENABLE), nullptr);
2791 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);
2792 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_ENABLED);
2793 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2795 column = gtk_tree_view_column_new();
2796 gtk_tree_view_column_set_title(column, _("Filter"));
2797 gtk_tree_view_column_set_resizable(column, TRUE);
2798 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);
2799 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_FILTER);
2801 renderer = gtk_cell_renderer_text_new();
2802 g_signal_connect(G_OBJECT(renderer), "edited",
2803 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2804 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2805 g_object_set(G_OBJECT(renderer), "editable", static_cast<gboolean>TRUE, NULL);
2806 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2807 GINT_TO_POINTER(FE_EXTENSION), nullptr);
2808 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2810 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), TRUE);
2811 gtk_tree_view_set_search_column(GTK_TREE_VIEW(filter_view), FILETYPES_COLUMN_FILTER);
2812 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(filter_view), search_function_cb, nullptr, nullptr);
2814 column = gtk_tree_view_column_new();
2815 gtk_tree_view_column_set_title(column, _("Description"));
2816 gtk_tree_view_column_set_resizable(column, TRUE);
2817 gtk_tree_view_column_set_fixed_width(column, 200);
2818 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2820 renderer = gtk_cell_renderer_text_new();
2821 g_signal_connect(G_OBJECT(renderer), "edited",
2822 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2823 g_object_set(G_OBJECT(renderer), "editable", static_cast<gboolean>TRUE, NULL);
2824 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2825 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2826 GINT_TO_POINTER(FE_DESCRIPTION), nullptr);
2827 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2828 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);
2829 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_DESCRIPTION);
2831 column = gtk_tree_view_column_new();
2832 gtk_tree_view_column_set_title(column, _("Class"));
2833 gtk_tree_view_column_set_resizable(column, TRUE);
2834 renderer = gtk_cell_renderer_combo_new();
2835 g_object_set(G_OBJECT(renderer), "editable", static_cast<gboolean>TRUE,
2836 "model", create_class_model(),
2841 g_signal_connect(G_OBJECT(renderer), "edited",
2842 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2843 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2844 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2845 GINT_TO_POINTER(FE_CLASS), nullptr);
2846 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2847 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);
2848 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_CLASS);
2850 column = gtk_tree_view_column_new();
2851 gtk_tree_view_column_set_title(column, _("Writable"));
2852 gtk_tree_view_column_set_resizable(column, FALSE);
2853 renderer = gtk_cell_renderer_toggle_new();
2854 g_signal_connect(G_OBJECT(renderer), "toggled",
2855 G_CALLBACK(filter_store_writable_cb), filter_store);
2856 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2857 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2858 GINT_TO_POINTER(FE_WRITABLE), nullptr);
2859 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2860 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);
2861 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_WRITABLE);
2863 column = gtk_tree_view_column_new();
2864 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2865 gtk_tree_view_column_set_resizable(column, FALSE);
2866 renderer = gtk_cell_renderer_toggle_new();
2867 g_signal_connect(G_OBJECT(renderer), "toggled",
2868 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2869 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2870 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2871 GINT_TO_POINTER(FE_ALLOW_SIDECAR), nullptr);
2872 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2873 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);
2874 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_SIDECAR);
2876 filter_store_populate();
2877 gq_gtk_container_add(GTK_WIDGET(scrolled), filter_view);
2878 gtk_widget_show(filter_view);
2880 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2882 button = pref_button_new(nullptr, nullptr, _("Defaults"),
2883 G_CALLBACK(filter_default_cb), filter_view);
2884 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2885 gtk_widget_show(button);
2887 button = pref_button_new(nullptr, GQ_ICON_REMOVE, _("Remove"),
2888 G_CALLBACK(filter_remove_cb), filter_view);
2889 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2890 gtk_widget_show(button);
2892 button = pref_button_new(nullptr, GQ_ICON_ADD, _("Add"),
2893 G_CALLBACK(filter_add_cb), filter_view);
2894 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2895 gtk_widget_show(button);
2899 static void config_tab_metadata(GtkWidget *notebook)
2904 GtkWidget *ct_button;
2906 GtkWidget *tmp_widget;
2908 GtkWidget *text_label;
2910 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2913 group = pref_group_new(vbox, FALSE, _("Metadata writing sequence"), GTK_ORIENTATION_VERTICAL);
2915 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2917 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."));
2918 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2919 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2921 gtk_widget_set_tooltip_text(label, _("A flowchart of the sequence is shown in the Help file"));
2923 ct_button = pref_checkbox_new_int(group, "", options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2924 text_label = gtk_bin_get_child(GTK_BIN(ct_button));
2925 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"));
2926 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2928 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)"));
2929 gtk_widget_set_tooltip_markup(ct_button, markup);
2933 gtk_widget_set_sensitive(ct_button, FALSE);
2936 tmp_widget = pref_checkbox_new_int(group, "", options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2937 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2938 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)"));
2939 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2942 label = pref_label_new(group, "");
2943 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(), "/");
2944 gtk_label_set_markup (GTK_LABEL(label), markup);
2947 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2948 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2949 gtk_widget_set_margin_start(label, 22);
2950 pref_spacer(group, PREF_PAD_GROUP);
2952 group = pref_group_new(vbox, FALSE, _("Step 1 Options:"), GTK_ORIENTATION_VERTICAL);
2954 gtk_widget_set_sensitive(group, FALSE);
2957 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2958 pref_checkbox_link_sensitivity(ct_button, hbox);
2960 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);
2961 gtk_widget_set_tooltip_text(tmp_widget, _("A simplified conversion list is in the Help file"));
2963 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);
2965 pref_checkbox_new_int(hbox, _("Ask before writing to image files"), options->metadata.confirm_write, &c_options->metadata.confirm_write);
2967 tmp_widget= pref_checkbox_new_int(hbox, "", options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2968 gtk_widget_set_tooltip_text(tmp_widget, _("This file naming convention is used by Darktable"));
2969 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2970 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", ")");
2971 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2974 pref_spacer(group, PREF_PAD_GROUP);
2976 group = pref_group_new(vbox, FALSE, _("Steps 2 and 3 Option:"), GTK_ORIENTATION_VERTICAL);
2978 gtk_widget_set_sensitive(group, FALSE);
2981 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);
2983 pref_spacer(group, PREF_PAD_GROUP);
2985 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2986 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);
2987 gtk_widget_set_tooltip_text(tmp_widget, _("See the Help file for a list of the tags used"));
2989 tmp_widget = pref_checkbox_new_int(group, _("Permit Keywords to be case-sensitive"), options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2990 gtk_widget_set_tooltip_text(tmp_widget, _("When selected, \"Place\" and \"place\" are two different keywords"));
2992 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"), options->metadata.write_orientation, &c_options->metadata.write_orientation);
2993 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"));
2996 gtk_widget_set_sensitive(ct_button, FALSE);
2999 pref_spacer(group, PREF_PAD_GROUP);
3001 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
3003 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"), options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
3005 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3006 pref_checkbox_link_sensitivity(ct_button, hbox);
3008 pref_spin_new_int(hbox, _("Timeout (seconds):"), nullptr, 0, 900, 1, options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
3010 pref_checkbox_new_int(group, _("Write metadata on image change"), options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
3012 pref_checkbox_new_int(group, _("Write metadata on directory change"), options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
3014 pref_spacer(group, PREF_PAD_GROUP);
3017 group = pref_group_new(vbox, FALSE, _("Spelling checks"), GTK_ORIENTATION_VERTICAL);
3019 ct_button = pref_checkbox_new_int(group, _("Check spelling - Requires restart"), options->metadata.check_spelling, &c_options->metadata.check_spelling);
3020 gtk_widget_set_tooltip_text(ct_button, _("Spelling checks are performed on info sidebar panes Comment, Headline and Title"));
3023 pref_spacer(group, PREF_PAD_GROUP);
3025 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
3027 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"), options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
3028 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");
3033 struct KeywordFindData
3040 GtkWidget *button_close;
3041 GtkWidget *button_stop;
3042 GtkWidget *button_start;
3043 GtkWidget *progress;
3051 guint idle_id; /* event source id */
3054 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
3056 GList *list_d = nullptr;
3057 GList *list_f = nullptr;
3061 filelist_read(dir_fd, &list_f, &list_d);
3065 filelist_read(dir_fd, &list_f, nullptr);
3068 list_f = filelist_filter(list_f, FALSE);
3069 list_d = filelist_filter(list_d, TRUE);
3071 kfd->list = g_list_concat(list_f, kfd->list);
3072 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
3075 static void keywords_find_reset(KeywordFindData *kfd)
3077 filelist_free(kfd->list);
3078 kfd->list = nullptr;
3080 filelist_free(kfd->list_dir);
3081 kfd->list_dir = nullptr;
3084 static void keywords_find_close_cb(GenericDialog *, gpointer data)
3086 auto kfd = static_cast<KeywordFindData *>(data);
3088 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
3090 keywords_find_reset(kfd);
3091 generic_dialog_close(kfd->gd);
3095 static void keywords_find_finish(KeywordFindData *kfd)
3097 keywords_find_reset(kfd);
3099 gq_gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
3100 gtk_spinner_stop(GTK_SPINNER(kfd->spinner));
3102 gtk_widget_set_sensitive(kfd->group, TRUE);
3103 gtk_widget_set_sensitive(kfd->button_start, TRUE);
3104 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3105 gtk_widget_set_sensitive(kfd->button_close, TRUE);
3108 static void keywords_find_stop_cb(GenericDialog *, gpointer data)
3110 auto kfd = static_cast<KeywordFindData *>(data);
3112 g_idle_remove_by_data(kfd);
3114 keywords_find_finish(kfd);
3117 static gboolean keywords_find_file(gpointer data)
3119 auto kfd = static_cast<KeywordFindData *>(data);
3121 GtkTextBuffer *buffer;
3129 fd = static_cast<FileData *>(kfd->list->data);
3130 kfd->list = g_list_remove(kfd->list, fd);
3132 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
3133 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3137 gtk_text_buffer_get_end_iter(buffer, &iter);
3138 tmp = g_strconcat(static_cast<const gchar *>(keywords->data), "\n", NULL);
3139 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3141 keywords = keywords->next;
3144 gq_gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
3145 file_data_unref(fd);
3146 g_list_free_full(keywords, g_free);
3148 return (G_SOURCE_CONTINUE);
3155 fd = static_cast<FileData *>(kfd->list_dir->data);
3156 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
3158 keywords_find_folder(kfd, fd);
3160 file_data_unref(fd);
3162 return G_SOURCE_CONTINUE;
3165 keywords_find_finish(kfd);
3167 return G_SOURCE_REMOVE;
3170 static void keywords_find_start_cb(GenericDialog *, gpointer data)
3172 auto kfd = static_cast<KeywordFindData *>(data);
3175 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
3177 path = remove_trailing_slash((gq_gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
3178 parse_out_relatives(path);
3182 warning_dialog(_("Invalid folder"),
3183 _("The specified folder can not be found."),
3184 GQ_ICON_DIALOG_WARNING, kfd->gd->dialog);
3190 gtk_widget_set_sensitive(kfd->group, FALSE);
3191 gtk_widget_set_sensitive(kfd->button_start, FALSE);
3192 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
3193 gtk_widget_set_sensitive(kfd->button_close, FALSE);
3194 gtk_spinner_start(GTK_SPINNER(kfd->spinner));
3196 dir_fd = file_data_new_dir(path);
3197 keywords_find_folder(kfd, dir_fd);
3198 file_data_unref(dir_fd);
3199 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
3205 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
3207 KeywordFindData *kfd;
3211 kfd = g_new0(KeywordFindData, 1);
3213 kfd->gd = generic_dialog_new(_("Search for keywords"),
3214 "search_for_keywords",
3217 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
3218 kfd->gd->cancel_cb = keywords_find_close_cb;
3219 kfd->button_close = generic_dialog_add_button(kfd->gd, GQ_ICON_CLOSE, _("Close"),
3220 keywords_find_close_cb, FALSE);
3221 kfd->button_start = generic_dialog_add_button(kfd->gd, GQ_ICON_OK, _("S_tart"),
3222 keywords_find_start_cb, FALSE);
3223 kfd->button_stop = generic_dialog_add_button(kfd->gd, GQ_ICON_STOP, _("Stop"),
3224 keywords_find_stop_cb, FALSE);
3225 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3227 generic_dialog_add_message(kfd->gd, nullptr, _("Search for keywords"), nullptr, FALSE);
3229 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
3230 pref_spacer(hbox, PREF_PAD_INDENT);
3231 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
3233 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3234 pref_label_new(hbox, _("Folder:"));
3236 label = tab_completion_new(&kfd->entry, path, nullptr, nullptr, nullptr, nullptr);
3237 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
3238 gq_gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
3239 gtk_widget_show(label);
3241 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
3243 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
3244 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3246 kfd->progress = gtk_entry_new();
3247 gtk_widget_set_can_focus(kfd->progress, FALSE);
3248 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
3249 gq_gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
3250 gq_gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
3251 gtk_widget_show(kfd->progress);
3253 kfd->spinner = gtk_spinner_new();
3254 gq_gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
3255 gtk_widget_show(kfd->spinner);
3257 kfd->list = nullptr;
3259 gtk_widget_show(kfd->gd->dialog);
3262 static void keywords_find_cb(GtkWidget *widget, gpointer)
3264 const gchar *path = layout_get_path(nullptr);
3266 if (!path || !*path) path = homedir();
3267 keywords_find_dialog(widget, path);
3270 static void config_tab_keywords_save()
3274 GtkTextBuffer *buffer;
3275 GList *kw_list = nullptr;
3281 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3282 gtk_text_buffer_get_bounds(buffer, &start, &end);
3284 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3286 kw_split = strtok(buffer_text, "\n");
3287 while (kw_split != nullptr)
3293 if (g_strcmp0(static_cast<const gchar *>(work->data), kw_split) == 0)
3302 kw_list = g_list_append(kw_list, g_strdup(kw_split));
3304 kw_split = strtok(nullptr, "\n");
3307 keyword_list_set(kw_list);
3309 g_list_free_full(kw_list, g_free);
3310 g_free(buffer_text);
3313 static void config_tab_keywords(GtkWidget *notebook)
3319 GtkWidget *scrolled;
3321 GtkTextBuffer *buffer;
3324 GspellTextView *gspell_view;
3327 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3329 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3331 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3333 button = pref_button_new(hbox, GQ_ICON_RUN, _("Search"),
3334 G_CALLBACK(keywords_find_cb), keyword_text);
3335 gtk_widget_set_tooltip_text(button, _("Search for existing keywords"));
3338 keyword_text = gtk_text_view_new();
3339 gtk_widget_set_size_request(keyword_text, 20, 20);
3340 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
3341 gq_gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3342 gtk_widget_show(scrolled);
3345 if (options->metadata.check_spelling)
3347 gspell_view = gspell_text_view_get_from_gtk_text_view(GTK_TEXT_VIEW(keyword_text));
3348 gspell_text_view_basic_setup(gspell_view);
3352 gq_gtk_container_add(GTK_WIDGET(scrolled), keyword_text);
3353 gtk_widget_show(keyword_text);
3355 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3357 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3358 gtk_text_buffer_create_tag(buffer, "monospace",
3359 "family", "monospace", NULL);
3361 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3362 gtk_text_buffer_get_start_iter(buffer, &iter);
3363 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3366 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3368 GList *kwl = keyword_list_get();
3369 kwl = g_list_first(kwl);
3372 gtk_text_buffer_get_end_iter (buffer, &iter);
3373 tmp = g_strconcat(static_cast<const gchar *>(kwl->data), "\n", NULL);
3374 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3379 gtk_text_buffer_set_modified(buffer, FALSE);
3386 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3388 auto option = static_cast<gint *>(data);
3390 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3394 *option = INTENT_PERCEPTUAL;
3397 *option = INTENT_RELATIVE_COLORIMETRIC;
3400 *option = INTENT_SATURATION;
3403 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3408 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3409 gint option, gint *option_c)
3416 pref_table_label(table, column, row, text, GTK_ALIGN_START);
3418 combo = gtk_combo_box_text_new();
3420 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3421 if (option == INTENT_PERCEPTUAL) current = 0;
3422 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3423 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3424 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3425 if (option == INTENT_SATURATION) current = 2;
3426 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3427 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3429 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3431 gtk_widget_set_tooltip_text(combo,_("Refer to the lcms documentation for the defaults used when the selected Intent is not available"));
3433 g_signal_connect(G_OBJECT(combo), "changed",
3434 G_CALLBACK(intent_menu_cb), option_c);
3436 gq_gtk_grid_attach(GTK_GRID(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
3437 gtk_widget_show(combo);
3441 static void config_tab_color(GtkWidget *notebook)
3450 vbox = scrolled_notebook_page(notebook, _("Color management"));
3452 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3454 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3457 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3458 gtk_grid_set_column_spacing(GTK_GRID(table), PREF_PAD_GAP);
3460 label = pref_table_label(table, 0, 0, _("Type"), GTK_ALIGN_START);
3461 pref_label_bold(label, TRUE, FALSE);
3463 label = pref_table_label(table, 1, 0, _("Menu name"), GTK_ALIGN_START);
3464 pref_label_bold(label, TRUE, FALSE);
3466 label = pref_table_label(table, 2, 0, _("File"), GTK_ALIGN_START);
3467 pref_label_bold(label, TRUE, FALSE);
3469 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3474 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3475 pref_table_label(table, 0, i + 1, buf, GTK_ALIGN_END);
3478 entry = gtk_entry_new();
3479 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3480 if (options->color_profile.input_name[i])
3482 gq_gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3484 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);
3485 gtk_widget_show(entry);
3486 color_profile_input_name_entry[i] = entry;
3488 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], nullptr, ".icc", "ICC Files", nullptr);
3489 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3490 gtk_widget_set_size_request(entry, 160, -1);
3491 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);
3492 gtk_widget_show(tabcomp);
3493 color_profile_input_file_entry[i] = entry;
3496 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3498 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3500 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3501 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3503 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3505 pref_table_label(table, 0, 0, _("Screen:"), GTK_ALIGN_END);
3506 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3507 options->color_profile.screen_file, nullptr, ".icc", "ICC Files", nullptr);
3508 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3509 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3511 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3513 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);
3515 gtk_widget_show(tabcomp);
3518 /* advanced entry tab */
3519 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer)
3521 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3523 c_options->file_ops.use_system_trash = FALSE;
3524 c_options->file_ops.no_trash = FALSE;
3528 static void use_system_trash_cb(GtkWidget *widget, gpointer)
3530 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3532 c_options->file_ops.use_system_trash = TRUE;
3533 c_options->file_ops.no_trash = FALSE;
3537 static void use_no_cache_cb(GtkWidget *widget, gpointer)
3539 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3541 c_options->file_ops.no_trash = TRUE;
3545 static void config_tab_behavior(GtkWidget *notebook)
3552 GtkWidget *ct_button;
3556 GtkWidget *with_rename;
3557 GtkWidget *collections_on_top;
3558 GtkWidget *hide_window_in_fullscreen;
3559 GtkWidget *hide_osd_in_fullscreen;
3560 GtkWidget *checkbox;
3563 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3565 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3567 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3568 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3569 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3570 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3571 pref_checkbox_new_int(group, _("Enable Delete key"),
3572 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3574 ct_button = pref_radiobutton_new(group, nullptr, _("Use Geeqie trash location"),
3575 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),nullptr);
3577 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3578 pref_checkbox_link_sensitivity(ct_button, hbox);
3580 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3581 pref_label_new(hbox, _("Folder:"));
3583 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, nullptr, nullptr, nullptr, nullptr);
3584 tab_completion_add_select_button(safe_delete_path_entry, nullptr, TRUE);
3585 gq_gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3586 gtk_widget_show(tabcomp);
3588 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3589 pref_checkbox_link_sensitivity(ct_button, hbox);
3591 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3592 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MiB"),
3593 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3594 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3595 button = pref_button_new(nullptr, nullptr, _("View"),
3596 G_CALLBACK(safe_delete_view_cb), nullptr);
3597 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3598 gtk_widget_show(button);
3600 button = pref_button_new(nullptr, GQ_ICON_CLEAR, nullptr,
3601 G_CALLBACK(safe_delete_clear_cb), nullptr);
3602 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3604 c_options->file_ops.no_trash = options->file_ops.no_trash;
3605 c_options->file_ops.use_system_trash = options->file_ops.use_system_trash;
3607 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3608 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), nullptr);
3610 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3611 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), nullptr);
3613 gtk_widget_show(button);
3615 pref_spacer(group, PREF_PAD_GROUP);
3618 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3620 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3621 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3623 pref_checkbox_new_int(group, _("In place renaming"),
3624 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3626 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3627 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3629 tmp = pref_checkbox_new_int(group, _("Circular selection lists"),
3630 options->circular_selection_lists, &c_options->circular_selection_lists);
3631 gtk_widget_set_tooltip_text(tmp, _("Traverse selection lists in a circular manner"));
3633 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3634 options->marks_save, &c_options->marks_save);
3635 gtk_widget_set_tooltip_text(marks,_("Note that marks linked to a keyword will be saved irrespective of this setting"));
3637 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3638 options->with_rename, &c_options->with_rename);
3639 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3641 collections_on_top = pref_checkbox_new_int(group, _("Permit duplicates in Collections"),
3642 options->collections_duplicates, &c_options->collections_duplicates);
3643 gtk_widget_set_tooltip_text(collections_on_top, _("Allow the same image to be in a Collection more than once"));
3645 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3646 options->collections_on_top, &c_options->collections_on_top);
3647 gtk_widget_set_tooltip_text(collections_on_top, _("Open collections window on top"));
3649 hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3650 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3651 gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice");
3653 hide_osd_in_fullscreen = pref_checkbox_new_int(group, _("Hide OSD in fullscreen"),
3654 options->hide_osd_in_fullscreen, &c_options->hide_osd_in_fullscreen);
3655 gtk_widget_set_tooltip_text(hide_osd_in_fullscreen,"Hide Overlay Screen Display in fullscreen mode");
3657 pref_spin_new_int(group, _("Recent folder list maximum size"), nullptr,
3658 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3660 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);
3661 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."));
3663 pref_spin_new_int(group, _("Drag'n drop icon size"), nullptr,
3664 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3666 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3667 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3669 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3670 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3672 pref_spacer(group, PREF_PAD_GROUP);
3674 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3676 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3677 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3678 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), nullptr,
3679 1, 32, 1, options->keyboard_scroll_step, reinterpret_cast<int *>(&c_options->keyboard_scroll_step));
3680 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3681 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3682 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3683 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3684 pref_checkbox_new_int(group, _("Open archive by left click on image"),
3685 options->image_l_click_archive, &c_options->image_l_click_archive);
3686 pref_checkbox_new_int(group, _("Play video by left click on image"),
3687 options->image_l_click_video, &c_options->image_l_click_video);
3688 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3689 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3691 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3692 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3693 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3694 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3695 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3697 pref_spacer(group, PREF_PAD_GROUP);
3699 group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3701 checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3702 options->override_disable_gpu, &c_options->override_disable_gpu);
3703 gtk_widget_set_tooltip_text(checkbox, _("Contact the developers for usage"));
3706 pref_spacer(group, PREF_PAD_GROUP);
3708 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3710 pref_spin_new_int(group, _("Debug level:"), nullptr,
3711 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3713 pref_checkbox_new_int(group, _("Timer data"),
3714 options->log_window.timer_data, &c_options->log_window.timer_data);
3716 pref_spin_new_int(group, _("Log Window max. lines:"), nullptr,
3717 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3719 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3720 pref_label_new(hbox, _("Log Window F1 command: "));
3721 log_window_f1_entry = gtk_entry_new();
3722 gq_gtk_entry_set_text(GTK_ENTRY(log_window_f1_entry), options->log_window.action);
3723 gq_gtk_box_pack_start(GTK_BOX(hbox), log_window_f1_entry, FALSE, FALSE, 0);
3724 gtk_entry_set_width_chars(GTK_ENTRY(log_window_f1_entry), 15);
3725 gtk_widget_show(log_window_f1_entry);
3729 /* accelerators tab */
3731 static gboolean accel_search_function_cb(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer)
3733 gboolean ret = TRUE;
3738 gtk_tree_model_get(model, iter, column, &text, -1);
3739 text_nocase = g_utf8_casefold(text, -1);
3740 key_nocase = g_utf8_casefold(key, -1);
3742 if (g_strstr_len(text_nocase, -1, key_nocase))
3749 g_free(text_nocase);
3754 static void accel_row_activated_cb(GtkTreeView *tree_view, GtkTreePath *, GtkTreeViewColumn *column, gpointer)
3759 list = gtk_tree_view_get_columns(tree_view);
3760 col_num = g_list_index(list, column);
3764 gtk_tree_view_set_search_column(tree_view, col_num);
3767 static void config_tab_accelerators(GtkWidget *notebook)
3773 GtkWidget *scrolled;
3774 GtkWidget *accel_view;
3775 GtkCellRenderer *renderer;
3776 GtkTreeSelection *selection;
3777 GtkTreeViewColumn *column;
3779 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3781 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3783 scrolled = gq_gtk_scrolled_window_new(nullptr, nullptr);
3784 gq_gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3785 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3786 gq_gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3787 gtk_widget_show(scrolled);
3789 accel_store = gtk_tree_store_new(5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3791 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3792 g_object_unref(accel_store);
3793 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3794 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3796 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3798 renderer = gtk_cell_renderer_text_new();
3800 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3805 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3806 gtk_tree_view_column_set_resizable(column, TRUE);
3807 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3810 renderer = gtk_cell_renderer_accel_new();
3811 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3812 G_CALLBACK(accel_store_cleared_cb), accel_store);
3813 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3814 G_CALLBACK(accel_store_edited_cb), accel_store);
3817 g_object_set (renderer,
3819 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3822 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3827 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3828 gtk_tree_view_column_set_resizable(column, TRUE);
3829 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3831 renderer = gtk_cell_renderer_text_new();
3833 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3838 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3839 gtk_tree_view_column_set_resizable(column, TRUE);
3840 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3842 renderer = gtk_cell_renderer_text_new();
3844 column = gtk_tree_view_column_new_with_attributes("Accel",
3849 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3850 gtk_tree_view_column_set_resizable(column, TRUE);
3851 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3853 column = gtk_tree_view_column_new_with_attributes("Icon",
3858 gtk_tree_view_column_set_sort_column_id(column, AE_ICON);
3859 gtk_tree_view_column_set_resizable(column, TRUE);
3860 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3862 /* Search on text in column */
3863 gtk_tree_view_set_activate_on_single_click(GTK_TREE_VIEW(accel_view), TRUE);
3864 g_signal_connect(accel_view, "row_activated", G_CALLBACK(accel_row_activated_cb), accel_store);
3865 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), TRUE);
3866 gtk_tree_view_set_search_column(GTK_TREE_VIEW(accel_view), AE_TOOLTIP);
3867 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(accel_view), accel_search_function_cb, nullptr, nullptr);
3869 accel_store_populate();
3870 gq_gtk_container_add(GTK_WIDGET(scrolled), accel_view);
3871 gtk_widget_show(accel_view);
3873 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3875 button = pref_button_new(nullptr, nullptr, _("Defaults"),
3876 G_CALLBACK(accel_default_cb), accel_view);
3877 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3878 gtk_widget_show(button);
3880 button = pref_button_new(nullptr, nullptr, _("Reset selected"),
3881 G_CALLBACK(accel_reset_cb), accel_view);
3882 gtk_widget_set_tooltip_text(button, _("Will only reset changes made before the settings are saved"));
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, _("Clear selected"),
3887 G_CALLBACK(accel_clear_cb), accel_view);
3888 gq_gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3889 gtk_widget_show(button);
3892 /* toolbar main tab */
3893 static void config_tab_toolbar_main(GtkWidget *notebook)
3896 GtkWidget *toolbardata;
3899 lw = static_cast<LayoutWindow *>(layout_window_list->data);
3901 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3903 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3904 gq_gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3905 gtk_widget_show(vbox);
3908 /* toolbar status tab */
3909 static void config_tab_toolbar_status(GtkWidget *notebook)
3912 GtkWidget *toolbardata;
3915 lw = static_cast<LayoutWindow *>(layout_window_list->data);
3917 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3919 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3920 gq_gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3921 gtk_widget_show(vbox);
3925 static gint extension_sort_cb(gconstpointer a, gconstpointer b)
3927 return g_strcmp0(static_cast<const gchar *>(a), static_cast<const gchar *>(b));
3930 static void config_tab_advanced(GtkWidget *notebook)
3933 GdkPixbufFormat *fm;
3935 GList *extensions_list = nullptr;
3936 GSList *formats_list;
3937 GString *types_string = g_string_new(nullptr);
3938 GtkWidget *alternate_checkbox;
3939 GtkWidget *dupes_threads_spin;
3941 GtkWidget *subgroup;
3943 GtkWidget *threads_string_label;
3944 GtkWidget *types_string_label;
3947 vbox = scrolled_notebook_page(notebook, _("Advanced"));
3948 group = pref_group_new(vbox, FALSE, _("External preview extraction"), GTK_ORIENTATION_VERTICAL);
3950 pref_checkbox_new_int(group, _("Use external preview extraction - Requires restart"), options->external_preview.enable, &c_options->external_preview.enable);
3952 pref_spacer(group, PREF_PAD_GROUP);
3954 formats_list = gdk_pixbuf_get_formats();
3956 while (formats_list)
3958 fm = static_cast<GdkPixbufFormat *>(formats_list->data);
3959 extensions = gdk_pixbuf_format_get_extensions(fm);
3962 while (extensions[i])
3964 extensions_list = g_list_insert_sorted(extensions_list, g_strdup(extensions[i]), extension_sort_cb);
3968 g_strfreev(extensions);
3969 formats_list = formats_list->next;
3972 while (extensions_list)
3974 if (types_string->len == 0)
3976 types_string = g_string_append(types_string, static_cast<const gchar *>(extensions_list->data));
3980 types_string = g_string_append(types_string, ", ");
3981 types_string = g_string_append(types_string, static_cast<const gchar *>(extensions_list->data));
3984 extensions_list = extensions_list->next;
3987 types_string = g_string_prepend(types_string, _("Usable file types:\n"));
3988 types_string_label = pref_label_new(group, types_string->str);
3989 gtk_label_set_line_wrap(GTK_LABEL(types_string_label), TRUE);
3991 pref_spacer(group, PREF_PAD_GROUP);
3993 group = pref_group_new(vbox, FALSE, _("File identification tool"), GTK_ORIENTATION_VERTICAL);
3994 external_preview_select_entry = gtk_entry_new();
3995 tabcomp = tab_completion_new(&external_preview_select_entry, options->external_preview.select, nullptr, nullptr, nullptr, nullptr);
3996 tab_completion_add_select_button(external_preview_select_entry, _("Select file identification tool"), FALSE);
3997 gq_gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3998 gtk_widget_show(tabcomp);
4000 group = pref_group_new(vbox, FALSE, _("Preview extraction tool"), GTK_ORIENTATION_VERTICAL);
4001 external_preview_extract_entry = gtk_entry_new();
4002 tabcomp = tab_completion_new(&external_preview_extract_entry, options->external_preview.extract, nullptr, nullptr, nullptr, nullptr);
4003 tab_completion_add_select_button(external_preview_extract_entry, _("Select preview extraction tool"), FALSE);
4004 gq_gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
4005 gtk_widget_show(tabcomp);
4007 gtk_widget_show(vbox);
4009 g_slist_free(formats_list);
4010 g_list_free_full(extensions_list, g_free);
4011 g_string_free(types_string, TRUE);
4013 pref_spacer(group, PREF_PAD_GROUP);
4015 pref_line(vbox, PREF_PAD_SPACE);
4016 group = pref_group_new(vbox, FALSE, _("Thread pool limits"), GTK_ORIENTATION_VERTICAL);
4018 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."));
4019 gtk_label_set_line_wrap(GTK_LABEL(threads_string_label), TRUE);
4021 pref_spacer(vbox, PREF_PAD_GROUP);
4023 dupes_threads_spin = pref_spin_new_int(vbox, _("Duplicate check:"), _("max. threads"), 0, get_cpu_cores(), 1, options->threads.duplicates, &c_options->threads.duplicates);
4024 gtk_widget_set_tooltip_markup(dupes_threads_spin, _("Set to 0 for unlimited"));
4026 pref_spacer(group, PREF_PAD_GROUP);
4028 pref_line(vbox, PREF_PAD_SPACE);
4030 group = pref_group_new(vbox, FALSE, _("Alternate similarity alogorithm"), GTK_ORIENTATION_VERTICAL);
4032 alternate_checkbox = pref_checkbox_new_int(group, _("Enable alternate similarity algorithm"), options->alternate_similarity_algorithm.enabled, &c_options->alternate_similarity_algorithm.enabled);
4034 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
4035 pref_checkbox_link_sensitivity(alternate_checkbox, subgroup);
4037 alternate_checkbox = pref_checkbox_new_int(subgroup, _("Use grayscale"), options->alternate_similarity_algorithm.grayscale, &c_options->alternate_similarity_algorithm.grayscale);
4038 gtk_widget_set_tooltip_text(alternate_checkbox, _("Reduce fingerprint to grayscale"));
4042 static void config_tab_stereo(GtkWidget *notebook)
4050 GtkWidget *fs_button;
4051 vbox = scrolled_notebook_page(notebook, _("Stereo"));
4053 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
4055 table = pref_table_new(group, 2, 1, FALSE, FALSE);
4056 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
4058 table = pref_table_new(group, 2, 2, TRUE, FALSE);
4059 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
4060 pref_checkbox_new_int(box, _("Mirror left image"),
4061 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
4062 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
4063 pref_checkbox_new_int(box, _("Flip left image"),
4064 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
4065 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
4066 pref_checkbox_new_int(box, _("Mirror right image"),
4067 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
4068 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
4069 pref_checkbox_new_int(box, _("Flip right image"),
4070 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
4071 pref_checkbox_new_int(group, _("Swap left and right images"),
4072 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
4073 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
4074 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
4076 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
4077 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
4078 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
4079 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
4080 pref_checkbox_link_sensitivity(fs_button, box2);
4081 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
4082 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
4083 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
4084 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
4085 pref_checkbox_new_int(box, _("Mirror left image"),
4086 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
4087 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
4088 pref_checkbox_new_int(box, _("Flip left image"),
4089 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
4090 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
4091 pref_checkbox_new_int(box, _("Mirror right image"),
4092 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
4093 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
4094 pref_checkbox_new_int(box, _("Flip right image"),
4095 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
4096 pref_checkbox_new_int(box2, _("Swap left and right images"),
4097 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
4098 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
4099 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
4101 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
4102 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
4103 pref_table_spin_new_int(table, 0, 0, _("Width"), nullptr,
4104 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
4105 pref_table_spin_new_int(table, 3, 0, _("Height"), nullptr,
4106 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
4107 pref_table_spin_new_int(table, 0, 1, _("Left X"), nullptr,
4108 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
4109 pref_table_spin_new_int(table, 3, 1, _("Left Y"), nullptr,
4110 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
4111 pref_table_spin_new_int(table, 0, 2, _("Right X"), nullptr,
4112 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
4113 pref_table_spin_new_int(table, 3, 2, _("Right Y"), nullptr,
4114 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
4118 /* Main preferences window */
4119 static void config_window_create(LayoutWindow *lw)
4121 GtkWidget *win_vbox;
4123 GtkWidget *notebook;
4125 GtkWidget *ct_button;
4127 if (!c_options) c_options = init_options(nullptr);
4129 configwindow = window_new("preferences", PIXBUF_INLINE_ICON_CONFIG, nullptr, _("Preferences"));
4130 DEBUG_NAME(configwindow);
4131 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
4132 g_signal_connect(G_OBJECT(configwindow), "delete_event",
4133 G_CALLBACK(config_window_delete), NULL);
4134 if (options->save_dialog_window_positions)
4136 gtk_window_resize(GTK_WINDOW(configwindow), lw->options.preferences_window.w, lw->options.preferences_window.h);
4137 gq_gtk_window_move(GTK_WINDOW(configwindow), lw->options.preferences_window.x, lw->options.preferences_window.y);
4141 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
4143 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
4144 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
4146 win_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
4147 gq_gtk_container_add(GTK_WIDGET(configwindow), win_vbox);
4148 gtk_widget_show(win_vbox);
4150 notebook = gtk_notebook_new();
4151 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
4152 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
4153 gq_gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
4155 config_tab_general(notebook);
4156 config_tab_image(notebook);
4157 config_tab_osd(notebook);
4158 config_tab_windows(notebook);
4159 config_tab_accelerators(notebook);
4160 config_tab_files(notebook);
4161 config_tab_metadata(notebook);
4162 config_tab_keywords(notebook);
4163 config_tab_color(notebook);
4164 config_tab_stereo(notebook);
4165 config_tab_behavior(notebook);
4166 config_tab_toolbar_main(notebook);
4167 config_tab_toolbar_status(notebook);
4168 config_tab_advanced(notebook);
4170 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), lw->options.preferences_window.page_number);
4172 hbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
4173 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
4174 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
4175 gq_gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
4176 gtk_widget_show(hbox);
4178 button = pref_button_new(nullptr, GQ_ICON_HELP, _("Help"),
4179 G_CALLBACK(config_window_help_cb), notebook);
4180 gq_gtk_container_add(GTK_WIDGET(hbox), button);
4181 gtk_widget_set_can_default(button, TRUE);
4182 gtk_widget_show(button);
4184 button = pref_button_new(nullptr, GQ_ICON_OK, "OK",
4185 G_CALLBACK(config_window_ok_cb), notebook);
4186 gq_gtk_container_add(GTK_WIDGET(hbox), button);
4187 gtk_widget_set_can_default(button, TRUE);
4188 gtk_widget_grab_default(button);
4189 gtk_widget_show(button);
4193 button = pref_button_new(nullptr, GQ_ICON_CANCEL, _("Cancel"),
4194 G_CALLBACK(config_window_close_cb), nullptr);
4195 gq_gtk_container_add(GTK_WIDGET(hbox), button);
4196 gtk_widget_set_can_default(button, TRUE);
4197 gtk_widget_show(button);
4199 if (!generic_dialog_get_alternative_button_order(configwindow))
4201 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
4204 gtk_widget_show(notebook);
4206 gtk_widget_show(configwindow);
4210 *-----------------------------------------------------------------------------
4211 * config window show (public)
4212 *-----------------------------------------------------------------------------
4215 void show_config_window(LayoutWindow *lw)
4219 gtk_window_present(GTK_WINDOW(configwindow));
4223 config_window_create(lw);
4232 void show_about_window(LayoutWindow *lw)
4234 GDataInputStream *data_stream;
4235 GInputStream *in_stream_authors;
4236 GInputStream *in_stream_translators;
4238 GdkPixbuf *pixbuf_icon;
4239 GdkPixbuf *pixbuf_logo;
4243 gchar *authors[1000];
4245 gchar *timezone_path;
4254 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"));
4256 timezone_path = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
4257 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
4259 cd = ZDOpenDatabase(timezone_path);
4262 copyright = g_string_append(copyright, ZDGetNotice(cd));
4266 log_printf("Error: Init of timezone database %s failed\n", timezone_path);
4268 ZDCloseDatabase(cd);
4270 g_free(timezone_path);
4272 copyright = g_string_append(copyright, _("\n\nSome icons by https://www.flaticon.com"));
4274 in_stream_authors = g_resources_open_stream(GQ_RESOURCE_PATH_CREDITS "/authors", G_RESOURCE_LOOKUP_FLAGS_NONE, nullptr);
4276 data_stream = g_data_input_stream_new(in_stream_authors);
4278 authors[0] = nullptr;
4279 while ((author_line = g_data_input_stream_read_line(G_DATA_INPUT_STREAM(data_stream), &length, nullptr, nullptr)))
4281 authors[i_authors] = g_strdup(author_line);
4283 g_free(author_line);
4285 authors[i_authors] = nullptr;
4287 g_input_stream_close(in_stream_authors, nullptr, nullptr);
4289 constexpr auto translators_path = GQ_RESOURCE_PATH_CREDITS "/translators";
4291 g_resources_get_info(translators_path, G_RESOURCE_LOOKUP_FLAGS_NONE, &size, &flags, nullptr);
4293 in_stream_translators = g_resources_open_stream(translators_path, G_RESOURCE_LOOKUP_FLAGS_NONE, nullptr);
4294 translators = static_cast<gchar *>(g_malloc0(size));
4295 g_input_stream_read_all(in_stream_translators, translators, size, &bytes_read, nullptr, nullptr);
4296 g_input_stream_close(in_stream_translators, nullptr, nullptr);
4298 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);
4300 artists[0] = g_strdup("Néstor Díaz Valencia <nestor@estudionexos.com>");
4301 artists[1] = nullptr;
4303 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
4304 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
4305 gtk_show_about_dialog(GTK_WINDOW(lw->window),
4306 "title", _("About Geeqie"),
4308 "program-name", GQ_APPNAME,
4310 "logo", pixbuf_logo,
4311 "icon", pixbuf_icon,
4312 "website", GQ_WEBSITE,
4313 "website-label", _("Website"),
4314 "comments", comment,
4317 "translator-credits", translators,
4318 "wrap-license", TRUE,
4319 "license", copyright->str,
4322 g_string_free(copyright, TRUE);
4324 while(n < i_authors)
4332 g_free(translators);
4333 g_object_unref(data_stream);
4334 g_object_unref(in_stream_authors);
4335 g_object_unref(in_stream_translators);
4338 static void image_overlay_set_text_colors()
4340 c_options->image_overlay.text_red = options->image_overlay.text_red;
4341 c_options->image_overlay.text_green = options->image_overlay.text_green;
4342 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
4343 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
4344 c_options->image_overlay.background_red = options->image_overlay.background_red;
4345 c_options->image_overlay.background_green = options->image_overlay.background_green;
4346 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
4347 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
4351 *-----------------------------------------------------------------------------
4352 * timezone database routines
4353 *-----------------------------------------------------------------------------
4356 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
4358 GError *error = nullptr;
4359 auto tz = static_cast<TZData *>(data);
4360 gchar *tmp_filename;
4361 gchar *timezone_bin;
4362 gchar *tmp_dir = nullptr;
4365 if (!g_cancellable_is_cancelled(tz->cancellable))
4367 generic_dialog_close(tz->gd);
4371 if (g_file_copy_finish(G_FILE(source_object), res, &error))
4373 tmp_filename = g_file_get_path(tz->tmp_g_file);
4374 fd = file_data_new_simple(tmp_filename);
4375 tmp_dir = open_archive(fd);
4379 timezone_bin = g_build_filename(tmp_dir, TIMEZONE_DATABASE_VERSION, TIMEZONE_DATABASE_FILE, NULL);
4380 if (isfile(timezone_bin))
4382 move_file(timezone_bin, tz->timezone_database_user);
4386 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GQ_ICON_DIALOG_WARNING, nullptr);
4389 g_free(timezone_bin);
4390 g_free(tmp_dir); // The folder in /tmp is deleted in exit_program_final()
4394 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GQ_ICON_DIALOG_WARNING, nullptr);
4396 g_free(tmp_filename);
4397 file_data_unref(fd);
4401 file_util_warning_dialog(_("Error: Timezone database download failed"), error->message, GQ_ICON_DIALOG_ERROR, nullptr);
4404 g_file_delete(tz->tmp_g_file, nullptr, &error);
4405 g_object_unref(tz->tmp_g_file);
4406 tz->tmp_g_file = nullptr;
4407 g_object_unref(tz->cancellable);
4408 g_object_unref(tz->timezone_database_gq);
4411 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
4413 auto tz = static_cast<TZData *>(data);
4415 if (!g_cancellable_is_cancelled(tz->cancellable))
4417 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), static_cast<gdouble>(current_num_bytes) / total_num_bytes);
4421 static void timezone_cancel_button_cb(GenericDialog *, gpointer data)
4423 auto tz = static_cast<TZData *>(data);
4425 g_cancellable_cancel(tz->cancellable);
4428 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
4430 auto tz = static_cast<TZData *>(data);
4431 GError *error = nullptr;
4432 GFileIOStream *io_stream;
4439 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
4443 file_util_warning_dialog(_("Timezone database download failed"), error->message, GQ_ICON_DIALOG_ERROR, nullptr);
4444 log_printf("Error: Download timezone database failed:\n%s", error->message);
4445 g_error_free(error);
4446 g_object_unref(tz->tmp_g_file);
4450 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE_WEB);
4452 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", nullptr, TRUE, timezone_cancel_button_cb, tz);
4454 generic_dialog_add_message(tz->gd, GQ_ICON_DIALOG_INFO, _("Downloading timezone database"), nullptr, FALSE);
4456 tz->progress = gtk_progress_bar_new();
4457 gq_gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
4458 gtk_widget_show(tz->progress);
4460 gtk_widget_show(tz->gd->dialog);
4461 tz->cancellable = g_cancellable_new();
4462 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);
4464 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
4467 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */