2 * Copyright (C) 2006 John Ellis
3 * Copyright (C) 2008 - 2016 The Geeqie Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "preferences.h"
25 #include "bar-keywords.h"
27 #include "color-man.h"
30 #include "filefilter.h"
31 #include "fullscreen.h"
33 #include "image-overlay.h"
35 #include "layout-util.h"
39 #include "pixbuf-util.h"
41 #include "slideshow.h"
45 #include "ui-fileops.h"
47 #include "ui-tabcomp.h"
49 #include "zonedetect.h"
60 #include <gspell/gspell.h>
63 #define EDITOR_NAME_MAX_LENGTH 32
64 #define EDITOR_COMMAND_MAX_LENGTH 1024
66 static void image_overlay_set_text_colours();
68 GtkWidget *keyword_text;
69 static void config_tab_keywords_save();
77 static ThumbSize thumb_size_list[] =
112 FILETYPES_COLUMN_ENABLED = 0,
113 FILETYPES_COLUMN_FILTER,
114 FILETYPES_COLUMN_DESCRIPTION,
115 FILETYPES_COLUMN_CLASS,
116 FILETYPES_COLUMN_WRITABLE,
117 FILETYPES_COLUMN_SIDECAR,
118 FILETYPES_COLUMN_COUNT
121 const gchar *format_class_list[] = {
132 /* config memory values */
133 static ConfOptions *c_options = nullptr;
140 static GtkWidget *configwindow = nullptr;
141 static GtkListStore *filter_store = nullptr;
142 static GtkTreeStore *accel_store = nullptr;
144 static GtkWidget *safe_delete_path_entry;
146 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
147 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
148 static GtkWidget *color_profile_screen_file_entry;
149 static GtkWidget *external_preview_select_entry;
150 static GtkWidget *external_preview_extract_entry;
152 static GtkWidget *sidecar_ext_entry;
153 static GtkWidget *help_search_engine_entry;
156 #define CONFIG_WINDOW_DEF_WIDTH 700
157 #define CONFIG_WINDOW_DEF_HEIGHT 600
160 *-----------------------------------------------------------------------------
161 * option widget callbacks (private)
162 *-----------------------------------------------------------------------------
165 static void zoom_increment_cb(GtkWidget *spin, gpointer)
167 c_options->image.zoom_increment = static_cast<gint>(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
170 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer)
172 gint mins_secs_tenths, delay;
174 mins_secs_tenths = c_options->slideshow.delay %
175 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
177 delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
178 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
181 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
182 SLIDESHOW_SUBSECOND_PRECISION;
185 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer)
187 gint hours, secs_tenths, delay;
189 hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
190 secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
192 delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
193 (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
194 (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
196 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
197 SLIDESHOW_SUBSECOND_PRECISION;
200 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer)
202 gint hours_mins, delay;
204 hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
206 delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
207 static_cast<gint>(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
208 static_cast<gdouble>(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
210 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
211 SLIDESHOW_SUBSECOND_PRECISION;
215 *-----------------------------------------------------------------------------
216 * sync program to config window routine (private)
217 *-----------------------------------------------------------------------------
220 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
226 buf = gtk_entry_get_text(GTK_ENTRY(entry));
227 if (buf && strlen(buf) > 0)
232 *option = g_strdup(buf);
237 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *, GtkTreeIter *iter, gpointer)
239 gchar *accel_path, *accel;
241 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
243 if (accel_path && accel_path[0])
246 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
247 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
257 static void config_window_apply()
259 gboolean refresh = FALSE;
264 config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
266 if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
267 if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
268 if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
269 if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
270 if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
271 if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
273 options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
274 options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
275 options->file_ops.confirm_move_to_trash = c_options->file_ops.confirm_move_to_trash;
276 options->file_ops.use_system_trash = c_options->file_ops.use_system_trash;
277 options->file_ops.no_trash = c_options->file_ops.no_trash;
278 options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
279 options->tools_restore_state = c_options->tools_restore_state;
280 options->save_window_positions = c_options->save_window_positions;
281 options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
282 options->save_window_workspace = c_options->save_window_workspace;
283 options->save_dialog_window_positions = c_options->save_dialog_window_positions;
284 options->show_window_ids = c_options->show_window_ids;
285 options->image.scroll_reset_method = c_options->image.scroll_reset_method;
286 options->image.zoom_2pass = c_options->image.zoom_2pass;
287 options->image.fit_window_to_image = c_options->image.fit_window_to_image;
288 options->image.limit_window_size = c_options->image.limit_window_size;
289 options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
290 options->image.max_window_size = c_options->image.max_window_size;
291 options->image.limit_autofit_size = c_options->image.limit_autofit_size;
292 options->image.max_autofit_size = c_options->image.max_autofit_size;
293 options->image.max_enlargement_size = c_options->image.max_enlargement_size;
294 options->image.tile_size = c_options->image.tile_size;
295 options->progressive_key_scrolling = c_options->progressive_key_scrolling;
296 options->keyboard_scroll_step = c_options->keyboard_scroll_step;
298 if (options->thumbnails.max_width != c_options->thumbnails.max_width
299 || options->thumbnails.max_height != c_options->thumbnails.max_height
300 || options->thumbnails.quality != c_options->thumbnails.quality)
302 thumb_format_changed = TRUE;
304 options->thumbnails.max_width = c_options->thumbnails.max_width;
305 options->thumbnails.max_height = c_options->thumbnails.max_height;
306 options->thumbnails.quality = c_options->thumbnails.quality;
308 options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
309 options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
310 options->thumbnails.use_exif = c_options->thumbnails.use_exif;
311 options->thumbnails.use_color_management = c_options->thumbnails.use_color_management;
312 options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
313 options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
314 options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
315 options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
316 options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
317 options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
318 options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
319 options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
321 options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
322 options->file_filter.disable = c_options->file_filter.disable;
324 config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, nullptr);
325 sidecar_ext_parse(options->sidecar.ext);
327 options->slideshow.random = c_options->slideshow.random;
328 options->slideshow.repeat = c_options->slideshow.repeat;
329 options->slideshow.delay = c_options->slideshow.delay;
331 options->mousewheel_scrolls = c_options->mousewheel_scrolls;
332 options->image_lm_click_nav = c_options->image_lm_click_nav;
333 options->image_l_click_archive = c_options->image_l_click_archive;
334 options->image_l_click_video = c_options->image_l_click_video;
335 options->image_l_click_video_editor = c_options->image_l_click_video_editor;
337 options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
339 options->image.tile_cache_max = c_options->image.tile_cache_max;
340 options->image.image_cache_max = c_options->image.image_cache_max;
342 options->image.zoom_quality = c_options->image.zoom_quality;
344 options->image.zoom_increment = c_options->image.zoom_increment;
346 options->image.zoom_style = c_options->image.zoom_style;
348 options->image.enable_read_ahead = c_options->image.enable_read_ahead;
350 options->appimage_notifications = c_options->appimage_notifications;
353 if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
354 || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
355 || !gdk_color_equal(&options->image.border_color, &c_options->image.border_color))
357 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
358 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
359 options->image.border_color = c_options->image.border_color;
360 layout_colors_update();
361 view_window_colors_update();
364 options->image.alpha_color_1 = c_options->image.alpha_color_1;
365 options->image.alpha_color_2 = c_options->image.alpha_color_2;
367 options->fullscreen.screen = c_options->fullscreen.screen;
368 options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
369 options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
370 options->fullscreen.above = c_options->fullscreen.above;
371 if (c_options->image_overlay.template_string)
372 set_image_overlay_template_string(&options->image_overlay.template_string,
373 c_options->image_overlay.template_string);
374 if (c_options->image_overlay.font)
375 set_image_overlay_font_string(&options->image_overlay.font,
376 c_options->image_overlay.font);
377 options->image_overlay.text_red = c_options->image_overlay.text_red;
378 options->image_overlay.text_green = c_options->image_overlay.text_green;
379 options->image_overlay.text_blue = c_options->image_overlay.text_blue;
380 options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
381 options->image_overlay.background_red = c_options->image_overlay.background_red;
382 options->image_overlay.background_green = c_options->image_overlay.background_green;
383 options->image_overlay.background_blue = c_options->image_overlay.background_blue;
384 options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
385 options->update_on_time_change = c_options->update_on_time_change;
387 options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
388 options->rot_invariant_sim = c_options->rot_invariant_sim;
390 options->tree_descend_subdirs = c_options->tree_descend_subdirs;
392 options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
393 options->circular_selection_lists = c_options->circular_selection_lists;
395 options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
396 options->recent_folder_image_list_maxsize = c_options->recent_folder_image_list_maxsize;
397 options->dnd_icon_size = c_options->dnd_icon_size;
398 options->clipboard_selection = c_options->clipboard_selection;
399 options->dnd_default_action = c_options->dnd_default_action;
401 options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
402 options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
403 options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
404 options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
405 options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
406 options->metadata.confirm_write = c_options->metadata.confirm_write;
407 options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
408 options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
409 options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
410 options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
411 options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
412 options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
413 options->metadata.write_orientation = c_options->metadata.write_orientation;
414 options->metadata.check_spelling = c_options->metadata.check_spelling;
415 options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
416 (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
417 (c_options->stereo.tmp.flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
418 (c_options->stereo.tmp.mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
419 (c_options->stereo.tmp.flip_left ? PR_STEREO_FLIP_LEFT : 0) |
420 (c_options->stereo.tmp.swap ? PR_STEREO_SWAP : 0) |
421 (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
422 options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
423 (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
424 (c_options->stereo.tmp.fs_flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
425 (c_options->stereo.tmp.fs_mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
426 (c_options->stereo.tmp.fs_flip_left ? PR_STEREO_FLIP_LEFT : 0) |
427 (c_options->stereo.tmp.fs_swap ? PR_STEREO_SWAP : 0) |
428 (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
429 options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
430 options->stereo.fixed_w = c_options->stereo.fixed_w;
431 options->stereo.fixed_h = c_options->stereo.fixed_h;
432 options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
433 options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
434 options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
435 options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
437 options->info_keywords.height = c_options->info_keywords.height;
438 options->info_title.height = c_options->info_title.height;
439 options->info_comment.height = c_options->info_comment.height;
440 options->info_rating.height = c_options->info_rating.height;
442 options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
443 options->expand_menu_toolbar = c_options->expand_menu_toolbar;
445 options->marks_save = c_options->marks_save;
446 options->with_rename = c_options->with_rename;
447 options->collections_on_top = c_options->collections_on_top;
448 options->hide_window_in_fullscreen = c_options->hide_window_in_fullscreen;
449 config_entry_to_option(help_search_engine_entry, &options->help_search_engine, nullptr);
451 options->external_preview.enable = c_options->external_preview.enable;
452 config_entry_to_option(external_preview_select_entry, &options->external_preview.select, nullptr);
453 config_entry_to_option(external_preview_extract_entry, &options->external_preview.extract, nullptr);
455 options->read_metadata_in_idle = c_options->read_metadata_in_idle;
457 options->star_rating.star = c_options->star_rating.star;
458 options->star_rating.rejected = c_options->star_rating.rejected;
460 options->threads.duplicates = c_options->threads.duplicates > 0 ? c_options->threads.duplicates : -1;
463 set_debug_level(debug_c);
467 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
469 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], nullptr);
470 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], nullptr);
472 config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, nullptr);
473 options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
474 if (options->color_profile.render_intent != c_options->color_profile.render_intent)
476 options->color_profile.render_intent = c_options->color_profile.render_intent;
481 options->mouse_button_8 = c_options->mouse_button_8;
482 options->mouse_button_9 = c_options->mouse_button_9;
484 options->override_disable_gpu = c_options->override_disable_gpu;
486 config_tab_keywords_save();
488 image_options_sync();
493 layout_refresh(nullptr);
496 if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, nullptr);
498 toolbar_apply(TOOLBAR_MAIN);
499 toolbar_apply(TOOLBAR_STATUS);
503 *-----------------------------------------------------------------------------
504 * config window main button callbacks (private)
505 *-----------------------------------------------------------------------------
508 static void config_window_close_cb(GtkWidget *, gpointer)
510 gtk_widget_destroy(configwindow);
511 configwindow = nullptr;
512 filter_store = nullptr;
515 static void config_window_help_cb(GtkWidget *, gpointer data)
517 auto notebook = static_cast<GtkWidget *>(data);
520 static const gchar *html_section[] =
522 "GuideOptionsGeneral.html",
523 "GuideOptionsImage.html",
524 "GuideOptionsOSD.html",
525 "GuideOptionsWindow.html",
526 "GuideOptionsKeyboard.html",
527 "GuideOptionsFiltering.html",
528 "GuideOptionsMetadata.html",
529 "GuideOptionsKeywords.html",
530 "GuideOptionsColor.html",
531 "GuideOptionsStereo.html",
532 "GuideOptionsBehavior.html",
533 "GuideOptionsToolbar.html",
534 "GuideOptionsToolbar.html",
535 "GuideOptionsAdvanced.html"
538 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
539 help_window_show(html_section[i]);
542 static gboolean config_window_delete(GtkWidget *, GdkEventAny *, gpointer)
544 config_window_close_cb(nullptr, nullptr);
548 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
551 auto notebook = static_cast<GtkNotebook *>(data);
559 lw = static_cast<LayoutWindow *>(layout_window_list->data);
561 window = gtk_widget_get_window(widget);
562 gdk_window_get_root_origin(window, &x, &y);
563 w = gdk_window_get_width(window);
564 h = gdk_window_get_height(window);
565 page_number = gtk_notebook_get_current_page(notebook);
567 lw->options.preferences_window.x = x;
568 lw->options.preferences_window.y = y;
569 lw->options.preferences_window.w = w;
570 lw->options.preferences_window.h = h;
571 lw->options.preferences_window.page_number = page_number;
573 config_window_apply();
574 layout_util_sync(lw);
575 save_options(options);
576 config_window_close_cb(nullptr, nullptr);
580 *-----------------------------------------------------------------------------
581 * config window setup (private)
582 *-----------------------------------------------------------------------------
585 static void quality_menu_cb(GtkWidget *combo, gpointer data)
587 auto option = static_cast<gint *>(data);
589 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
593 *option = GDK_INTERP_NEAREST;
596 *option = GDK_INTERP_TILES;
599 *option = GDK_INTERP_BILINEAR;
604 static void dnd_default_action_selection_menu_cb(GtkWidget *combo, gpointer data)
606 auto option = static_cast<gint *>(data);
608 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
612 *option = DND_ACTION_ASK;
615 *option = DND_ACTION_COPY;
618 *option = DND_ACTION_MOVE;
622 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
624 auto option = static_cast<gint *>(data);
626 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
629 *option = CLIPBOARD_PRIMARY;
632 *option = CLIPBOARD_CLIPBOARD;
635 *option = CLIPBOARD_BOTH;
638 *option = CLIPBOARD_BOTH;
642 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
643 guint option, guint *option_c)
650 pref_table_label(table, column, row, text, GTK_ALIGN_START);
652 combo = gtk_combo_box_text_new();
654 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
655 if (option == GDK_INTERP_NEAREST) current = 0;
656 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
657 if (option == GDK_INTERP_TILES) current = 1;
658 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear (best, but slowest)"));
659 if (option == GDK_INTERP_BILINEAR) current = 2;
661 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
663 g_signal_connect(G_OBJECT(combo), "changed",
664 G_CALLBACK(quality_menu_cb), option_c);
666 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
667 gtk_widget_show(combo);
670 static void add_dnd_default_action_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, DnDAction option, DnDAction *option_c)
677 pref_table_label(table, column, row, text, GTK_ALIGN_START);
679 combo = gtk_combo_box_text_new();
681 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Ask"));
682 if (option == DND_ACTION_ASK) current = 0;
683 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Copy"));
684 if (option == DND_ACTION_COPY) current = 1;
685 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Move"));
686 if (option == DND_ACTION_MOVE) current = 2;
688 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
690 g_signal_connect(G_OBJECT(combo), "changed",
691 G_CALLBACK(dnd_default_action_selection_menu_cb), option_c);
693 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
694 gtk_widget_show(combo);
697 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
698 gint option, gint *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), _("Primary"));
710 if (option == CLIPBOARD_PRIMARY) current = 0;
711 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Clipboard"));
712 if (option == CLIPBOARD_CLIPBOARD) current = 1;
713 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Both"));
714 if (option == CLIPBOARD_BOTH) current = 2;
716 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
718 g_signal_connect(G_OBJECT(combo), "changed",
719 G_CALLBACK(clipboard_selection_menu_cb), option_c);
721 gtk_table_attach(GTK_TABLE(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 zoom_style_selection_menu_cb(GtkWidget *combo, gpointer data)
727 auto option = static_cast<gint *>(data);
729 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
732 *option = ZOOM_GEOMETRIC;
735 *option = ZOOM_ARITHMETIC;
738 *option = ZOOM_GEOMETRIC;
742 static void add_zoom_style_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, ZoomStyle option, ZoomStyle *option_c)
749 pref_table_label(table, column, row, text, GTK_ALIGN_START);
751 combo = gtk_combo_box_text_new();
753 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Geometric"));
754 if (option == ZOOM_GEOMETRIC) current = 0;
755 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Arithmetic"));
756 if (option == ZOOM_ARITHMETIC) current = 1;
758 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
760 g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(zoom_style_selection_menu_cb), option_c);
762 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
763 gtk_widget_show(combo);
766 struct UseableMouseItems
768 const gchar *name; /* GtkActionEntry terminology */
770 const gchar *icon_name;
773 static const UseableMouseItems useable_mouse_items[] = {
775 {"FirstImage", N_("First Image"), GQ_ICON_GO_TOP},
776 {"PrevImage", N_("Previous Image"), GQ_ICON_GO_UP},
777 {"NextImage", N_("Next Image"), GQ_ICON_GO_DOWN},
778 {"LastImage", N_("Last Image"), GQ_ICON_GO_BOTTOM},
779 {"Back", N_("Back"), GQ_ICON_GO_PREV},
780 {"Forward", N_("Forward"), GQ_ICON_GO_NEXT},
781 {"Home", N_("Home"), GQ_ICON_HOME},
782 {"Up", N_("Up"), GQ_ICON_GO_UP},
783 {"FirstPage", N_("First page"), GQ_ICON_PREV_PAGE},
784 {"LastPage", N_("Last Page"), GQ_ICON_NEXT_PAGE},
785 {"NextPage", N_("Next page"), GQ_ICON_FORWARD_PAGE},
786 {"PrevPage", N_("Previous Page"), GQ_ICON_BACK_PAGE},
787 {"NewWindow", N_("New _window"), GQ_ICON_NEW},
788 {"NewCollection", N_("New collection"), GQ_ICON_COLLECTION},
789 {"OpenCollection", N_("Open collection"), GQ_ICON_OPEN},
790 {"Search", N_("Search"), GQ_ICON_FIND},
791 {"FindDupes", N_("Find duplicates"), GQ_ICON_FIND},
792 {"NewFolder", N_("New folder"),GQ_ICON_DIRECTORY},
793 {"Copy", N_("Copy"), GQ_ICON_COPY},
794 {"Move", N_("Move"), PIXBUF_INLINE_ICON_MOVE},
795 {"Rename", N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
796 {"Delete", N_("Delete"), GQ_ICON_DELETE},
797 {"CloseWindow", N_("Close Window"), GQ_ICON_CLOSE},
798 {"PanView", N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
799 {"SelectAll", N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
800 {"SelectNone", N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
801 {"SelectInvert", N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
802 {"ShowFileFilter", N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
803 {"RectangularSelection", N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
804 {"Print", N_("Print"), GQ_ICON_PRINT},
805 {"Preferences", N_("Preferences"), GQ_ICON_PREFERENCES},
806 {"LayoutConfig", N_("Configure this window"), GQ_ICON_PREFERENCES},
807 {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
808 {"RotateCW", N_("Rotate clockwise 90°"), PIXBUF_INLINE_ICON_CW},
809 {"RotateCCW", N_("Rotate counterclockwise 90°"), PIXBUF_INLINE_ICON_CCW},
810 {"Rotate180", N_("Rotate 180°"), PIXBUF_INLINE_ICON_180},
811 {"Mirror", N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
812 {"Flip", N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
813 {"AlterNone", N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
814 {"ZoomIn", N_("Zoom in"), GQ_ICON_ZOOM_IN},
815 {"ZoomOut", N_("Zoom out"), GQ_ICON_ZOOM_OUT},
816 {"Zoom100", N_("Zoom 1:1"), GQ_ICON_ZOOM_100},
817 {"ZoomFit", N_("Zoom to fit"), GQ_ICON_ZOOM_FIT},
818 {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
819 {"ZoomFillVert", N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
820 {"Zoom200", N_("Zoom 2:1"), GQ_ICON_GENERIC},
821 {"Zoom300", N_("Zoom 3:1"), GQ_ICON_GENERIC},
822 {"Zoom400", N_("Zoom 4:1"), GQ_ICON_GENERIC},
823 {"Zoom50", N_("Zoom 1:2"), GQ_ICON_GENERIC},
824 {"Zoom33", N_("Zoom 1:3"), GQ_ICON_GENERIC},
825 {"Zoom25", N_("Zoom 1:4"), GQ_ICON_GENERIC},
826 {"ConnectZoomIn", N_("Connected Zoom in"), GQ_ICON_ZOOM_IN},
827 {"SplitPaneSync", N_("Split Pane Sync"), PIXBUF_INLINE_SPLIT_PANE_SYNC},
828 {"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
829 {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
830 {"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
831 {"SlideShowPause", N_("Pause slideshow"), GQ_ICON_PAUSE},
832 {"SlideShowFaster", N_("Slideshow Faster"), GQ_ICON_GENERIC},
833 {"SlideShowSlower", N_("Slideshow Slower"), GQ_ICON_GENERIC},
834 {"Refresh", N_("Refresh"), GQ_ICON_REFRESH},
835 {"HelpContents", N_("Help"), GQ_ICON_HELP},
836 {"ExifWin", N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
837 {"Thumbnails", N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
838 {"ShowMarks", N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
839 {"DrawRectangle", N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
840 {"FloatTools", N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
841 {"SBar", N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
842 {"SBarSort", N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
843 {"Quit", N_("Quit"), GQ_ICON_QUIT},
844 {nullptr, nullptr, nullptr}
847 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
849 auto option = static_cast<gchar **>(data);
852 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
854 const UseableMouseItems *list = useable_mouse_items;
858 if (g_strcmp0(list->label, label) == 0)
866 *option = g_strdup(list->name);
870 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
871 gchar *option, gchar **option_c)
879 pref_table_label(table, column, row, text, GTK_ALIGN_START);
881 combo = gtk_combo_box_text_new();
883 const UseableMouseItems *list = useable_mouse_items;
887 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
888 if (g_strcmp0(list->name, option) == 0)
896 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
898 g_signal_connect(G_OBJECT(combo), "changed",
899 G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
901 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
902 gtk_widget_show(combo);
905 static void thumb_size_menu_cb(GtkWidget *combo, gpointer)
909 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
912 if (static_cast<guint>(n) < sizeof(thumb_size_list) / sizeof(ThumbSize))
914 c_options->thumbnails.max_width = thumb_size_list[n].w;
915 c_options->thumbnails.max_height = thumb_size_list[n].h;
919 c_options->thumbnails.max_width = options->thumbnails.max_width;
920 c_options->thumbnails.max_height = options->thumbnails.max_height;
924 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
930 c_options->thumbnails.max_width = options->thumbnails.max_width;
931 c_options->thumbnails.max_height = options->thumbnails.max_height;
933 pref_table_label(table, column, row, text, GTK_ALIGN_START);
935 combo = gtk_combo_box_text_new();
938 for (i = 0; static_cast<guint>(i) < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
943 w = thumb_size_list[i].w;
944 h = thumb_size_list[i].h;
946 buf = g_strdup_printf("%d x %d", w, h);
947 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
950 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
957 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
958 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
964 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
965 g_signal_connect(G_OBJECT(combo), "changed",
966 G_CALLBACK(thumb_size_menu_cb), NULL);
968 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
969 gtk_widget_show(combo);
972 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
974 auto option = static_cast<gint *>(data);
976 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
980 *option = PR_STEREO_NONE;
983 *option = PR_STEREO_ANAGLYPH_RC;
986 *option = PR_STEREO_ANAGLYPH_GM;
989 *option = PR_STEREO_ANAGLYPH_YB;
992 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
995 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
998 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
1001 *option = PR_STEREO_ANAGLYPH_DB_RC;
1004 *option = PR_STEREO_ANAGLYPH_DB_GM;
1007 *option = PR_STEREO_ANAGLYPH_DB_YB;
1010 *option = PR_STEREO_HORIZ;
1013 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
1016 *option = PR_STEREO_VERT;
1019 *option = PR_STEREO_VERT | PR_STEREO_HALF;
1022 *option = PR_STEREO_FIXED;
1027 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1028 gint option, gint *option_c, gboolean add_fixed)
1035 pref_table_label(table, column, row, text, GTK_ALIGN_START);
1037 combo = gtk_combo_box_text_new();
1039 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
1041 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
1042 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
1043 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
1044 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
1045 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
1046 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
1047 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
1048 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
1049 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
1050 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
1051 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
1052 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
1053 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
1054 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
1055 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
1056 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
1057 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
1058 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
1060 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
1061 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
1062 if (option & PR_STEREO_HORIZ)
1065 if (option & PR_STEREO_HALF) current = 11;
1068 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
1069 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
1070 if (option & PR_STEREO_VERT)
1073 if (option & PR_STEREO_HALF) current = 13;
1078 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
1079 if (option & PR_STEREO_FIXED) current = 14;
1082 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1084 g_signal_connect(G_OBJECT(combo), "changed",
1085 G_CALLBACK(stereo_mode_menu_cb), option_c);
1087 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
1088 gtk_widget_show(combo);
1091 static void video_menu_cb(GtkWidget *combo, gpointer data)
1093 auto option = static_cast<gchar **>(data);
1095 auto ed = static_cast<EditorDescription *>(g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo))));
1099 static void video_menu_populate(gpointer data, gpointer user_data)
1101 auto combo = static_cast<GtkWidget *>(user_data);
1102 auto ed = static_cast<EditorDescription *>(data);
1104 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1107 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1108 gchar *option, gchar **option_c)
1112 /* use lists since they are sorted */
1113 GList *eds = editor_list_get();
1117 pref_table_label(table, column, row, text, GTK_ALIGN_START);
1119 combo = gtk_combo_box_text_new();
1120 g_list_foreach(eds,video_menu_populate,combo);
1121 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1123 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1125 g_signal_connect(G_OBJECT(combo), "changed",
1126 G_CALLBACK(video_menu_cb), option_c);
1128 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
1129 gtk_widget_show(combo);
1132 static void filter_store_populate()
1136 if (!filter_store) return;
1138 gtk_list_store_clear(filter_store);
1140 work = filter_get_list();
1146 fe = static_cast<FilterEntry *>(work->data);
1149 gtk_list_store_append(filter_store, &iter);
1150 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1154 static void filter_store_ext_edit_cb(GtkCellRendererText *, gchar *path_str, gchar *new_text, gpointer data)
1156 auto model = static_cast<GtkWidget *>(data);
1157 auto fe = static_cast<FilterEntry *>(data);
1161 if (!new_text || strlen(new_text) < 1) return;
1163 tpath = gtk_tree_path_new_from_string(path_str);
1164 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1165 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1167 g_free(fe->extensions);
1168 fe->extensions = g_strdup(new_text);
1170 gtk_tree_path_free(tpath);
1174 static void filter_store_class_edit_cb(GtkCellRendererText *, gchar *path_str, gchar *new_text, gpointer data)
1176 auto model = static_cast<GtkWidget *>(data);
1177 auto fe = static_cast<FilterEntry *>(data);
1182 if (!new_text || !new_text[0]) return;
1184 tpath = gtk_tree_path_new_from_string(path_str);
1185 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1186 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1188 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1190 if (strcmp(new_text, _(format_class_list[i])) == 0)
1192 fe->file_class = static_cast<FileFormatClass>(i);
1197 gtk_tree_path_free(tpath);
1201 static void filter_store_desc_edit_cb(GtkCellRendererText *, gchar *path_str, gchar *new_text, gpointer data)
1203 auto model = static_cast<GtkWidget *>(data);
1208 if (!new_text || !new_text[0]) return;
1210 tpath = gtk_tree_path_new_from_string(path_str);
1211 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1212 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1214 g_free(fe->description);
1215 fe->description = g_strdup(new_text);
1217 gtk_tree_path_free(tpath);
1220 static void filter_store_enable_cb(GtkCellRendererToggle *, gchar *path_str, gpointer data)
1222 auto model = static_cast<GtkWidget *>(data);
1227 tpath = gtk_tree_path_new_from_string(path_str);
1228 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1229 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1231 fe->enabled = !fe->enabled;
1233 gtk_tree_path_free(tpath);
1237 static void filter_store_writable_cb(GtkCellRendererToggle *, gchar *path_str, gpointer data)
1239 auto model = static_cast<GtkWidget *>(data);
1244 tpath = gtk_tree_path_new_from_string(path_str);
1245 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1246 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1248 fe->writable = !fe->writable;
1249 if (fe->writable) fe->allow_sidecar = FALSE;
1251 gtk_tree_path_free(tpath);
1255 static void filter_store_sidecar_cb(GtkCellRendererToggle *, gchar *path_str, gpointer data)
1257 auto model = static_cast<GtkWidget *>(data);
1262 tpath = gtk_tree_path_new_from_string(path_str);
1263 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1264 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1266 fe->allow_sidecar = !fe->allow_sidecar;
1267 if (fe->allow_sidecar) fe->writable = FALSE;
1269 gtk_tree_path_free(tpath);
1273 static void filter_set_func(GtkTreeViewColumn *, GtkCellRenderer *cell,
1274 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1278 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1280 switch (GPOINTER_TO_INT(data))
1283 g_object_set(GTK_CELL_RENDERER(cell),
1284 "active", fe->enabled, NULL);
1287 g_object_set(GTK_CELL_RENDERER(cell),
1288 "text", fe->extensions, NULL);
1290 case FE_DESCRIPTION:
1291 g_object_set(GTK_CELL_RENDERER(cell),
1292 "text", fe->description, NULL);
1295 g_object_set(GTK_CELL_RENDERER(cell),
1296 "text", _(format_class_list[fe->file_class]), NULL);
1299 g_object_set(GTK_CELL_RENDERER(cell),
1300 "active", fe->writable, NULL);
1302 case FE_ALLOW_SIDECAR:
1303 g_object_set(GTK_CELL_RENDERER(cell),
1304 "active", fe->allow_sidecar, NULL);
1309 static gboolean filter_add_scroll(gpointer data)
1313 GtkCellRenderer *cell;
1314 GtkTreeViewColumn *column;
1317 GtkTreeModel *store;
1319 FilterEntry *filter;
1321 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), nullptr);
1322 path = gtk_tree_path_new_from_indices(rows-1, -1);
1324 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1326 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1327 cell = static_cast<GtkCellRenderer *>(g_list_last(list_cells)->data);
1329 store = gtk_tree_view_get_model(GTK_TREE_VIEW(data));
1330 valid = gtk_tree_model_get_iter_first(store, &iter);
1334 gtk_tree_model_get(store, &iter, 0, &filter, -1);
1336 if (g_strcmp0(filter->extensions, ".new") == 0)
1338 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
1342 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1345 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1346 path, column, FALSE, 0.0, 0.0 );
1347 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1348 path, column, cell, TRUE);
1350 gtk_tree_path_free(path);
1351 g_list_free(list_cells);
1353 return(G_SOURCE_REMOVE);
1356 static void filter_add_cb(GtkWidget *, gpointer data)
1358 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1359 filter_store_populate();
1361 g_idle_add(static_cast<GSourceFunc>(filter_add_scroll), data);
1364 static void filter_remove_cb(GtkWidget *, gpointer data)
1366 auto filter_view = static_cast<GtkWidget *>(data);
1367 GtkTreeSelection *selection;
1371 if (!filter_store) return;
1372 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1373 if (!gtk_tree_selection_get_selected(selection, nullptr, &iter)) return;
1374 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1377 filter_remove_entry(fe);
1379 filter_store_populate();
1382 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1386 GtkTreeViewColumn *column;
1388 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1389 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1390 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1392 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1396 gtk_tree_path_free(path);
1398 return(G_SOURCE_REMOVE);
1401 static void filter_default_ok_cb(GenericDialog *gd, gpointer)
1404 filter_add_defaults();
1406 filter_store_populate();
1408 g_idle_add(reinterpret_cast<GSourceFunc>(filter_default_ok_scroll), gd->data);
1411 static void dummy_cancel_cb(GenericDialog *, gpointer)
1413 /* no op, only so cancel button appears */
1416 static void filter_default_cb(GtkWidget *widget, gpointer data)
1420 gd = generic_dialog_new(_("Reset filters"),
1421 "reset_filter", widget, TRUE,
1422 dummy_cancel_cb, data);
1423 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Reset filters"),
1424 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1425 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", filter_default_ok_cb, TRUE);
1426 gtk_widget_show(gd->dialog);
1429 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1431 auto frame = static_cast<GtkWidget *>(data);
1433 gtk_widget_set_sensitive(frame,
1434 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1437 static void safe_delete_view_cb(GtkWidget *, gpointer)
1439 layout_set_path(nullptr, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1442 static void safe_delete_clear_ok_cb(GenericDialog *, gpointer)
1444 file_util_trash_clear();
1447 static void safe_delete_clear_cb(GtkWidget *widget, gpointer)
1451 gd = generic_dialog_new(_("Clear trash"),
1452 "clear_trash", widget, TRUE,
1453 dummy_cancel_cb, nullptr);
1454 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Clear trash"),
1455 _("This will remove the trash contents."), FALSE);
1456 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", safe_delete_clear_ok_cb, TRUE);
1457 entry = gtk_entry_new();
1458 gtk_widget_set_can_focus(entry, FALSE);
1459 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1460 if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1461 gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1462 gtk_widget_show(entry);
1463 gtk_widget_show(gd->dialog);
1466 static void image_overlay_template_view_changed_cb(GtkWidget *, gpointer data)
1468 GtkWidget *pTextView;
1469 GtkTextBuffer *pTextBuffer;
1473 pTextView = GTK_WIDGET(data);
1475 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1476 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1477 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1479 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1480 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1483 static void image_overlay_default_template_ok_cb(GenericDialog *, gpointer data)
1485 auto text_view = static_cast<GtkTextView *>(data);
1486 GtkTextBuffer *buffer;
1488 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1489 if (!configwindow) return;
1491 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1492 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1495 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1499 gd = generic_dialog_new(_("Reset image overlay template string"),
1500 "reset_image_overlay_template_string", widget, TRUE,
1501 dummy_cancel_cb, data);
1502 generic_dialog_add_message(gd, GQ_ICON_DIALOG_QUESTION, _("Reset image overlay template string"),
1503 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1504 generic_dialog_add_button(gd, GQ_ICON_OK, "OK", image_overlay_default_template_ok_cb, TRUE);
1505 gtk_widget_show(gd->dialog);
1508 static void image_overlay_help_cb(GtkWidget *, gpointer)
1510 help_window_show("GuideOptionsOSD.html");
1513 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer)
1517 PangoFontDescription *font_desc;
1519 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1520 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1522 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1524 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1525 font = pango_font_description_to_string(font_desc);
1526 g_free(c_options->image_overlay.font);
1527 c_options->image_overlay.font = g_strdup(font);
1531 gtk_widget_destroy(dialog);
1534 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer)
1539 dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1540 colour.red = options->image_overlay.text_red;
1541 colour.green = options->image_overlay.text_green;
1542 colour.blue = options->image_overlay.text_blue;
1543 colour.alpha = options->image_overlay.text_alpha;
1544 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1545 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1547 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1549 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1550 c_options->image_overlay.text_red = colour.red*255;
1551 c_options->image_overlay.text_green = colour.green*255;
1552 c_options->image_overlay.text_blue = colour.blue*255;
1553 c_options->image_overlay.text_alpha = colour.alpha*255;
1555 gtk_widget_destroy(dialog);
1559 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer)
1564 dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1565 colour.red = options->image_overlay.background_red;
1566 colour.green = options->image_overlay.background_green;
1567 colour.blue = options->image_overlay.background_blue;
1568 colour.alpha = options->image_overlay.background_alpha;
1569 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1570 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1572 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1574 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1575 c_options->image_overlay.background_red = colour.red*255;
1576 c_options->image_overlay.background_green = colour.green*255;
1577 c_options->image_overlay.background_blue = colour.blue*255;
1578 c_options->image_overlay.background_alpha = colour.alpha*255;
1580 gtk_widget_destroy(dialog);
1583 static void accel_store_populate()
1586 GList *groups, *actions;
1588 const gchar *accel_path;
1592 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1594 gtk_tree_store_clear(accel_store);
1595 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 */
1597 g_assert(lw && lw->ui_manager);
1598 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1601 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1604 action = GTK_ACTION(actions->data);
1605 accel_path = gtk_action_get_accel_path(action);
1606 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1608 gchar *label, *label2, *tooltip, *accel;
1609 g_object_get(action,
1610 "tooltip", &tooltip,
1614 if (pango_parse_markup(label, -1, '_', nullptr, &label2, nullptr, nullptr) && label2)
1620 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1624 gtk_tree_store_append(accel_store, &iter, nullptr);
1625 gtk_tree_store_set(accel_store, &iter,
1628 AE_TOOLTIP, tooltip ? tooltip : "",
1629 AE_ACCEL, accel_path,
1637 actions = actions->next;
1640 groups = groups->next;
1644 static void accel_store_cleared_cb(GtkCellRendererAccel *, gchar *, gpointer)
1649 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *, GtkTreeIter *iter, gpointer data)
1651 auto accel1 = static_cast<gchar *>(data);
1656 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1658 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1659 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1661 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1663 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1664 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1673 static void accel_store_edited_cb(GtkCellRendererAccel *, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint, gpointer)
1675 auto model = reinterpret_cast<GtkTreeModel *>(accel_store);
1679 GtkAccelKey old_key, key;
1680 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1682 gtk_tree_model_get_iter(model, &iter, path);
1683 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1685 /* test if the accelerator can be stored without conflicts*/
1686 gtk_accel_map_lookup_entry(accel_path, &old_key);
1688 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1689 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1690 gtk_accel_map_lookup_entry(accel_path, &key);
1692 /* restore the original for now, the key will be really changed when the changes are confirmed */
1693 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1695 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1696 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1698 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1699 gtk_tree_path_free(path);
1703 static gboolean accel_default_scroll(GtkTreeView *data)
1707 GtkTreeViewColumn *column;
1709 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1710 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1711 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1713 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1717 gtk_tree_path_free(path);
1719 return(G_SOURCE_REMOVE);
1722 static void accel_default_cb(GtkWidget *, gpointer data)
1724 accel_store_populate();
1726 g_idle_add(reinterpret_cast<GSourceFunc>(accel_default_scroll), data);
1729 void accel_clear_selection(GtkTreeModel *, GtkTreePath *, GtkTreeIter *iter, gpointer)
1731 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1734 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *, GtkTreeIter *iter, gpointer)
1737 gchar *accel_path, *accel;
1739 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1740 gtk_accel_map_lookup_entry(accel_path, &key);
1741 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1743 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1745 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1750 static void accel_clear_cb(GtkWidget *, gpointer data)
1752 GtkTreeSelection *selection;
1754 if (!accel_store) return;
1755 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1756 gtk_tree_selection_selected_foreach(selection, &accel_clear_selection, nullptr);
1759 static void accel_reset_cb(GtkWidget *, gpointer data)
1761 GtkTreeSelection *selection;
1763 if (!accel_store) return;
1764 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1765 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, nullptr);
1770 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1774 GtkWidget *scrolled;
1775 GtkWidget *viewport;
1777 scrolled = gtk_scrolled_window_new(nullptr, nullptr);
1778 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1779 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1780 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1781 label = gtk_label_new(title);
1782 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1783 gtk_widget_show(scrolled);
1785 viewport = gtk_viewport_new(nullptr, nullptr);
1786 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1787 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1788 gtk_widget_show(viewport);
1790 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
1791 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1792 gtk_widget_show(vbox);
1797 static void cache_standard_cb(GtkWidget *widget, gpointer)
1799 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1801 c_options->thumbnails.spec_standard =TRUE;
1802 c_options->thumbnails.cache_into_dirs = FALSE;
1806 static void cache_geeqie_cb(GtkWidget *widget, gpointer)
1808 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1810 c_options->thumbnails.spec_standard =FALSE;
1811 c_options->thumbnails.cache_into_dirs = FALSE;
1815 static void cache_local_cb(GtkWidget *widget, gpointer)
1817 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1819 c_options->thumbnails.cache_into_dirs = TRUE;
1820 c_options->thumbnails.spec_standard =FALSE;
1824 static void help_search_engine_entry_icon_cb(GtkEntry *, GtkEntryIconPosition pos, GdkEvent *, gpointer userdata)
1826 if (pos == GTK_ENTRY_ICON_PRIMARY)
1828 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1832 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1836 static void star_rating_star_icon_cb(GtkEntry *, GtkEntryIconPosition pos, GdkEvent *, gpointer userdata)
1838 gchar *rating_symbol;
1840 if (pos == GTK_ENTRY_ICON_PRIMARY)
1842 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1843 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1844 g_free(rating_symbol);
1848 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1849 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1850 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1854 static void star_rating_rejected_icon_cb(GtkEntry *, GtkEntryIconPosition pos, GdkEvent *, gpointer userdata)
1856 gchar *rating_symbol;
1858 if (pos == GTK_ENTRY_ICON_PRIMARY)
1860 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1861 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1862 g_free(rating_symbol);
1866 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1867 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1868 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1872 static guint star_rating_symbol_test(GtkWidget *, gpointer data)
1874 auto hbox = static_cast<GtkContainer *>(data);
1875 GString *str = g_string_new(nullptr);
1876 GtkEntry *hex_code_entry;
1877 gchar *hex_code_full;
1880 guint64 hex_value = 0;
1882 list = gtk_container_get_children(hbox);
1884 hex_code_entry = static_cast<GtkEntry *>(g_list_nth_data(list, 2));
1885 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1887 hex_code = g_strsplit(hex_code_full, "+", 2);
1888 if (hex_code[0] && hex_code[1])
1890 hex_value = strtoull(hex_code[1], nullptr, 16);
1892 if (!hex_value || hex_value > 0x10FFFF)
1894 hex_value = 0x003F; // Unicode 'Question Mark'
1896 str = g_string_append_unichar(str, static_cast<gunichar>(hex_value));
1897 gtk_label_set_text(static_cast<GtkLabel *>(g_list_nth_data(list, 1)), str->str);
1899 g_strfreev(hex_code);
1900 g_string_free(str, TRUE);
1901 g_free(hex_code_full);
1906 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1908 guint64 star_symbol;
1910 star_symbol = star_rating_symbol_test(widget, data);
1911 c_options->star_rating.star = star_symbol;
1914 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1916 guint64 rejected_symbol;
1918 rejected_symbol = star_rating_symbol_test(widget, data);
1919 c_options->star_rating.rejected = rejected_symbol;
1922 /* general options tab */
1923 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1927 GCancellable *cancellable;
1929 GtkWidget *progress;
1931 GFile *timezone_database_gq;
1932 gchar *timezone_database_user;
1935 static void config_tab_general(GtkWidget *notebook)
1940 GtkWidget *group_frame;
1941 GtkWidget *subgroup;
1943 GtkWidget *ct_button;
1946 gint hours, minutes, remainder;
1948 GtkWidget *star_rating_entry;
1950 gchar *rating_symbol;
1953 gchar *download_locn;
1954 GNetworkMonitor *net_mon;
1955 GSocketConnectable *tz_org;
1956 gboolean internet_available = FALSE;
1959 vbox = scrolled_notebook_page(notebook, _("General"));
1961 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1963 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1964 add_thumb_size_menu(table, 0, 0, _("Size:"));
1965 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1967 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1968 pref_label_new(hbox, _("Custom size: "));
1969 pref_spin_new_int(hbox, _("Width:"), nullptr, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
1970 pref_spin_new_int(hbox, _("Height:"), nullptr, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
1972 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
1973 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1975 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1976 pref_checkbox_link_sensitivity(ct_button, subgroup);
1978 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
1979 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
1980 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
1981 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1982 button = pref_radiobutton_new(group_frame, nullptr, get_thumbnails_cache_dir(),
1983 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1984 G_CALLBACK(cache_geeqie_cb), nullptr);
1986 group_frame = pref_frame_new(subgroup, TRUE,
1987 _("Store thumbnails local to image folder (non-standard)"),
1988 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1989 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
1990 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
1991 G_CALLBACK(cache_local_cb), nullptr);
1993 group_frame = pref_frame_new(subgroup, TRUE,
1994 _("Use standard thumbnail style and cache, shared with other applications"),
1995 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1996 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
1997 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1998 G_CALLBACK(cache_standard_cb), nullptr);
2000 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
2001 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
2003 pref_checkbox_new_int(group, _("Thumbnail color management"),
2004 options->thumbnails.use_color_management, &c_options->thumbnails.use_color_management);
2006 spin = pref_spin_new_int(group, _("Collection preview:"), nullptr,
2008 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
2009 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
2011 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
2012 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
2013 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
2016 pref_spacer(group, PREF_PAD_GROUP);
2018 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
2020 c_options->star_rating.star = options->star_rating.star;
2021 c_options->star_rating.rejected = options->star_rating.rejected;
2023 str = g_string_new(nullptr);
2024 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2025 pref_label_new(hbox, _("Star character: "));
2026 str = g_string_append_unichar(str, options->star_rating.star);
2027 pref_label_new(hbox, g_strdup(str->str));
2028 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
2029 star_rating_entry = gtk_entry_new();
2030 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2031 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2032 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2033 gtk_widget_show(star_rating_entry);
2034 button = pref_button_new(nullptr, nullptr, _("Set"),
2035 G_CALLBACK(star_rating_star_test_cb), hbox);
2036 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2037 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2038 gtk_widget_show(button);
2039 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."));
2040 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2041 GTK_ENTRY_ICON_SECONDARY, GQ_ICON_CLEAR);
2042 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2043 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2044 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2045 GTK_ENTRY_ICON_PRIMARY, GQ_ICON_REVERT);
2046 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2047 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2048 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2049 G_CALLBACK(star_rating_star_icon_cb),
2052 g_string_free(str, TRUE);
2053 g_free(rating_symbol);
2055 str = g_string_new(nullptr);
2056 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2057 pref_label_new(hbox, _("Rejected character: "));
2058 str = g_string_append_unichar(str, options->star_rating.rejected);
2059 pref_label_new(hbox, g_strdup(str->str));
2060 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2061 star_rating_entry = gtk_entry_new();
2062 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2063 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2064 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2065 gtk_widget_show(star_rating_entry);
2066 button = pref_button_new(nullptr, nullptr, _("Set"),
2067 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2068 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2069 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2070 gtk_widget_show(button);
2071 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."));
2072 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2073 GTK_ENTRY_ICON_SECONDARY, GQ_ICON_CLEAR);
2074 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2075 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2076 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(star_rating_entry),
2077 GTK_ENTRY_ICON_PRIMARY, GQ_ICON_REVERT);
2078 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2079 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2080 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2081 G_CALLBACK(star_rating_rejected_icon_cb),
2084 g_string_free(str, TRUE);
2085 g_free(rating_symbol);
2087 pref_spacer(group, PREF_PAD_GROUP);
2089 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2091 c_options->slideshow.delay = options->slideshow.delay;
2092 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2093 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2094 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2095 seconds = static_cast<gdouble>(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2096 SLIDESHOW_SUBSECOND_PRECISION;
2098 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2100 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), nullptr,
2102 options->slideshow.delay ? hours : 0.0,
2103 G_CALLBACK(slideshow_delay_hours_cb), nullptr);
2104 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2105 spin = pref_spin_new(hbox, ":" , nullptr,
2107 options->slideshow.delay ? minutes: 0.0,
2108 G_CALLBACK(slideshow_delay_minutes_cb), nullptr);
2109 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2110 spin = pref_spin_new(hbox, ":", nullptr,
2111 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2112 options->slideshow.delay ? seconds : 10.0,
2113 G_CALLBACK(slideshow_delay_seconds_cb), nullptr);
2114 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2116 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2117 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2119 pref_spacer(group, PREF_PAD_GROUP);
2121 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2123 pref_spin_new_int(group, _("Decoded image cache size (MiB):"), nullptr,
2124 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2125 pref_checkbox_new_int(group, _("Preload next image"),
2126 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2128 pref_checkbox_new_int(group, _("Refresh on file change"),
2129 options->update_on_time_change, &c_options->update_on_time_change);
2132 pref_spacer(group, PREF_PAD_GROUP);
2134 group = pref_group_new(vbox, FALSE, _("Expand menu and toolbar"), GTK_ORIENTATION_VERTICAL);
2136 pref_checkbox_new_int(group, _("Expand menu and toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2137 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2138 gtk_widget_set_tooltip_text(group, _("Expand the menu and toolbar to the full width of the window"));
2140 pref_spacer(group, PREF_PAD_GROUP);
2142 if (g_getenv("APPDIR") && strstr(g_getenv("APPDIR"), "/tmp/.mount_Geeqie"))
2144 group = pref_group_new(vbox, FALSE, _("AppImage updates notifications"), GTK_ORIENTATION_VERTICAL);
2145 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2146 pref_checkbox_new_int(group, _("Enable"), options->appimage_notifications, &c_options->appimage_notifications);
2147 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"));
2149 pref_spacer(group, PREF_PAD_GROUP);
2153 net_mon = g_network_monitor_get_default();
2154 tz_org = g_network_address_parse_uri(TIMEZONE_DATABASE_WEB, 80, nullptr);
2157 internet_available = g_network_monitor_can_reach(net_mon, tz_org, nullptr, nullptr);
2158 g_object_unref(tz_org);
2161 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2162 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2164 if (!internet_available)
2166 gtk_widget_set_sensitive(group, FALSE);
2169 tz = g_new0(TZData, 1);
2171 path = path_from_utf8(TIMEZONE_DATABASE_WEB);
2172 basename = g_path_get_basename(path);
2173 tz->timezone_database_user = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
2177 if (isfile(tz->timezone_database_user))
2179 button = pref_button_new(GTK_WIDGET(hbox), nullptr, _("Update"), G_CALLBACK(timezone_database_install_cb), tz);
2183 button = pref_button_new(GTK_WIDGET(hbox), nullptr, _("Install"), G_CALLBACK(timezone_database_install_cb), tz);
2186 download_locn = g_strconcat(_("Download database from: "), TIMEZONE_DATABASE_WEB, NULL);
2187 pref_label_new(GTK_WIDGET(hbox), download_locn);
2188 g_free(download_locn);
2190 if (!internet_available)
2192 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"));
2196 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"));
2198 gtk_widget_show(button);
2200 pref_spacer(group, PREF_PAD_GROUP);
2202 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2204 help_search_engine_entry = gtk_entry_new();
2205 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2206 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2207 gtk_widget_show(help_search_engine_entry);
2209 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"));
2211 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(help_search_engine_entry),
2212 GTK_ENTRY_ICON_SECONDARY, GQ_ICON_CLEAR);
2213 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2214 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2215 gtk_entry_set_icon_from_icon_name(GTK_ENTRY(help_search_engine_entry),
2216 GTK_ENTRY_ICON_PRIMARY, GQ_ICON_REVERT);
2217 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2218 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2219 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2220 G_CALLBACK(help_search_engine_entry_icon_cb),
2221 help_search_engine_entry);
2225 static void config_tab_image(GtkWidget *notebook)
2230 GtkWidget *ct_button;
2231 GtkWidget *enlargement_button;
2235 vbox = scrolled_notebook_page(notebook, _("Image"));
2237 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2239 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2240 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2242 pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2243 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2245 c_options->image.zoom_increment = options->image.zoom_increment;
2246 spin = pref_spin_new(group, _("Zoom increment:"), nullptr,
2247 0.01, 4.0, 0.01, 2, static_cast<gdouble>(options->image.zoom_increment) / 100.0,
2248 G_CALLBACK(zoom_increment_cb), nullptr);
2249 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2251 c_options->image.zoom_style = options->image.zoom_style;
2252 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2253 add_zoom_style_selection_menu(table, 0, 0, _("Zoom style:"), options->image.zoom_style, &c_options->image.zoom_style);
2255 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2257 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2258 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2259 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2260 spin = pref_spin_new_int(hbox, nullptr, nullptr,
2262 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2263 pref_checkbox_link_sensitivity(enlargement_button, spin);
2264 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."));
2266 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2267 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2268 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2269 spin = pref_spin_new_int(hbox, nullptr, nullptr,
2271 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2272 pref_checkbox_link_sensitivity(ct_button, spin);
2273 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."));
2275 group = pref_group_new(vbox, FALSE, _("Tile size"), GTK_ORIENTATION_VERTICAL);
2277 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2278 spin = pref_spin_new_int(hbox, _("Pixels"), _("(Requires restart)"),
2280 options->image.tile_size, &c_options->image.tile_size);
2281 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."));
2283 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2285 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2286 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2288 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2289 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2291 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2292 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2294 c_options->image.border_color = options->image.border_color;
2296 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2297 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2299 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2300 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2302 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2303 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2308 static void save_default_window_layout_cb(GtkWidget *, gpointer)
2310 LayoutWindow *lw = nullptr;
2311 gchar *default_path;
2314 /* Get current lw */
2317 tmp_id = lw->options.id;
2318 lw->options.id = g_strdup("lw_default");
2320 default_path = g_build_filename(get_rc_dir(), DEFAULT_WINDOW_LAYOUT, NULL);
2321 save_default_layout_options_to_file(default_path, options, lw);
2322 g_free(lw->options.id);
2323 lw->options.id = tmp_id;
2324 g_free(default_path);
2327 static gboolean popover_cb(gpointer data)
2329 auto popover = static_cast<GtkPopover *>(data);
2331 gtk_popover_popdown(popover);
2336 static void default_layout_changed_cb(GtkWidget *, GtkPopover *popover)
2338 gtk_popover_popup(popover);
2340 g_timeout_add(2000, popover_cb, popover);
2343 static GtkWidget *create_popover(GtkWidget *parent, GtkWidget *child, GtkPositionType pos)
2347 popover = gtk_popover_new(parent);
2348 gtk_popover_set_position(GTK_POPOVER (popover), pos);
2349 gtk_container_add (GTK_CONTAINER(popover), child);
2350 gtk_container_set_border_width(GTK_CONTAINER (popover), 6);
2351 gtk_widget_show (child);
2356 static void config_tab_windows(GtkWidget *notebook)
2361 GtkWidget *subgroup;
2363 GtkWidget *ct_button;
2366 vbox = scrolled_notebook_page(notebook, _("Windows"));
2368 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2370 ct_button = pref_checkbox_new_int(group, _("Remember session"),
2371 options->save_window_positions, &c_options->save_window_positions);
2373 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2374 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2375 pref_checkbox_link_sensitivity(ct_button, button);
2377 button = pref_checkbox_new_int(group, _("Remember window workspace"),
2378 options->save_window_workspace, &c_options->save_window_workspace);
2379 pref_checkbox_link_sensitivity(ct_button, button);
2381 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2382 options->tools_restore_state, &c_options->tools_restore_state);
2384 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2385 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2387 pref_checkbox_new_int(group, _("Show window IDs"),
2388 options->show_window_ids, &c_options->show_window_ids);
2390 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2391 pref_label_new(subgroup, _("Use current layout for default: "));
2392 button = pref_button_new(subgroup, nullptr, _("Set"), G_CALLBACK(save_default_window_layout_cb), nullptr);
2396 popover = create_popover(button, gtk_label_new(_("Current window layout\nhas been set as default")), GTK_POS_TOP);
2397 gtk_popover_set_modal(GTK_POPOVER (popover), FALSE);
2398 g_signal_connect(button, "clicked", G_CALLBACK(default_layout_changed_cb), popover);
2400 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2402 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2403 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2405 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2406 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2407 options->image.limit_window_size, &c_options->image.limit_window_size);
2408 spin = pref_spin_new_int(hbox, nullptr, nullptr,
2410 options->image.max_window_size, &c_options->image.max_window_size);
2411 pref_checkbox_link_sensitivity(ct_button, spin);
2413 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2415 c_options->fullscreen.screen = options->fullscreen.screen;
2416 c_options->fullscreen.above = options->fullscreen.above;
2417 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2418 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2419 gtk_widget_show(hbox);
2421 pref_checkbox_new_int(group, _("Smooth image flip"),
2422 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2423 pref_checkbox_new_int(group, _("Disable screen saver"),
2424 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2427 #define PRE_FORMATTED_COLUMNS 5
2428 static void config_tab_osd(GtkWidget *notebook)
2434 GtkWidget *image_overlay_template_view;
2435 GtkWidget *scrolled;
2436 GtkWidget *scrolled_pre_formatted;
2437 GtkTextBuffer *buffer;
2439 GtkWidget *subgroup;
2441 vbox = scrolled_notebook_page(notebook, _("OSD"));
2443 image_overlay_template_view = gtk_text_view_new();
2445 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2447 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2449 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2450 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2451 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2452 gtk_widget_show(scrolled_pre_formatted);
2453 gtk_widget_show(subgroup);
2455 pref_line(group, PREF_PAD_GAP);
2457 pref_label_new(group, _("Image overlay template"));
2459 scrolled = gtk_scrolled_window_new(nullptr, nullptr);
2460 gtk_widget_set_size_request(scrolled, 200, 150);
2461 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2462 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2463 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2464 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2465 gtk_widget_show(scrolled);
2467 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2468 _("Extensive formatting options are shown in the Help file"));
2470 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2471 gtk_widget_show(image_overlay_template_view);
2473 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2475 button = pref_button_new(nullptr, GQ_ICON_SELECT_FONT, _("Font"),
2476 G_CALLBACK(image_overlay_set_font_cb), notebook);
2478 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2479 gtk_widget_show(button);
2481 button = pref_button_new(nullptr, GQ_ICON_SELECT_COLOR, _("Text"),
2482 G_CALLBACK(image_overlay_set_text_colour_cb), nullptr);
2483 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2484 gtk_widget_show(button);
2486 button = pref_button_new(nullptr, GQ_ICON_SELECT_COLOR, _("Background"),
2487 G_CALLBACK(image_overlay_set_background_colour_cb), nullptr);
2488 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2489 gtk_widget_show(button);
2490 image_overlay_set_text_colours();
2492 button = pref_button_new(nullptr, nullptr, _("Defaults"),
2493 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2494 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2495 gtk_widget_show(button);
2497 button = pref_button_new(nullptr, GQ_ICON_HELP, _("Help"),
2498 G_CALLBACK(image_overlay_help_cb), nullptr);
2499 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2500 gtk_widget_show(button);
2502 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2503 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2504 g_signal_connect(G_OBJECT(buffer), "changed",
2505 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2507 pref_line(group, PREF_PAD_GAP);
2509 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2510 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2511 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2512 gtk_widget_show(hbox);
2513 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2514 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2515 gtk_widget_show(label);
2516 pref_spacer(group,TRUE);
2518 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2519 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2520 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2521 gtk_widget_show(hbox);
2522 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2523 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2524 gtk_widget_show(label);
2525 pref_spacer(group,TRUE);
2527 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2528 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2529 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2530 gtk_widget_show(hbox);
2531 label = gtk_label_new(_("%path:39%"));
2532 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2533 gtk_widget_show(label);
2534 pref_spacer(group,TRUE);
2536 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2537 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2538 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2539 gtk_widget_show(hbox);
2540 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%"));
2541 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2542 gtk_widget_show(label);
2543 pref_spacer(group,TRUE);
2545 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2546 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2547 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2548 gtk_widget_show(hbox);
2549 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2550 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2551 gtk_widget_show(label);
2554 static GtkTreeModel *create_class_model()
2556 GtkListStore *model;
2560 /* create list store */
2561 model = gtk_list_store_new(1, G_TYPE_STRING);
2562 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2564 gtk_list_store_append(model, &iter);
2565 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2567 return GTK_TREE_MODEL (model);
2572 static gint filter_table_sort_cb(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data)
2574 gint n = GPOINTER_TO_INT(data);
2576 FilterEntry *filter_a;
2577 FilterEntry *filter_b;
2579 gtk_tree_model_get(model, a, 0, &filter_a, -1);
2580 gtk_tree_model_get(model, b, 0, &filter_b, -1);
2584 case FILETYPES_COLUMN_ENABLED:
2586 ret = filter_a->enabled - filter_b->enabled;
2589 case FILETYPES_COLUMN_FILTER:
2591 ret = g_utf8_collate(filter_a->extensions, filter_b->extensions);
2594 case FILETYPES_COLUMN_DESCRIPTION:
2596 ret = g_utf8_collate(filter_a->description, filter_b->description);
2599 case FILETYPES_COLUMN_CLASS:
2601 ret = g_strcmp0(format_class_list[filter_a->file_class], format_class_list[filter_b->file_class]);
2604 case FILETYPES_COLUMN_WRITABLE:
2606 ret = filter_a->writable - filter_b->writable;
2609 case FILETYPES_COLUMN_SIDECAR:
2611 ret = filter_a->allow_sidecar - filter_b->allow_sidecar;
2615 g_return_val_if_reached(0);
2621 static gboolean search_function_cb(GtkTreeModel *model, gint, const gchar *key, GtkTreeIter *iter, gpointer)
2624 gboolean ret = TRUE;
2626 gtk_tree_model_get(model, iter, 0, &fe, -1);
2628 if (g_strstr_len(fe->extensions, -1, key))
2636 static void config_tab_files(GtkWidget *notebook)
2643 GtkWidget *ct_button;
2644 GtkWidget *scrolled;
2645 GtkWidget *filter_view;
2646 GtkCellRenderer *renderer;
2647 GtkTreeSelection *selection;
2648 GtkTreeViewColumn *column;
2650 vbox = scrolled_notebook_page(notebook, _("File Filters"));
2652 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2654 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2655 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2656 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2657 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2658 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);
2659 pref_checkbox_new_int(group, _("Disable file extension checks"),
2660 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2662 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2663 options->file_filter.disable, &c_options->file_filter.disable);
2666 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2668 sidecar_ext_entry = gtk_entry_new();
2669 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2670 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2671 gtk_widget_show(sidecar_ext_entry);
2673 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2675 frame = pref_group_parent(group);
2676 g_signal_connect(G_OBJECT(ct_button), "toggled",
2677 G_CALLBACK(filter_disable_cb), frame);
2678 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2680 scrolled = gtk_scrolled_window_new(nullptr, nullptr);
2681 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2682 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2683 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2684 gtk_widget_show(scrolled);
2686 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2687 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2688 g_object_unref(filter_store);
2689 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2690 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2692 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2694 column = gtk_tree_view_column_new();
2695 gtk_tree_view_column_set_title(column, _("Enabled"));
2696 gtk_tree_view_column_set_resizable(column, TRUE);
2698 renderer = gtk_cell_renderer_toggle_new();
2699 g_signal_connect(G_OBJECT(renderer), "toggled",
2700 G_CALLBACK(filter_store_enable_cb), filter_store);
2701 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2702 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2703 GINT_TO_POINTER(FE_ENABLE), nullptr);
2704 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);
2705 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_ENABLED);
2706 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2708 column = gtk_tree_view_column_new();
2709 gtk_tree_view_column_set_title(column, _("Filter"));
2710 gtk_tree_view_column_set_resizable(column, TRUE);
2711 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);
2712 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_FILTER);
2714 renderer = gtk_cell_renderer_text_new();
2715 g_signal_connect(G_OBJECT(renderer), "edited",
2716 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2717 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2718 g_object_set(G_OBJECT(renderer), "editable", static_cast<gboolean>TRUE, NULL);
2719 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2720 GINT_TO_POINTER(FE_EXTENSION), nullptr);
2721 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2723 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), TRUE);
2724 gtk_tree_view_set_search_column(GTK_TREE_VIEW(filter_view), FILETYPES_COLUMN_FILTER);
2725 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(filter_view), search_function_cb, nullptr, nullptr);
2727 column = gtk_tree_view_column_new();
2728 gtk_tree_view_column_set_title(column, _("Description"));
2729 gtk_tree_view_column_set_resizable(column, TRUE);
2730 gtk_tree_view_column_set_fixed_width(column, 200);
2731 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2733 renderer = gtk_cell_renderer_text_new();
2734 g_signal_connect(G_OBJECT(renderer), "edited",
2735 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2736 g_object_set(G_OBJECT(renderer), "editable", static_cast<gboolean>TRUE, NULL);
2737 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2738 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2739 GINT_TO_POINTER(FE_DESCRIPTION), nullptr);
2740 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2741 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);
2742 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_DESCRIPTION);
2744 column = gtk_tree_view_column_new();
2745 gtk_tree_view_column_set_title(column, _("Class"));
2746 gtk_tree_view_column_set_resizable(column, TRUE);
2747 renderer = gtk_cell_renderer_combo_new();
2748 g_object_set(G_OBJECT(renderer), "editable", static_cast<gboolean>TRUE,
2749 "model", create_class_model(),
2754 g_signal_connect(G_OBJECT(renderer), "edited",
2755 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2756 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2757 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2758 GINT_TO_POINTER(FE_CLASS), nullptr);
2759 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2760 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);
2761 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_CLASS);
2763 column = gtk_tree_view_column_new();
2764 gtk_tree_view_column_set_title(column, _("Writable"));
2765 gtk_tree_view_column_set_resizable(column, FALSE);
2766 renderer = gtk_cell_renderer_toggle_new();
2767 g_signal_connect(G_OBJECT(renderer), "toggled",
2768 G_CALLBACK(filter_store_writable_cb), filter_store);
2769 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2770 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2771 GINT_TO_POINTER(FE_WRITABLE), nullptr);
2772 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2773 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);
2774 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_WRITABLE);
2776 column = gtk_tree_view_column_new();
2777 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2778 gtk_tree_view_column_set_resizable(column, FALSE);
2779 renderer = gtk_cell_renderer_toggle_new();
2780 g_signal_connect(G_OBJECT(renderer), "toggled",
2781 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2782 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2783 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2784 GINT_TO_POINTER(FE_ALLOW_SIDECAR), nullptr);
2785 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2786 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);
2787 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_SIDECAR);
2789 filter_store_populate();
2790 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2791 gtk_widget_show(filter_view);
2793 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2795 button = pref_button_new(nullptr, nullptr, _("Defaults"),
2796 G_CALLBACK(filter_default_cb), filter_view);
2797 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2798 gtk_widget_show(button);
2800 button = pref_button_new(nullptr, GQ_ICON_REMOVE, _("Remove"),
2801 G_CALLBACK(filter_remove_cb), filter_view);
2802 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2803 gtk_widget_show(button);
2805 button = pref_button_new(nullptr, GQ_ICON_ADD, _("Add"),
2806 G_CALLBACK(filter_add_cb), filter_view);
2807 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2808 gtk_widget_show(button);
2812 static void config_tab_metadata(GtkWidget *notebook)
2817 GtkWidget *ct_button;
2819 GtkWidget *tmp_widget;
2821 GtkWidget *text_label;
2823 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2826 group = pref_group_new(vbox, FALSE, _("Metadata writing sequence"), GTK_ORIENTATION_VERTICAL);
2828 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2830 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."));
2831 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2832 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2834 gtk_widget_set_tooltip_text(label, _("A flowchart of the sequence is shown in the Help file"));
2836 ct_button = pref_checkbox_new_int(group, "", options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2837 text_label = gtk_bin_get_child(GTK_BIN(ct_button));
2838 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"));
2839 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2841 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)"));
2842 gtk_widget_set_tooltip_markup(ct_button, markup);
2846 gtk_widget_set_sensitive(ct_button, FALSE);
2849 tmp_widget = pref_checkbox_new_int(group, "", options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2850 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2851 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)"));
2852 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2855 label = pref_label_new(group, "");
2856 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(), "/");
2857 gtk_label_set_markup (GTK_LABEL(label), markup);
2860 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2861 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2862 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2863 pref_spacer(group, PREF_PAD_GROUP);
2865 group = pref_group_new(vbox, FALSE, _("Step 1 Options:"), GTK_ORIENTATION_VERTICAL);
2867 gtk_widget_set_sensitive(group, FALSE);
2870 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2871 pref_checkbox_link_sensitivity(ct_button, hbox);
2873 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);
2874 gtk_widget_set_tooltip_text(tmp_widget, _("A simplified conversion list is in the Help file"));
2876 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);
2878 pref_checkbox_new_int(hbox, _("Ask before writing to image files"), options->metadata.confirm_write, &c_options->metadata.confirm_write);
2880 tmp_widget= pref_checkbox_new_int(hbox, "", options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2881 gtk_widget_set_tooltip_text(tmp_widget, _("This file naming convention is used by Darktable"));
2882 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2883 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", ")");
2884 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2887 pref_spacer(group, PREF_PAD_GROUP);
2889 group = pref_group_new(vbox, FALSE, _("Steps 2 and 3 Option:"), GTK_ORIENTATION_VERTICAL);
2891 gtk_widget_set_sensitive(group, FALSE);
2894 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);
2896 pref_spacer(group, PREF_PAD_GROUP);
2898 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2899 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);
2900 gtk_widget_set_tooltip_text(tmp_widget, _("See the Help file for a list of the tags used"));
2902 tmp_widget = pref_checkbox_new_int(group, _("Permit Keywords to be case-sensitive"), options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2903 gtk_widget_set_tooltip_text(tmp_widget, _("When selected, \"Place\" and \"place\" are two different keywords"));
2905 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"), options->metadata.write_orientation, &c_options->metadata.write_orientation);
2906 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"));
2909 gtk_widget_set_sensitive(ct_button, FALSE);
2912 pref_spacer(group, PREF_PAD_GROUP);
2914 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2916 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"), options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2918 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2919 pref_checkbox_link_sensitivity(ct_button, hbox);
2921 pref_spin_new_int(hbox, _("Timeout (seconds):"), nullptr, 0, 900, 1, options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2923 pref_checkbox_new_int(group, _("Write metadata on image change"), options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2925 pref_checkbox_new_int(group, _("Write metadata on directory change"), options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2927 pref_spacer(group, PREF_PAD_GROUP);
2930 group = pref_group_new(vbox, FALSE, _("Spelling checks"), GTK_ORIENTATION_VERTICAL);
2932 ct_button = pref_checkbox_new_int(group, _("Check spelling - Requires restart"), options->metadata.check_spelling, &c_options->metadata.check_spelling);
2933 gtk_widget_set_tooltip_text(ct_button, _("Spelling checks are performed on info sidebar panes Comment, Headline and Title"));
2936 pref_spacer(group, PREF_PAD_GROUP);
2938 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2940 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"), options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2941 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");
2946 struct KeywordFindData
2953 GtkWidget *button_close;
2954 GtkWidget *button_stop;
2955 GtkWidget *button_start;
2956 GtkWidget *progress;
2964 guint idle_id; /* event source id */
2967 #define KEYWORD_DIALOG_WIDTH 400
2969 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
2971 GList *list_d = nullptr;
2972 GList *list_f = nullptr;
2976 filelist_read(dir_fd, &list_f, &list_d);
2980 filelist_read(dir_fd, &list_f, nullptr);
2983 list_f = filelist_filter(list_f, FALSE);
2984 list_d = filelist_filter(list_d, TRUE);
2986 kfd->list = g_list_concat(list_f, kfd->list);
2987 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
2990 static void keywords_find_reset(KeywordFindData *kfd)
2992 filelist_free(kfd->list);
2993 kfd->list = nullptr;
2995 filelist_free(kfd->list_dir);
2996 kfd->list_dir = nullptr;
2999 static void keywords_find_close_cb(GenericDialog *, gpointer data)
3001 auto kfd = static_cast<KeywordFindData *>(data);
3003 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
3005 keywords_find_reset(kfd);
3006 generic_dialog_close(kfd->gd);
3010 static void keywords_find_finish(KeywordFindData *kfd)
3012 keywords_find_reset(kfd);
3014 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
3015 gtk_spinner_stop(GTK_SPINNER(kfd->spinner));
3017 gtk_widget_set_sensitive(kfd->group, TRUE);
3018 gtk_widget_set_sensitive(kfd->button_start, TRUE);
3019 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3020 gtk_widget_set_sensitive(kfd->button_close, TRUE);
3023 static void keywords_find_stop_cb(GenericDialog *, gpointer data)
3025 auto kfd = static_cast<KeywordFindData *>(data);
3027 g_idle_remove_by_data(kfd);
3029 keywords_find_finish(kfd);
3032 static gboolean keywords_find_file(gpointer data)
3034 auto kfd = static_cast<KeywordFindData *>(data);
3036 GtkTextBuffer *buffer;
3044 fd = static_cast<FileData *>(kfd->list->data);
3045 kfd->list = g_list_remove(kfd->list, fd);
3047 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
3048 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3052 gtk_text_buffer_get_end_iter(buffer, &iter);
3053 tmp = g_strconcat(static_cast<const gchar *>(keywords->data), "\n", NULL);
3054 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3056 keywords = keywords->next;
3059 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
3060 file_data_unref(fd);
3061 g_list_free_full(keywords, g_free);
3063 return (G_SOURCE_CONTINUE);
3065 else if (kfd->list_dir)
3069 fd = static_cast<FileData *>(kfd->list_dir->data);
3070 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
3072 keywords_find_folder(kfd, fd);
3074 file_data_unref(fd);
3076 return G_SOURCE_CONTINUE;
3079 keywords_find_finish(kfd);
3081 return G_SOURCE_REMOVE;
3084 static void keywords_find_start_cb(GenericDialog *, gpointer data)
3086 auto kfd = static_cast<KeywordFindData *>(data);
3089 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
3091 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
3092 parse_out_relatives(path);
3096 warning_dialog(_("Invalid folder"),
3097 _("The specified folder can not be found."),
3098 GQ_ICON_DIALOG_WARNING, kfd->gd->dialog);
3104 gtk_widget_set_sensitive(kfd->group, FALSE);
3105 gtk_widget_set_sensitive(kfd->button_start, FALSE);
3106 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
3107 gtk_widget_set_sensitive(kfd->button_close, FALSE);
3108 gtk_spinner_start(GTK_SPINNER(kfd->spinner));
3110 dir_fd = file_data_new_dir(path);
3111 keywords_find_folder(kfd, dir_fd);
3112 file_data_unref(dir_fd);
3113 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
3119 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
3121 KeywordFindData *kfd;
3125 kfd = g_new0(KeywordFindData, 1);
3127 kfd->gd = generic_dialog_new(_("Search for keywords"),
3128 "search_for_keywords",
3131 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
3132 kfd->gd->cancel_cb = keywords_find_close_cb;
3133 kfd->button_close = generic_dialog_add_button(kfd->gd, GQ_ICON_CLOSE, _("Close"),
3134 keywords_find_close_cb, FALSE);
3135 kfd->button_start = generic_dialog_add_button(kfd->gd, GQ_ICON_OK, _("S_tart"),
3136 keywords_find_start_cb, FALSE);
3137 kfd->button_stop = generic_dialog_add_button(kfd->gd, GQ_ICON_STOP, _("Stop"),
3138 keywords_find_stop_cb, FALSE);
3139 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3141 generic_dialog_add_message(kfd->gd, nullptr, _("Search for keywords"), nullptr, FALSE);
3143 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
3144 pref_spacer(hbox, PREF_PAD_INDENT);
3145 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
3147 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3148 pref_label_new(hbox, _("Folder:"));
3150 label = tab_completion_new(&kfd->entry, path, nullptr, nullptr, nullptr, nullptr);
3151 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
3152 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
3153 gtk_widget_show(label);
3155 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
3157 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
3158 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3160 kfd->progress = gtk_entry_new();
3161 gtk_widget_set_can_focus(kfd->progress, FALSE);
3162 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
3163 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
3164 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
3165 gtk_widget_show(kfd->progress);
3167 kfd->spinner = gtk_spinner_new();
3168 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
3169 gtk_widget_show(kfd->spinner);
3171 kfd->list = nullptr;
3173 gtk_widget_show(kfd->gd->dialog);
3176 static void keywords_find_cb(GtkWidget *widget, gpointer)
3178 const gchar *path = layout_get_path(nullptr);
3180 if (!path || !*path) path = homedir();
3181 keywords_find_dialog(widget, path);
3184 static void config_tab_keywords_save()
3186 GtkTextIter start, end;
3187 GtkTextBuffer *buffer;
3188 GList *kw_list = nullptr;
3194 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3195 gtk_text_buffer_get_bounds(buffer, &start, &end);
3197 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3199 kw_split = strtok(buffer_text, "\n");
3200 while (kw_split != nullptr)
3206 if (g_strcmp0(static_cast<const gchar *>(work->data), kw_split) == 0)
3215 kw_list = g_list_append(kw_list, g_strdup(kw_split));
3217 kw_split = strtok(nullptr, "\n");
3220 keyword_list_set(kw_list);
3222 g_list_free_full(kw_list, g_free);
3223 g_free(buffer_text);
3226 static void config_tab_keywords(GtkWidget *notebook)
3232 GtkWidget *scrolled;
3234 GtkTextBuffer *buffer;
3237 GspellTextView *gspell_view;
3240 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3242 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3244 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3246 button = pref_button_new(hbox, GQ_ICON_RUN, _("Search"),
3247 G_CALLBACK(keywords_find_cb), keyword_text);
3248 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
3251 keyword_text = gtk_text_view_new();
3252 gtk_widget_set_size_request(keyword_text, 20, 20);
3253 scrolled = gtk_scrolled_window_new(nullptr, nullptr);
3254 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3255 gtk_widget_show(scrolled);
3258 if (options->metadata.check_spelling)
3260 gspell_view = gspell_text_view_get_from_gtk_text_view(GTK_TEXT_VIEW(keyword_text));
3261 gspell_text_view_basic_setup(gspell_view);
3265 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
3266 gtk_widget_show(keyword_text);
3268 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3270 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3271 gtk_text_buffer_create_tag(buffer, "monospace",
3272 "family", "monospace", NULL);
3274 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3275 gtk_text_buffer_get_start_iter(buffer, &iter);
3276 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3279 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3281 GList *kwl = keyword_list_get();
3282 kwl = g_list_first(kwl);
3285 gtk_text_buffer_get_end_iter (buffer, &iter);
3286 tmp = g_strconcat(static_cast<const gchar *>(kwl->data), "\n", NULL);
3287 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3292 gtk_text_buffer_set_modified(buffer, FALSE);
3299 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3301 auto option = static_cast<gint *>(data);
3303 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3307 *option = INTENT_PERCEPTUAL;
3310 *option = INTENT_RELATIVE_COLORIMETRIC;
3313 *option = INTENT_SATURATION;
3316 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3321 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3322 gint option, gint *option_c)
3329 pref_table_label(table, column, row, text, GTK_ALIGN_START);
3331 combo = gtk_combo_box_text_new();
3333 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3334 if (option == INTENT_PERCEPTUAL) current = 0;
3335 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3336 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3337 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3338 if (option == INTENT_SATURATION) current = 2;
3339 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3340 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3342 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3344 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3346 g_signal_connect(G_OBJECT(combo), "changed",
3347 G_CALLBACK(intent_menu_cb), option_c);
3349 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
3350 gtk_widget_show(combo);
3354 static void config_tab_color(GtkWidget *notebook)
3363 vbox = scrolled_notebook_page(notebook, _("Color management"));
3365 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3367 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3370 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3371 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3373 label = pref_table_label(table, 0, 0, _("Type"), GTK_ALIGN_START);
3374 pref_label_bold(label, TRUE, FALSE);
3376 label = pref_table_label(table, 1, 0, _("Menu name"), GTK_ALIGN_START);
3377 pref_label_bold(label, TRUE, FALSE);
3379 label = pref_table_label(table, 2, 0, _("File"), GTK_ALIGN_START);
3380 pref_label_bold(label, TRUE, FALSE);
3382 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3387 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3388 pref_table_label(table, 0, i + 1, buf, GTK_ALIGN_END);
3391 entry = gtk_entry_new();
3392 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3393 if (options->color_profile.input_name[i])
3395 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3397 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3398 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), static_cast<GtkAttachOptions>(0), 0, 0);
3399 gtk_widget_show(entry);
3400 color_profile_input_name_entry[i] = entry;
3402 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], nullptr, ".icc", "ICC Files", nullptr);
3403 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3404 gtk_widget_set_size_request(entry, 160, -1);
3405 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3406 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), static_cast<GtkAttachOptions>(0), 0, 0);
3407 gtk_widget_show(tabcomp);
3408 color_profile_input_file_entry[i] = entry;
3411 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3413 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3415 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3416 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3418 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3420 pref_table_label(table, 0, 0, _("Screen:"), GTK_ALIGN_END);
3421 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3422 options->color_profile.screen_file, nullptr, ".icc", "ICC Files", nullptr);
3423 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3424 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3426 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3428 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3430 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), static_cast<GtkAttachOptions>(0), 0, 0);
3432 gtk_widget_show(tabcomp);
3435 /* advanced entry tab */
3436 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer)
3438 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3440 c_options->file_ops.use_system_trash = FALSE;
3441 c_options->file_ops.no_trash = FALSE;
3445 static void use_system_trash_cb(GtkWidget *widget, gpointer)
3447 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3449 c_options->file_ops.use_system_trash = TRUE;
3450 c_options->file_ops.no_trash = FALSE;
3454 static void use_no_cache_cb(GtkWidget *widget, gpointer)
3456 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3458 c_options->file_ops.no_trash = TRUE;
3462 static void config_tab_behavior(GtkWidget *notebook)
3469 GtkWidget *ct_button;
3473 GtkWidget *with_rename;
3474 GtkWidget *collections_on_top;
3475 GtkWidget *hide_window_in_fullscreen;
3476 GtkWidget *checkbox;
3479 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3481 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3483 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3484 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3485 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3486 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3487 pref_checkbox_new_int(group, _("Enable Delete key"),
3488 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3490 ct_button = pref_radiobutton_new(group, nullptr, _("Use Geeqie trash location"),
3491 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),nullptr);
3493 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3494 pref_checkbox_link_sensitivity(ct_button, hbox);
3496 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3497 pref_label_new(hbox, _("Folder:"));
3499 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, nullptr, nullptr, nullptr, nullptr);
3500 tab_completion_add_select_button(safe_delete_path_entry, nullptr, TRUE);
3501 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3502 gtk_widget_show(tabcomp);
3504 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3505 pref_checkbox_link_sensitivity(ct_button, hbox);
3507 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3508 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MiB"),
3509 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3510 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3511 button = pref_button_new(nullptr, nullptr, _("View"),
3512 G_CALLBACK(safe_delete_view_cb), nullptr);
3513 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3514 gtk_widget_show(button);
3516 button = pref_button_new(nullptr, GQ_ICON_CLEAR, nullptr,
3517 G_CALLBACK(safe_delete_clear_cb), nullptr);
3518 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3520 c_options->file_ops.no_trash = options->file_ops.no_trash;
3521 c_options->file_ops.use_system_trash = options->file_ops.use_system_trash;
3523 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3524 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), nullptr);
3526 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3527 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), nullptr);
3529 gtk_widget_show(button);
3531 pref_spacer(group, PREF_PAD_GROUP);
3534 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3536 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3537 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3539 pref_checkbox_new_int(group, _("In place renaming"),
3540 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3542 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3543 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3545 tmp = pref_checkbox_new_int(group, _("Circular selection lists"),
3546 options->circular_selection_lists, &c_options->circular_selection_lists);
3547 gtk_widget_set_tooltip_text(tmp, _("Traverse selection lists in a circular manner"));
3549 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3550 options->marks_save, &c_options->marks_save);
3551 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3553 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3554 options->with_rename, &c_options->with_rename);
3555 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3557 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3558 options->collections_on_top, &c_options->collections_on_top);
3559 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3561 hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3562 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3563 gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice");
3565 pref_spin_new_int(group, _("Recent folder list maximum size"), nullptr,
3566 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3568 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);
3569 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."));
3571 pref_spin_new_int(group, _("Drag'n drop icon size"), nullptr,
3572 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3574 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3575 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3577 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3578 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3580 pref_spacer(group, PREF_PAD_GROUP);
3582 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3584 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3585 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3586 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), nullptr,
3587 1, 32, 1, options->keyboard_scroll_step, reinterpret_cast<int *>(&c_options->keyboard_scroll_step));
3588 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3589 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3590 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3591 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3592 pref_checkbox_new_int(group, _("Open archive by left click on image"),
3593 options->image_l_click_archive, &c_options->image_l_click_archive);
3594 pref_checkbox_new_int(group, _("Play video by left click on image"),
3595 options->image_l_click_video, &c_options->image_l_click_video);
3596 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3597 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3599 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3600 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3601 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3602 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3603 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3605 pref_spacer(group, PREF_PAD_GROUP);
3607 group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3609 checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3610 options->override_disable_gpu, &c_options->override_disable_gpu);
3611 gtk_widget_set_tooltip_text(checkbox, "Contact the developers for usage");
3614 pref_spacer(group, PREF_PAD_GROUP);
3616 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3618 pref_spin_new_int(group, _("Debug level:"), nullptr,
3619 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3621 pref_checkbox_new_int(group, _("Timer data"),
3622 options->log_window.timer_data, &c_options->log_window.timer_data);
3624 pref_spin_new_int(group, _("Log Window max. lines:"), nullptr,
3625 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3629 /* accelerators tab */
3631 static gboolean accel_search_function_cb(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer)
3633 gboolean ret = TRUE;
3638 gtk_tree_model_get(model, iter, column, &text, -1);
3639 text_nocase = g_utf8_casefold(text, -1);
3640 key_nocase = g_utf8_casefold(key, -1);
3642 if (g_strstr_len(text_nocase, -1, key_nocase))
3649 g_free(text_nocase);
3654 static void accel_row_activated_cb(GtkTreeView *tree_view, GtkTreePath *, GtkTreeViewColumn *column, gpointer)
3659 list = gtk_tree_view_get_columns(tree_view);
3660 col_num = g_list_index(list, column);
3664 gtk_tree_view_set_search_column(tree_view, col_num);
3667 static void config_tab_accelerators(GtkWidget *notebook)
3673 GtkWidget *scrolled;
3674 GtkWidget *accel_view;
3675 GtkCellRenderer *renderer;
3676 GtkTreeSelection *selection;
3677 GtkTreeViewColumn *column;
3679 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3681 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3683 scrolled = gtk_scrolled_window_new(nullptr, nullptr);
3684 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3685 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3686 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3687 gtk_widget_show(scrolled);
3689 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3691 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3692 g_object_unref(accel_store);
3693 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3694 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3696 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3698 renderer = gtk_cell_renderer_text_new();
3700 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3705 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3706 gtk_tree_view_column_set_resizable(column, TRUE);
3707 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3710 renderer = gtk_cell_renderer_accel_new();
3711 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3712 G_CALLBACK(accel_store_cleared_cb), accel_store);
3713 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3714 G_CALLBACK(accel_store_edited_cb), accel_store);
3717 g_object_set (renderer,
3719 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3722 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3727 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3728 gtk_tree_view_column_set_resizable(column, TRUE);
3729 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3731 renderer = gtk_cell_renderer_text_new();
3733 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3738 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3739 gtk_tree_view_column_set_resizable(column, TRUE);
3740 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3742 renderer = gtk_cell_renderer_text_new();
3744 column = gtk_tree_view_column_new_with_attributes("Accel",
3749 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3750 gtk_tree_view_column_set_resizable(column, TRUE);
3751 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3753 /* Search on text in column */
3754 gtk_tree_view_set_activate_on_single_click(GTK_TREE_VIEW(accel_view), TRUE);
3755 g_signal_connect(accel_view, "row_activated", G_CALLBACK(accel_row_activated_cb), accel_store);
3756 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), TRUE);
3757 gtk_tree_view_set_search_column(GTK_TREE_VIEW(accel_view), AE_TOOLTIP);
3758 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(accel_view), accel_search_function_cb, nullptr, nullptr);
3760 accel_store_populate();
3761 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3762 gtk_widget_show(accel_view);
3764 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3766 button = pref_button_new(nullptr, nullptr, _("Defaults"),
3767 G_CALLBACK(accel_default_cb), accel_view);
3768 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3769 gtk_widget_show(button);
3771 button = pref_button_new(nullptr, nullptr, _("Reset selected"),
3772 G_CALLBACK(accel_reset_cb), accel_view);
3773 gtk_widget_set_tooltip_text(button, _("Will only reset changes made before the settings are saved"));
3774 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3775 gtk_widget_show(button);
3777 button = pref_button_new(nullptr, nullptr, _("Clear selected"),
3778 G_CALLBACK(accel_clear_cb), accel_view);
3779 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3780 gtk_widget_show(button);
3783 /* toolbar main tab */
3784 static void config_tab_toolbar_main(GtkWidget *notebook)
3787 GtkWidget *toolbardata;
3790 lw = static_cast<LayoutWindow *>(layout_window_list->data);
3792 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3794 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3795 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3796 gtk_widget_show(vbox);
3799 /* toolbar status tab */
3800 static void config_tab_toolbar_status(GtkWidget *notebook)
3803 GtkWidget *toolbardata;
3806 lw = static_cast<LayoutWindow *>(layout_window_list->data);
3808 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3810 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3811 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3812 gtk_widget_show(vbox);
3816 static gint extension_sort_cb(gconstpointer a, gconstpointer b)
3818 return g_strcmp0(static_cast<const gchar *>(a), static_cast<const gchar *>(b));
3821 static void config_tab_advanced(GtkWidget *notebook)
3825 GSList *formats_list;
3826 GList *extensions_list = nullptr;
3829 GdkPixbufFormat *fm;
3831 GString *types_string = g_string_new(nullptr);
3832 GtkWidget *types_string_label;
3833 GtkWidget *threads_string_label;
3834 GtkWidget *dupes_threads_spin;
3836 vbox = scrolled_notebook_page(notebook, _("Advanced"));
3837 group = pref_group_new(vbox, FALSE, _("External preview extraction"), GTK_ORIENTATION_VERTICAL);
3839 pref_checkbox_new_int(group, _("Use external preview extraction - Requires restart"), options->external_preview.enable, &c_options->external_preview.enable);
3841 pref_spacer(group, PREF_PAD_GROUP);
3843 formats_list = gdk_pixbuf_get_formats();
3845 while (formats_list)
3847 fm = static_cast<GdkPixbufFormat *>(formats_list->data);
3848 extensions = gdk_pixbuf_format_get_extensions(fm);
3851 while (extensions[i])
3853 extensions_list = g_list_insert_sorted(extensions_list, g_strdup(extensions[i]), extension_sort_cb);
3857 g_strfreev(extensions);
3858 formats_list = formats_list->next;
3861 while (extensions_list)
3863 if (types_string->len == 0)
3865 types_string = g_string_append(types_string, static_cast<const gchar *>(extensions_list->data));
3869 types_string = g_string_append(types_string, ", ");
3870 types_string = g_string_append(types_string, static_cast<const gchar *>(extensions_list->data));
3873 extensions_list = extensions_list->next;
3876 types_string = g_string_prepend(types_string, _("Usable file types:\n"));
3877 types_string_label = pref_label_new(group, types_string->str);
3878 gtk_label_set_line_wrap(GTK_LABEL(types_string_label), TRUE);
3880 pref_spacer(group, PREF_PAD_GROUP);
3882 group = pref_group_new(vbox, FALSE, _("File identification tool"), GTK_ORIENTATION_VERTICAL);
3883 external_preview_select_entry = gtk_entry_new();
3884 tabcomp = tab_completion_new(&external_preview_select_entry, options->external_preview.select, nullptr, nullptr, nullptr, nullptr);
3885 tab_completion_add_select_button(external_preview_select_entry, _("Select file identification tool"), FALSE);
3886 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3887 gtk_widget_show(tabcomp);
3889 group = pref_group_new(vbox, FALSE, _("Preview extraction tool"), GTK_ORIENTATION_VERTICAL);
3890 external_preview_extract_entry = gtk_entry_new();
3891 tabcomp = tab_completion_new(&external_preview_extract_entry, options->external_preview.extract, nullptr, nullptr, nullptr, nullptr);
3892 tab_completion_add_select_button(external_preview_extract_entry, _("Select preview extraction tool"), FALSE);
3893 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3894 gtk_widget_show(tabcomp);
3896 gtk_widget_show(vbox);
3898 g_slist_free(formats_list);
3899 g_list_free_full(extensions_list, g_free);
3900 g_string_free(types_string, TRUE);
3902 pref_spacer(group, PREF_PAD_GROUP);
3904 pref_line(vbox, PREF_PAD_SPACE);
3905 group = pref_group_new(vbox, FALSE, _("Thread pool limits"), GTK_ORIENTATION_VERTICAL);
3907 threads_string_label = pref_label_new(group, "This option limits the number of threads (or cpu cores)\nthat Geeqie will use when running duplicate checks. The default value is 0, which means all available cores will be used.");
3908 gtk_label_set_line_wrap(GTK_LABEL(threads_string_label), TRUE);
3910 pref_spacer(vbox, PREF_PAD_GROUP);
3912 dupes_threads_spin = pref_spin_new_int(vbox, _("Duplicate check:"), _("max. threads"), 0, get_cpu_cores(), 1, options->threads.duplicates, &c_options->threads.duplicates);
3913 gtk_widget_set_tooltip_markup(dupes_threads_spin, _("Set to 0 for unlimited"));
3917 static void config_tab_stereo(GtkWidget *notebook)
3925 GtkWidget *fs_button;
3926 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3928 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3930 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3931 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3933 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3934 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
3935 pref_checkbox_new_int(box, _("Mirror left image"),
3936 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3937 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
3938 pref_checkbox_new_int(box, _("Flip left image"),
3939 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3940 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
3941 pref_checkbox_new_int(box, _("Mirror right image"),
3942 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3943 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
3944 pref_checkbox_new_int(box, _("Flip right image"),
3945 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3946 pref_checkbox_new_int(group, _("Swap left and right images"),
3947 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3948 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3949 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3951 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3952 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3953 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3954 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3955 pref_checkbox_link_sensitivity(fs_button, box2);
3956 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3957 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3958 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3959 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
3960 pref_checkbox_new_int(box, _("Mirror left image"),
3961 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3962 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, nullptr);
3963 pref_checkbox_new_int(box, _("Flip left image"),
3964 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3965 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
3966 pref_checkbox_new_int(box, _("Mirror right image"),
3967 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3968 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, nullptr);
3969 pref_checkbox_new_int(box, _("Flip right image"),
3970 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3971 pref_checkbox_new_int(box2, _("Swap left and right images"),
3972 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3973 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3974 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3976 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3977 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3978 pref_table_spin_new_int(table, 0, 0, _("Width"), nullptr,
3979 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3980 pref_table_spin_new_int(table, 3, 0, _("Height"), nullptr,
3981 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3982 pref_table_spin_new_int(table, 0, 1, _("Left X"), nullptr,
3983 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3984 pref_table_spin_new_int(table, 3, 1, _("Left Y"), nullptr,
3985 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3986 pref_table_spin_new_int(table, 0, 2, _("Right X"), nullptr,
3987 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3988 pref_table_spin_new_int(table, 3, 2, _("Right Y"), nullptr,
3989 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3993 /* Main preferences window */
3994 static void config_window_create(LayoutWindow *lw)
3996 GtkWidget *win_vbox;
3998 GtkWidget *notebook;
4000 GtkWidget *ct_button;
4002 if (!c_options) c_options = init_options(nullptr);
4004 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, nullptr, _("Preferences"));
4005 DEBUG_NAME(configwindow);
4006 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
4007 g_signal_connect(G_OBJECT(configwindow), "delete_event",
4008 G_CALLBACK(config_window_delete), NULL);
4009 if (options->save_dialog_window_positions)
4011 gtk_window_resize(GTK_WINDOW(configwindow), lw->options.preferences_window.w, lw->options.preferences_window.h);
4012 gtk_window_move(GTK_WINDOW(configwindow), lw->options.preferences_window.x, lw->options.preferences_window.y);
4016 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
4018 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
4019 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
4021 win_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
4022 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
4023 gtk_widget_show(win_vbox);
4025 notebook = gtk_notebook_new();
4026 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
4027 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
4028 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
4030 config_tab_general(notebook);
4031 config_tab_image(notebook);
4032 config_tab_osd(notebook);
4033 config_tab_windows(notebook);
4034 config_tab_accelerators(notebook);
4035 config_tab_files(notebook);
4036 config_tab_metadata(notebook);
4037 config_tab_keywords(notebook);
4038 config_tab_color(notebook);
4039 config_tab_stereo(notebook);
4040 config_tab_behavior(notebook);
4041 config_tab_toolbar_main(notebook);
4042 config_tab_toolbar_status(notebook);
4043 config_tab_advanced(notebook);
4045 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), lw->options.preferences_window.page_number);
4047 hbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
4048 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
4049 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
4050 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
4051 gtk_widget_show(hbox);
4053 button = pref_button_new(nullptr, GQ_ICON_HELP, _("Help"),
4054 G_CALLBACK(config_window_help_cb), notebook);
4055 gtk_container_add(GTK_CONTAINER(hbox), button);
4056 gtk_widget_set_can_default(button, TRUE);
4057 gtk_widget_show(button);
4059 button = pref_button_new(nullptr, GQ_ICON_OK, "OK",
4060 G_CALLBACK(config_window_ok_cb), notebook);
4061 gtk_container_add(GTK_CONTAINER(hbox), button);
4062 gtk_widget_set_can_default(button, TRUE);
4063 gtk_widget_grab_default(button);
4064 gtk_widget_show(button);
4068 button = pref_button_new(nullptr, GQ_ICON_CANCEL, _("Cancel"),
4069 G_CALLBACK(config_window_close_cb), nullptr);
4070 gtk_container_add(GTK_CONTAINER(hbox), button);
4071 gtk_widget_set_can_default(button, TRUE);
4072 gtk_widget_show(button);
4074 if (!generic_dialog_get_alternative_button_order(configwindow))
4076 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
4079 gtk_widget_show(notebook);
4081 gtk_widget_show(configwindow);
4085 *-----------------------------------------------------------------------------
4086 * config window show (public)
4087 *-----------------------------------------------------------------------------
4090 void show_config_window(LayoutWindow *lw)
4094 gtk_window_present(GTK_WINDOW(configwindow));
4098 config_window_create(lw);
4107 void show_about_window(LayoutWindow *lw)
4109 GDataInputStream *data_stream;
4110 GInputStream *in_stream_authors;
4111 GInputStream *in_stream_translators;
4113 GdkPixbuf *pixbuf_icon;
4114 GdkPixbuf *pixbuf_logo;
4118 gchar *authors[1000];
4119 gchar *authors_path;
4121 gchar *timezone_path;
4123 gchar *translators_path;
4131 copyright = g_string_new(nullptr);
4132 copyright = g_string_append(copyright, "This program comes with absolutely no warranty.\nGNU General Public License, version 2 or later.\nSee https://www.gnu.org/licenses/old-licenses/gpl-2.0.html\n\n");
4134 timezone_path = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
4135 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
4137 cd = ZDOpenDatabase(timezone_path);
4140 copyright = g_string_append(copyright, ZDGetNotice(cd));
4144 log_printf("Error: Init of timezone database %s failed\n", timezone_path);
4146 ZDCloseDatabase(cd);
4148 g_free(timezone_path);
4150 authors_path = g_build_filename(GQ_RESOURCE_PATH_CREDITS, "authors", NULL);
4152 in_stream_authors = g_resources_open_stream(authors_path, G_RESOURCE_LOOKUP_FLAGS_NONE, nullptr);
4154 data_stream = g_data_input_stream_new(in_stream_authors);
4156 authors[0] = nullptr;
4157 while ((author_line = g_data_input_stream_read_line(G_DATA_INPUT_STREAM(data_stream), &length, nullptr, nullptr)))
4159 authors[i_authors] = g_strdup(author_line);
4161 g_free(author_line);
4163 authors[i_authors] = nullptr;
4165 g_input_stream_close(in_stream_authors, nullptr, nullptr);
4167 translators_path = g_build_filename(GQ_RESOURCE_PATH_CREDITS, "translators", NULL);
4169 g_resources_get_info(translators_path, G_RESOURCE_LOOKUP_FLAGS_NONE, &size, &flags, nullptr);
4171 in_stream_translators = g_resources_open_stream(translators_path, G_RESOURCE_LOOKUP_FLAGS_NONE, nullptr);
4172 translators = static_cast<gchar *>(g_malloc0(size));
4173 g_input_stream_read_all(in_stream_translators, translators, size, &bytes_read, nullptr, nullptr);
4174 g_input_stream_close(in_stream_translators, nullptr, nullptr);
4176 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);
4178 artists[0] = g_strdup("Néstor Díaz Valencia <nestor@estudionexos.com>");
4179 artists[1] = nullptr;
4181 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
4182 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
4183 gtk_show_about_dialog(GTK_WINDOW(lw->window),
4184 "title", _("About Geeqie"),
4186 "program-name", GQ_APPNAME,
4188 "logo", pixbuf_logo,
4189 "icon", pixbuf_icon,
4190 "website", GQ_WEBSITE,
4191 "website-label", "Website",
4192 "comments", comment,
4195 "translator-credits", translators,
4196 "wrap-license", TRUE,
4197 "license", copyright->str,
4200 g_string_free(copyright, TRUE);
4202 while(n < i_authors)
4209 g_free(authors_path);
4211 g_free(translators);
4212 g_free(translators_path);
4213 g_object_unref(data_stream);
4214 g_object_unref(in_stream_authors);
4215 g_object_unref(in_stream_translators);
4218 static void image_overlay_set_text_colours()
4220 c_options->image_overlay.text_red = options->image_overlay.text_red;
4221 c_options->image_overlay.text_green = options->image_overlay.text_green;
4222 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
4223 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
4224 c_options->image_overlay.background_red = options->image_overlay.background_red;
4225 c_options->image_overlay.background_green = options->image_overlay.background_green;
4226 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
4227 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
4231 *-----------------------------------------------------------------------------
4232 * timezone database routines
4233 *-----------------------------------------------------------------------------
4236 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
4238 GError *error = nullptr;
4239 auto tz = static_cast<TZData *>(data);
4240 gchar *tmp_filename;
4241 gchar *timezone_bin;
4242 gchar *tmp_dir = nullptr;
4245 if (!g_cancellable_is_cancelled(tz->cancellable))
4247 generic_dialog_close(tz->gd);
4251 if (g_file_copy_finish(G_FILE(source_object), res, &error))
4253 tmp_filename = g_file_get_path(tz->tmp_g_file);
4254 fd = file_data_new_simple(tmp_filename);
4255 tmp_dir = open_archive(fd);
4259 timezone_bin = g_build_filename(tmp_dir, TIMEZONE_DATABASE_VERSION, TIMEZONE_DATABASE_FILE, NULL);
4260 if (isfile(timezone_bin))
4262 move_file(timezone_bin, tz->timezone_database_user);
4266 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GQ_ICON_DIALOG_WARNING, nullptr);
4269 g_free(timezone_bin);
4270 g_free(tmp_dir); // The folder in /tmp is deleted in exit_program_final()
4274 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GQ_ICON_DIALOG_WARNING, nullptr);
4276 g_free(tmp_filename);
4277 file_data_unref(fd);
4281 file_util_warning_dialog(_("Error: Timezone database download failed"), error->message, GQ_ICON_DIALOG_ERROR, nullptr);
4284 g_file_delete(tz->tmp_g_file, nullptr, &error);
4285 g_object_unref(tz->tmp_g_file);
4286 tz->tmp_g_file = nullptr;
4287 g_object_unref(tz->cancellable);
4288 g_object_unref(tz->timezone_database_gq);
4291 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
4293 auto tz = static_cast<TZData *>(data);
4295 if (!g_cancellable_is_cancelled(tz->cancellable))
4297 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), static_cast<gdouble>(current_num_bytes) / total_num_bytes);
4301 static void timezone_cancel_button_cb(GenericDialog *, gpointer data)
4303 auto tz = static_cast<TZData *>(data);
4305 g_cancellable_cancel(tz->cancellable);
4308 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
4310 auto tz = static_cast<TZData *>(data);
4311 GError *error = nullptr;
4312 GFileIOStream *io_stream;
4319 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
4323 file_util_warning_dialog(_("Timezone database download failed"), error->message, GQ_ICON_DIALOG_ERROR, nullptr);
4324 log_printf("Error: Download timezone database failed:\n%s", error->message);
4325 g_error_free(error);
4326 g_object_unref(tz->tmp_g_file);
4330 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE_WEB);
4332 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", nullptr, TRUE, timezone_cancel_button_cb, tz);
4334 generic_dialog_add_message(tz->gd, GQ_ICON_DIALOG_INFO, _("Downloading timezone database"), nullptr, FALSE);
4336 tz->progress = gtk_progress_bar_new();
4337 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
4338 gtk_widget_show(tz->progress);
4340 gtk_widget_show(tz->gd->dialog);
4341 tz->cancellable = g_cancellable_new();
4342 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);
4344 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
4347 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */