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"
26 #include "bar_keywords.h"
28 #include "cache_maint.h"
33 #include "filefilter.h"
34 #include "fullscreen.h"
36 #include "image-overlay.h"
37 #include "color-man.h"
39 #include "layout_config.h"
40 #include "layout_util.h"
44 #include "pixbuf_util.h"
46 #include "slideshow.h"
50 #include "ui_fileops.h"
52 #include "ui_spinner.h"
53 #include "ui_tabcomp.h"
54 #include "ui_utildlg.h"
56 #include "zonedetect.h"
67 #include <gspell/gspell.h>
70 #define EDITOR_NAME_MAX_LENGTH 32
71 #define EDITOR_COMMAND_MAX_LENGTH 1024
73 static void image_overlay_set_text_colours();
75 GtkWidget *keyword_text;
76 static void config_tab_keywords_save();
78 typedef struct _ThumbSize ThumbSize;
85 static ThumbSize thumb_size_list[] =
120 FILETYPES_COLUMN_ENABLED = 0,
121 FILETYPES_COLUMN_FILTER,
122 FILETYPES_COLUMN_DESCRIPTION,
123 FILETYPES_COLUMN_CLASS,
124 FILETYPES_COLUMN_WRITABLE,
125 FILETYPES_COLUMN_SIDECAR,
126 FILETYPES_COLUMN_COUNT
129 gchar *format_class_list[] = {
140 /* config memory values */
141 static ConfOptions *c_options = NULL;
148 static GtkWidget *configwindow = NULL;
149 static GtkListStore *filter_store = NULL;
150 static GtkTreeStore *accel_store = NULL;
152 static GtkWidget *safe_delete_path_entry;
154 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
155 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
156 static GtkWidget *color_profile_screen_file_entry;
157 static GtkWidget *external_preview_select_entry;
158 static GtkWidget *external_preview_extract_entry;
160 static GtkWidget *sidecar_ext_entry;
161 static GtkWidget *help_search_engine_entry;
164 #define CONFIG_WINDOW_DEF_WIDTH 700
165 #define CONFIG_WINDOW_DEF_HEIGHT 600
168 *-----------------------------------------------------------------------------
169 * option widget callbacks (private)
170 *-----------------------------------------------------------------------------
173 static void zoom_increment_cb(GtkWidget *spin, gpointer data)
175 c_options->image.zoom_increment = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
178 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer data)
180 gint mins_secs_tenths, delay;
182 mins_secs_tenths = c_options->slideshow.delay %
183 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
185 delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
186 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
189 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
190 SLIDESHOW_SUBSECOND_PRECISION;
193 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer data)
195 gint hours, secs_tenths, delay;
197 hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
198 secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
200 delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
201 (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
202 (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
204 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
205 SLIDESHOW_SUBSECOND_PRECISION;
208 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer data)
210 gint hours_mins, delay;
212 hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
214 delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
215 (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
216 (gdouble)(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
218 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
219 SLIDESHOW_SUBSECOND_PRECISION;
223 *-----------------------------------------------------------------------------
224 * sync program to config window routine (private)
225 *-----------------------------------------------------------------------------
228 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
234 buf = gtk_entry_get_text(GTK_ENTRY(entry));
235 if (buf && strlen(buf) > 0)
240 *option = g_strdup(buf);
245 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
247 gchar *accel_path, *accel;
249 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
251 if (accel_path && accel_path[0])
254 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
255 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
265 static void config_window_apply(void)
267 gboolean refresh = FALSE;
272 config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
274 if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
275 if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
276 if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
277 if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
278 if (options->file_sort.natural != c_options->file_sort.natural) refresh = TRUE;
279 if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
280 if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
282 options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
283 options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
284 options->file_ops.confirm_move_to_trash = c_options->file_ops.confirm_move_to_trash;
285 options->file_ops.use_system_trash = c_options->file_ops.use_system_trash;
286 options->file_ops.no_trash = c_options->file_ops.no_trash;
287 options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
288 options->tools_restore_state = c_options->tools_restore_state;
289 options->save_window_positions = c_options->save_window_positions;
290 options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
291 options->save_window_workspace = c_options->save_window_workspace;
292 options->save_dialog_window_positions = c_options->save_dialog_window_positions;
293 options->show_window_ids = c_options->show_window_ids;
294 options->image.scroll_reset_method = c_options->image.scroll_reset_method;
295 options->image.zoom_2pass = c_options->image.zoom_2pass;
296 options->image.fit_window_to_image = c_options->image.fit_window_to_image;
297 options->image.limit_window_size = c_options->image.limit_window_size;
298 options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
299 options->image.max_window_size = c_options->image.max_window_size;
300 options->image.limit_autofit_size = c_options->image.limit_autofit_size;
301 options->image.max_autofit_size = c_options->image.max_autofit_size;
302 options->image.max_enlargement_size = c_options->image.max_enlargement_size;
303 options->image.use_clutter_renderer = c_options->image.use_clutter_renderer;
304 options->image.tile_size = c_options->image.tile_size;
305 options->progressive_key_scrolling = c_options->progressive_key_scrolling;
306 options->keyboard_scroll_step = c_options->keyboard_scroll_step;
308 if (options->thumbnails.max_width != c_options->thumbnails.max_width
309 || options->thumbnails.max_height != c_options->thumbnails.max_height
310 || options->thumbnails.quality != c_options->thumbnails.quality)
312 thumb_format_changed = TRUE;
314 options->thumbnails.max_width = c_options->thumbnails.max_width;
315 options->thumbnails.max_height = c_options->thumbnails.max_height;
316 options->thumbnails.quality = c_options->thumbnails.quality;
318 options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
319 options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
320 options->thumbnails.use_exif = c_options->thumbnails.use_exif;
321 options->thumbnails.use_color_management = c_options->thumbnails.use_color_management;
322 options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
323 options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
324 // options->thumbnails.use_ft_metadata_small = c_options->thumbnails.use_ft_metadata_small;
325 options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
326 options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
327 options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
328 options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
329 options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
330 options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
332 options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
333 options->file_sort.natural = c_options->file_sort.natural;
334 options->file_filter.disable = c_options->file_filter.disable;
336 config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, NULL);
337 sidecar_ext_parse(options->sidecar.ext);
339 options->slideshow.random = c_options->slideshow.random;
340 options->slideshow.repeat = c_options->slideshow.repeat;
341 options->slideshow.delay = c_options->slideshow.delay;
343 options->mousewheel_scrolls = c_options->mousewheel_scrolls;
344 options->image_lm_click_nav = c_options->image_lm_click_nav;
345 options->image_l_click_archive = c_options->image_l_click_archive;
346 options->image_l_click_video = c_options->image_l_click_video;
347 options->image_l_click_video_editor = c_options->image_l_click_video_editor;
349 options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
351 options->image.tile_cache_max = c_options->image.tile_cache_max;
352 options->image.image_cache_max = c_options->image.image_cache_max;
354 options->image.zoom_quality = c_options->image.zoom_quality;
356 options->image.zoom_increment = c_options->image.zoom_increment;
358 options->image.zoom_style = c_options->image.zoom_style;
360 options->image.enable_read_ahead = c_options->image.enable_read_ahead;
363 if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
364 || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
365 || !gdk_color_equal(&options->image.border_color, &c_options->image.border_color))
367 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
368 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
369 options->image.border_color = c_options->image.border_color;
370 layout_colors_update();
371 view_window_colors_update();
374 options->image.alpha_color_1 = c_options->image.alpha_color_1;
375 options->image.alpha_color_2 = c_options->image.alpha_color_2;
377 options->fullscreen.screen = c_options->fullscreen.screen;
378 options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
379 options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
380 options->fullscreen.above = c_options->fullscreen.above;
381 if (c_options->image_overlay.template_string)
382 set_image_overlay_template_string(&options->image_overlay.template_string,
383 c_options->image_overlay.template_string);
384 if (c_options->image_overlay.font)
385 set_image_overlay_font_string(&options->image_overlay.font,
386 c_options->image_overlay.font);
387 options->image_overlay.text_red = c_options->image_overlay.text_red;
388 options->image_overlay.text_green = c_options->image_overlay.text_green;
389 options->image_overlay.text_blue = c_options->image_overlay.text_blue;
390 options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
391 options->image_overlay.background_red = c_options->image_overlay.background_red;
392 options->image_overlay.background_green = c_options->image_overlay.background_green;
393 options->image_overlay.background_blue = c_options->image_overlay.background_blue;
394 options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
395 options->update_on_time_change = c_options->update_on_time_change;
397 options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
398 options->rot_invariant_sim = c_options->rot_invariant_sim;
400 options->tree_descend_subdirs = c_options->tree_descend_subdirs;
402 options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
403 options->circular_selection_lists = c_options->circular_selection_lists;
405 options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
406 options->recent_folder_image_list_maxsize = c_options->recent_folder_image_list_maxsize;
407 options->dnd_icon_size = c_options->dnd_icon_size;
408 options->clipboard_selection = c_options->clipboard_selection;
409 options->dnd_default_action = c_options->dnd_default_action;
411 options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
412 options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
413 options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
414 options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
415 options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
416 options->metadata.confirm_write = c_options->metadata.confirm_write;
417 options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
418 options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
419 options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
420 options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
421 options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
422 options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
423 options->metadata.write_orientation = c_options->metadata.write_orientation;
424 options->metadata.check_spelling = c_options->metadata.check_spelling;
425 options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
426 (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
427 (c_options->stereo.tmp.flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
428 (c_options->stereo.tmp.mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
429 (c_options->stereo.tmp.flip_left ? PR_STEREO_FLIP_LEFT : 0) |
430 (c_options->stereo.tmp.swap ? PR_STEREO_SWAP : 0) |
431 (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
432 options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
433 (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
434 (c_options->stereo.tmp.fs_flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
435 (c_options->stereo.tmp.fs_mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
436 (c_options->stereo.tmp.fs_flip_left ? PR_STEREO_FLIP_LEFT : 0) |
437 (c_options->stereo.tmp.fs_swap ? PR_STEREO_SWAP : 0) |
438 (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
439 options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
440 options->stereo.fixed_w = c_options->stereo.fixed_w;
441 options->stereo.fixed_h = c_options->stereo.fixed_h;
442 options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
443 options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
444 options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
445 options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
447 options->info_keywords.height = c_options->info_keywords.height;
448 options->info_title.height = c_options->info_title.height;
449 options->info_comment.height = c_options->info_comment.height;
450 options->info_rating.height = c_options->info_rating.height;
452 options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
453 options->expand_menu_toolbar = c_options->expand_menu_toolbar;
455 options->marks_save = c_options->marks_save;
456 options->with_rename = c_options->with_rename;
457 options->collections_on_top = c_options->collections_on_top;
458 options->hide_window_in_fullscreen = c_options->hide_window_in_fullscreen;
459 config_entry_to_option(help_search_engine_entry, &options->help_search_engine, NULL);
461 options->external_preview.enable = c_options->external_preview.enable;
462 config_entry_to_option(external_preview_select_entry, &options->external_preview.select, NULL);
463 config_entry_to_option(external_preview_extract_entry, &options->external_preview.extract, NULL);
465 options->read_metadata_in_idle = c_options->read_metadata_in_idle;
467 options->star_rating.star = c_options->star_rating.star;
468 options->star_rating.rejected = c_options->star_rating.rejected;
470 options->threads.duplicates = c_options->threads.duplicates > 0 ? c_options->threads.duplicates : -1;
473 set_debug_level(debug_c);
477 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
479 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
480 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
482 config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
483 options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
484 if (options->color_profile.render_intent != c_options->color_profile.render_intent)
486 options->color_profile.render_intent = c_options->color_profile.render_intent;
491 options->mouse_button_8 = c_options->mouse_button_8;
492 options->mouse_button_9 = c_options->mouse_button_9;
494 options->override_disable_gpu = c_options->override_disable_gpu;
496 config_tab_keywords_save();
498 image_options_sync();
503 layout_refresh(NULL);
506 if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, NULL);
508 toolbar_apply(TOOLBAR_MAIN);
509 toolbar_apply(TOOLBAR_STATUS);
513 *-----------------------------------------------------------------------------
514 * config window main button callbacks (private)
515 *-----------------------------------------------------------------------------
518 static void config_window_close_cb(GtkWidget *widget, gpointer data)
520 gtk_widget_destroy(configwindow);
525 static void config_window_help_cb(GtkWidget *widget, gpointer data)
527 GtkWidget *notebook = data;
530 static gchar *html_section[] =
532 "GuideOptionsGeneral.html",
533 "GuideOptionsImage.html",
534 "GuideOptionsOSD.html",
535 "GuideOptionsWindow.html",
536 "GuideOptionsKeyboard.html",
537 "GuideOptionsFiltering.html",
538 "GuideOptionsMetadata.html",
539 "GuideOptionsKeywords.html",
540 "GuideOptionsColor.html",
541 "GuideOptionsStereo.html",
542 "GuideOptionsBehavior.html",
543 "GuideOptionsToolbar.html",
544 "GuideOptionsToolbar.html",
545 "GuideOptionsAdvanced.html"
548 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
549 help_window_show(html_section[i]);
552 static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpointer data)
554 config_window_close_cb(NULL, NULL);
558 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
561 GtkNotebook *notebook = data;
569 lw = layout_window_list->data;
571 window = gtk_widget_get_window(widget);
572 gdk_window_get_root_origin(window, &x, &y);
573 w = gdk_window_get_width(window);
574 h = gdk_window_get_height(window);
575 page_number = gtk_notebook_get_current_page(notebook);
577 lw->options.preferences_window.x = x;
578 lw->options.preferences_window.y = y;
579 lw->options.preferences_window.w = w;
580 lw->options.preferences_window.h = h;
581 lw->options.preferences_window.page_number = page_number;
583 config_window_apply();
584 layout_util_sync(lw);
585 save_options(options);
586 config_window_close_cb(NULL, NULL);
590 *-----------------------------------------------------------------------------
591 * config window setup (private)
592 *-----------------------------------------------------------------------------
595 static void quality_menu_cb(GtkWidget *combo, gpointer data)
599 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
603 *option = GDK_INTERP_NEAREST;
606 *option = GDK_INTERP_TILES;
609 *option = GDK_INTERP_BILINEAR;
614 static void dnd_default_action_selection_menu_cb(GtkWidget *combo, gpointer data)
618 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
622 *option = DND_ACTION_ASK;
625 *option = DND_ACTION_COPY;
628 *option = DND_ACTION_MOVE;
632 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
636 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
639 *option = CLIPBOARD_PRIMARY;
642 *option = CLIPBOARD_CLIPBOARD;
645 *option = CLIPBOARD_BOTH;
648 *option = CLIPBOARD_BOTH;
652 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
653 guint option, guint *option_c)
660 pref_table_label(table, column, row, text, 0.0);
662 combo = gtk_combo_box_text_new();
664 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
665 if (option == GDK_INTERP_NEAREST) current = 0;
666 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
667 if (option == GDK_INTERP_TILES) current = 1;
668 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear (best, but slowest)"));
669 if (option == GDK_INTERP_BILINEAR) current = 2;
671 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
673 g_signal_connect(G_OBJECT(combo), "changed",
674 G_CALLBACK(quality_menu_cb), option_c);
676 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
677 gtk_widget_show(combo);
680 static void add_dnd_default_action_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, DnDAction option, DnDAction *option_c)
687 pref_table_label(table, column, row, text, 0.0);
689 combo = gtk_combo_box_text_new();
691 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Ask"));
692 if (option == DND_ACTION_ASK) current = 0;
693 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Copy"));
694 if (option == DND_ACTION_COPY) current = 1;
695 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Move"));
696 if (option == DND_ACTION_MOVE) current = 2;
698 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
700 g_signal_connect(G_OBJECT(combo), "changed",
701 G_CALLBACK(dnd_default_action_selection_menu_cb), option_c);
703 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
704 gtk_widget_show(combo);
707 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
708 gint option, gint *option_c)
715 pref_table_label(table, column, row, text, 0.0);
717 combo = gtk_combo_box_text_new();
719 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Primary"));
720 if (option == CLIPBOARD_PRIMARY) current = 0;
721 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Clipboard"));
722 if (option == CLIPBOARD_CLIPBOARD) current = 1;
723 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Both"));
724 if (option == CLIPBOARD_BOTH) current = 2;
726 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
728 g_signal_connect(G_OBJECT(combo), "changed",
729 G_CALLBACK(clipboard_selection_menu_cb), option_c);
731 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
732 gtk_widget_show(combo);
735 static void zoom_style_selection_menu_cb(GtkWidget *combo, gpointer data)
739 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
742 *option = ZOOM_GEOMETRIC;
745 *option = ZOOM_ARITHMETIC;
748 *option = ZOOM_GEOMETRIC;
752 static void add_zoom_style_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, ZoomStyle option, ZoomStyle *option_c)
759 pref_table_label(table, column, row, text, 0.0);
761 combo = gtk_combo_box_text_new();
763 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Geometric"));
764 if (option == ZOOM_GEOMETRIC) current = 0;
765 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Arithmetic"));
766 if (option == ZOOM_ARITHMETIC) current = 1;
768 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
770 g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(zoom_style_selection_menu_cb), option_c);
772 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
773 gtk_widget_show(combo);
776 typedef struct _UseableMouseItems UseableMouseItems;
777 struct _UseableMouseItems
779 gchar *name; /* GtkActionEntry terminology */
784 static const UseableMouseItems useable_mouse_items[] = {
786 {"FirstImage", N_("First Image"), GTK_STOCK_GOTO_TOP},
787 {"PrevImage", N_("Previous Image"), GTK_STOCK_GO_UP},
788 {"NextImage", N_("Next Image"), GTK_STOCK_GO_DOWN},
789 {"LastImage", N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
790 {"Back", N_("Back"), GTK_STOCK_GO_BACK},
791 {"Forward", N_("Forward"), GTK_STOCK_GO_FORWARD},
792 {"Home", N_("Home"), GTK_STOCK_HOME},
793 {"Up", N_("Up"), GTK_STOCK_GO_UP},
794 {"FirstPage", N_("First page"), GTK_STOCK_MEDIA_PREVIOUS},
795 {"LastPage", N_("Last Page"), GTK_STOCK_MEDIA_NEXT},
796 {"NextPage", N_("Next page"), GTK_STOCK_MEDIA_FORWARD},
797 {"PrevPage", N_("Previous Page"), GTK_STOCK_MEDIA_REWIND},
798 {"NewWindow", N_("New _window"), GTK_STOCK_NEW},
799 {"NewCollection", N_("New collection"), GTK_STOCK_INDEX},
800 {"OpenCollection", N_("Open collection"), GTK_STOCK_OPEN},
801 {"Search", N_("Search"), GTK_STOCK_FIND},
802 {"FindDupes", N_("Find duplicates"), GTK_STOCK_FIND},
803 {"NewFolder", N_("New folder"),GTK_STOCK_DIRECTORY},
804 {"Copy", N_("Copy"), GTK_STOCK_COPY},
805 {"Move", N_("Move"), PIXBUF_INLINE_ICON_MOVE},
806 {"Rename", N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
807 {"Delete", N_("Delete"), GTK_STOCK_DELETE},
808 {"CloseWindow", N_("Close Window"), GTK_STOCK_CLOSE},
809 {"PanView", N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
810 {"SelectAll", N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
811 {"SelectNone", N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
812 {"SelectInvert", N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
813 {"ShowFileFilter", N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
814 {"RectangularSelection", N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
815 {"Print", N_("Print"), GTK_STOCK_PRINT},
816 {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
817 {"LayoutConfig", N_("Configure this window"), GTK_STOCK_PREFERENCES},
818 {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
819 {"RotateCW", N_("Rotate clockwise 90°"), PIXBUF_INLINE_ICON_CW},
820 {"RotateCCW", N_("Rotate counterclockwise 90°"), PIXBUF_INLINE_ICON_CCW},
821 {"Rotate180", N_("Rotate 180°"), PIXBUF_INLINE_ICON_180},
822 {"Mirror", N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
823 {"Flip", N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
824 {"AlterNone", N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
825 {"ZoomIn", N_("Zoom in"), GTK_STOCK_ZOOM_IN},
826 {"ZoomOut", N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
827 {"Zoom100", N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
828 {"ZoomFit", N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
829 {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
830 {"ZoomFillVert", N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
831 {"Zoom200", N_("Zoom 2:1"), GTK_STOCK_FILE},
832 {"Zoom300", N_("Zoom 3:1"), GTK_STOCK_FILE},
833 {"Zoom400", N_("Zoom 4:1"), GTK_STOCK_FILE},
834 {"Zoom50", N_("Zoom 1:2"), GTK_STOCK_FILE},
835 {"Zoom33", N_("Zoom1:3"), GTK_STOCK_FILE},
836 {"Zoom25", N_("Zoom 1:4"), GTK_STOCK_FILE},
837 {"ConnectZoomIn", N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
838 {"SplitPaneSync", N_("Split Pane Sync"), PIXBUF_INLINE_SPLIT_PANE_SYNC},
839 {"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
840 {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
841 {"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
842 {"SlideShowPause", N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
843 {"SlideShowFaster", N_("Slideshow Faster"), GTK_STOCK_FILE},
844 {"SlideShowSlower", N_("Slideshow Slower"), GTK_STOCK_FILE},
845 {"Refresh", N_("Refresh"), GTK_STOCK_REFRESH},
846 {"HelpContents", N_("Help"), GTK_STOCK_HELP},
847 {"ExifWin", N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
848 {"Thumbnails", N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
849 {"ShowMarks", N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
850 {"DrawRectangle", N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
851 {"FloatTools", N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
852 {"SBar", N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
853 {"SBarSort", N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
854 {"Quit", N_("Quit"), GTK_STOCK_QUIT},
858 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
860 gchar **option = data;
863 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
865 const UseableMouseItems *list = useable_mouse_items;
869 if (g_strcmp0(list->label, label) == 0)
877 *option = g_strdup(list->name);
881 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
882 gchar *option, gchar **option_c)
890 pref_table_label(table, column, row, text, 0.0);
892 combo = gtk_combo_box_text_new();
894 const UseableMouseItems *list = useable_mouse_items;
898 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
899 if (g_strcmp0(list->name, option) == 0)
907 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
909 g_signal_connect(G_OBJECT(combo), "changed",
910 G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
912 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
913 gtk_widget_show(combo);
916 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
920 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
923 if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
925 c_options->thumbnails.max_width = thumb_size_list[n].w;
926 c_options->thumbnails.max_height = thumb_size_list[n].h;
930 c_options->thumbnails.max_width = options->thumbnails.max_width;
931 c_options->thumbnails.max_height = options->thumbnails.max_height;
935 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
941 c_options->thumbnails.max_width = options->thumbnails.max_width;
942 c_options->thumbnails.max_height = options->thumbnails.max_height;
944 pref_table_label(table, column, row, text, 0.0);
946 combo = gtk_combo_box_text_new();
949 for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
954 w = thumb_size_list[i].w;
955 h = thumb_size_list[i].h;
957 buf = g_strdup_printf("%d x %d", w, h);
958 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
961 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
968 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
969 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
975 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
976 g_signal_connect(G_OBJECT(combo), "changed",
977 G_CALLBACK(thumb_size_menu_cb), NULL);
979 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
980 gtk_widget_show(combo);
983 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
987 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
991 *option = PR_STEREO_NONE;
994 *option = PR_STEREO_ANAGLYPH_RC;
997 *option = PR_STEREO_ANAGLYPH_GM;
1000 *option = PR_STEREO_ANAGLYPH_YB;
1003 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
1006 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
1009 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
1012 *option = PR_STEREO_ANAGLYPH_DB_RC;
1015 *option = PR_STEREO_ANAGLYPH_DB_GM;
1018 *option = PR_STEREO_ANAGLYPH_DB_YB;
1021 *option = PR_STEREO_HORIZ;
1024 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
1027 *option = PR_STEREO_VERT;
1030 *option = PR_STEREO_VERT | PR_STEREO_HALF;
1033 *option = PR_STEREO_FIXED;
1038 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1039 gint option, gint *option_c, gboolean add_fixed)
1046 pref_table_label(table, column, row, text, 0.0);
1048 combo = gtk_combo_box_text_new();
1050 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
1052 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
1053 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
1054 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
1055 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
1056 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
1057 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
1058 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
1059 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
1060 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
1061 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
1062 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
1063 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
1064 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
1065 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
1066 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
1067 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
1068 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
1069 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
1071 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
1072 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
1073 if (option & PR_STEREO_HORIZ)
1076 if (option & PR_STEREO_HALF) current = 11;
1079 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
1080 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
1081 if (option & PR_STEREO_VERT)
1084 if (option & PR_STEREO_HALF) current = 13;
1089 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
1090 if (option & PR_STEREO_FIXED) current = 14;
1093 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1095 g_signal_connect(G_OBJECT(combo), "changed",
1096 G_CALLBACK(stereo_mode_menu_cb), option_c);
1098 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1099 gtk_widget_show(combo);
1102 static void video_menu_cb(GtkWidget *combo, gpointer data)
1104 gchar **option = data;
1106 EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
1110 static void video_menu_populate(gpointer data, gpointer user_data)
1112 GtkWidget *combo = user_data;
1113 EditorDescription *ed = data;
1115 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1118 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1119 gchar *option, gchar **option_c)
1123 /* use lists since they are sorted */
1124 GList *eds = editor_list_get();
1128 pref_table_label(table, column, row, text, 0.0);
1130 combo = gtk_combo_box_text_new();
1131 g_list_foreach(eds,video_menu_populate,(gpointer)combo);
1132 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1134 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1136 g_signal_connect(G_OBJECT(combo), "changed",
1137 G_CALLBACK(video_menu_cb), option_c);
1139 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1140 gtk_widget_show(combo);
1143 static void filter_store_populate(void)
1147 if (!filter_store) return;
1149 gtk_list_store_clear(filter_store);
1151 work = filter_get_list();
1160 gtk_list_store_append(filter_store, &iter);
1161 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1165 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1166 gchar *new_text, gpointer data)
1168 GtkWidget *model = data;
1169 FilterEntry *fe = data;
1173 if (!new_text || strlen(new_text) < 1) return;
1175 tpath = gtk_tree_path_new_from_string(path_str);
1176 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1177 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1179 g_free(fe->extensions);
1180 fe->extensions = g_strdup(new_text);
1182 gtk_tree_path_free(tpath);
1186 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1187 gchar *new_text, gpointer data)
1189 GtkWidget *model = data;
1190 FilterEntry *fe = data;
1195 if (!new_text || !new_text[0]) return;
1197 tpath = gtk_tree_path_new_from_string(path_str);
1198 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1199 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1201 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1203 if (strcmp(new_text, _(format_class_list[i])) == 0)
1210 gtk_tree_path_free(tpath);
1214 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1215 gchar *new_text, gpointer data)
1217 GtkWidget *model = data;
1222 if (!new_text || !new_text[0]) return;
1224 tpath = gtk_tree_path_new_from_string(path_str);
1225 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1226 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1228 g_free(fe->description);
1229 fe->description = g_strdup(new_text);
1231 gtk_tree_path_free(tpath);
1234 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
1235 gchar *path_str, gpointer data)
1237 GtkWidget *model = data;
1242 tpath = gtk_tree_path_new_from_string(path_str);
1243 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1244 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1246 fe->enabled = !fe->enabled;
1248 gtk_tree_path_free(tpath);
1252 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
1253 gchar *path_str, gpointer data)
1255 GtkWidget *model = data;
1260 tpath = gtk_tree_path_new_from_string(path_str);
1261 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1262 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1264 fe->writable = !fe->writable;
1265 if (fe->writable) fe->allow_sidecar = FALSE;
1267 gtk_tree_path_free(tpath);
1271 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
1272 gchar *path_str, gpointer data)
1274 GtkWidget *model = data;
1279 tpath = gtk_tree_path_new_from_string(path_str);
1280 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1281 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1283 fe->allow_sidecar = !fe->allow_sidecar;
1284 if (fe->allow_sidecar) fe->writable = FALSE;
1286 gtk_tree_path_free(tpath);
1290 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1291 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1295 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1297 switch (GPOINTER_TO_INT(data))
1300 g_object_set(GTK_CELL_RENDERER(cell),
1301 "active", fe->enabled, NULL);
1304 g_object_set(GTK_CELL_RENDERER(cell),
1305 "text", fe->extensions, NULL);
1307 case FE_DESCRIPTION:
1308 g_object_set(GTK_CELL_RENDERER(cell),
1309 "text", fe->description, NULL);
1312 g_object_set(GTK_CELL_RENDERER(cell),
1313 "text", _(format_class_list[fe->file_class]), NULL);
1316 g_object_set(GTK_CELL_RENDERER(cell),
1317 "active", fe->writable, NULL);
1319 case FE_ALLOW_SIDECAR:
1320 g_object_set(GTK_CELL_RENDERER(cell),
1321 "active", fe->allow_sidecar, NULL);
1326 static gboolean filter_add_scroll(gpointer data)
1330 GtkCellRenderer *cell;
1331 GtkTreeViewColumn *column;
1334 GtkTreeModel *store;
1336 FilterEntry *filter;
1338 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1339 path = gtk_tree_path_new_from_indices(rows-1, -1);
1341 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1343 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1344 cell = g_list_last(list_cells)->data;
1346 store = gtk_tree_view_get_model(GTK_TREE_VIEW(data));
1347 valid = gtk_tree_model_get_iter_first(store, &iter);
1351 gtk_tree_model_get(store, &iter, 0, &filter, -1);
1353 if (g_strcmp0(filter->extensions, ".new") == 0)
1355 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
1359 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1362 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1363 path, column, FALSE, 0.0, 0.0 );
1364 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1365 path, column, cell, TRUE);
1367 gtk_tree_path_free(path);
1368 g_list_free(list_cells);
1373 static void filter_add_cb(GtkWidget *widget, gpointer data)
1375 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1376 filter_store_populate();
1378 g_idle_add((GSourceFunc)filter_add_scroll, data);
1381 static void filter_remove_cb(GtkWidget *widget, gpointer data)
1383 GtkWidget *filter_view = data;
1384 GtkTreeSelection *selection;
1388 if (!filter_store) return;
1389 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1390 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1391 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1394 filter_remove_entry(fe);
1396 filter_store_populate();
1399 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1403 GtkTreeViewColumn *column;
1405 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1406 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1407 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1409 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1413 gtk_tree_path_free(path);
1418 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
1421 filter_add_defaults();
1423 filter_store_populate();
1425 g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1428 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1430 /* no op, only so cancel button appears */
1433 static void filter_default_cb(GtkWidget *widget, gpointer data)
1437 gd = generic_dialog_new(_("Reset filters"),
1438 "reset_filter", widget, TRUE,
1439 dummy_cancel_cb, data);
1440 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1441 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1442 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1443 gtk_widget_show(gd->dialog);
1446 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1448 GtkWidget *frame = data;
1450 gtk_widget_set_sensitive(frame,
1451 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1454 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
1456 layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1459 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
1461 file_util_trash_clear();
1464 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
1468 gd = generic_dialog_new(_("Clear trash"),
1469 "clear_trash", widget, TRUE,
1470 dummy_cancel_cb, NULL);
1471 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1472 _("This will remove the trash contents."), FALSE);
1473 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1474 entry = gtk_entry_new();
1475 gtk_widget_set_can_focus(entry, FALSE);
1476 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1477 if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1478 gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1479 gtk_widget_show(entry);
1480 gtk_widget_show(gd->dialog);
1483 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
1485 GtkWidget *pTextView;
1486 GtkTextBuffer *pTextBuffer;
1490 pTextView = GTK_WIDGET(data);
1492 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1493 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1494 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1496 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1497 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1500 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
1502 GtkTextView *text_view = data;
1503 GtkTextBuffer *buffer;
1505 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1506 if (!configwindow) return;
1508 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1509 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1512 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1516 gd = generic_dialog_new(_("Reset image overlay template string"),
1517 "reset_image_overlay_template_string", widget, TRUE,
1518 dummy_cancel_cb, data);
1519 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1520 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1521 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1522 gtk_widget_show(gd->dialog);
1525 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
1527 help_window_show("GuideOptionsOSD.html");
1530 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer data)
1532 #if GTK_CHECK_VERSION(3,4,0)
1535 PangoFontDescription *font_desc;
1537 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1538 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1540 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1542 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1543 font = pango_font_description_to_string(font_desc);
1544 g_free(c_options->image_overlay.font);
1545 c_options->image_overlay.font = g_strdup(font);
1549 gtk_widget_destroy(dialog);
1553 font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
1554 c_options->image_overlay.font = g_strdup(font);
1558 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer data)
1561 #if GTK_CHECK_VERSION(3,4,0)
1564 dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1565 colour.red = options->image_overlay.text_red;
1566 colour.green = options->image_overlay.text_green;
1567 colour.blue = options->image_overlay.text_blue;
1568 colour.alpha = options->image_overlay.text_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.text_red = colour.red*255;
1576 c_options->image_overlay.text_green = colour.green*255;
1577 c_options->image_overlay.text_blue = colour.blue*255;
1578 c_options->image_overlay.text_alpha = colour.alpha*255;
1580 gtk_widget_destroy(dialog);
1583 GtkColorSelection *colorsel;
1585 dialog = gtk_color_selection_dialog_new("Image Overlay Text Colour");
1586 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1587 colour.red = options->image_overlay.text_red*257;
1588 colour.green = options->image_overlay.text_green*257;
1589 colour.blue = options->image_overlay.text_blue*257;
1590 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1591 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1592 gtk_color_selection_set_current_color(colorsel, &colour);
1593 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.text_alpha*257);
1595 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1597 gtk_color_selection_get_current_color(colorsel, &colour);
1598 c_options->image_overlay.text_red = colour.red/257;
1599 c_options->image_overlay.text_green = colour.green/257;
1600 c_options->image_overlay.text_blue = colour.blue/257;
1601 c_options->image_overlay.text_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1603 gtk_widget_destroy (dialog);
1608 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer data)
1611 #if GTK_CHECK_VERSION(3,4,0)
1614 dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1615 colour.red = options->image_overlay.background_red;
1616 colour.green = options->image_overlay.background_green;
1617 colour.blue = options->image_overlay.background_blue;
1618 colour.alpha = options->image_overlay.background_alpha;
1619 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1620 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1622 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1624 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1625 c_options->image_overlay.background_red = colour.red*255;
1626 c_options->image_overlay.background_green = colour.green*255;
1627 c_options->image_overlay.background_blue = colour.blue*255;
1628 c_options->image_overlay.background_alpha = colour.alpha*255;
1630 gtk_widget_destroy(dialog);
1633 GtkColorSelection *colorsel;
1635 dialog = gtk_color_selection_dialog_new("Image Overlay Background Colour");
1636 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1637 colour.red = options->image_overlay.background_red*257;
1638 colour.green = options->image_overlay.background_green*257;
1639 colour.blue = options->image_overlay.background_blue*257;
1640 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1641 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1642 gtk_color_selection_set_current_color(colorsel, &colour);
1643 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.background_alpha*257);
1645 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1647 gtk_color_selection_get_current_color(colorsel, &colour);
1648 c_options->image_overlay.background_red = colour.red/257;
1649 c_options->image_overlay.background_green = colour.green/257;
1650 c_options->image_overlay.background_blue = colour.blue/257;
1651 c_options->image_overlay.background_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1653 gtk_widget_destroy(dialog);
1657 static void accel_store_populate(void)
1660 GList *groups, *actions;
1662 const gchar *accel_path;
1666 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1668 gtk_tree_store_clear(accel_store);
1669 lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
1671 g_assert(lw && lw->ui_manager);
1672 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1675 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1678 action = GTK_ACTION(actions->data);
1679 accel_path = gtk_action_get_accel_path(action);
1680 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1682 gchar *label, *label2, *tooltip, *accel;
1683 g_object_get(action,
1684 "tooltip", &tooltip,
1688 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1694 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1698 gtk_tree_store_append(accel_store, &iter, NULL);
1699 gtk_tree_store_set(accel_store, &iter,
1702 AE_TOOLTIP, tooltip ? tooltip : "",
1703 AE_ACCEL, accel_path,
1711 actions = actions->next;
1714 groups = groups->next;
1718 static void accel_store_cleared_cb(GtkCellRendererAccel *accel, gchar *path_string, gpointer user_data)
1723 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1725 gchar *accel1 = data;
1730 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1732 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1733 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1735 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1737 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1738 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1747 static void accel_store_edited_cb(GtkCellRendererAccel *accel, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode, gpointer user_data)
1749 GtkTreeModel *model = (GtkTreeModel *)accel_store;
1753 GtkAccelKey old_key, key;
1754 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1756 gtk_tree_model_get_iter(model, &iter, path);
1757 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1759 /* test if the accelerator can be stored without conflicts*/
1760 gtk_accel_map_lookup_entry(accel_path, &old_key);
1762 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1763 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1764 gtk_accel_map_lookup_entry(accel_path, &key);
1766 /* restore the original for now, the key will be really changed when the changes are confirmed */
1767 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1769 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1770 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1772 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1773 gtk_tree_path_free(path);
1777 static gboolean accel_default_scroll(GtkTreeView *data)
1781 GtkTreeViewColumn *column;
1783 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1784 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1785 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1787 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1791 gtk_tree_path_free(path);
1796 static void accel_default_cb(GtkWidget *widget, gpointer data)
1798 accel_store_populate();
1800 g_idle_add((GSourceFunc)accel_default_scroll, data);
1803 void accel_remove_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1805 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1808 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1811 gchar *accel_path, *accel;
1813 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1814 gtk_accel_map_lookup_entry(accel_path, &key);
1815 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1817 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1819 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1824 static void accel_reset_cb(GtkWidget *widget, gpointer data)
1826 GtkTreeSelection *selection;
1828 if (!accel_store) return;
1829 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1830 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1835 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1839 GtkWidget *scrolled;
1840 GtkWidget *viewport;
1842 scrolled = gtk_scrolled_window_new(NULL, NULL);
1843 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1844 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1845 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1846 label = gtk_label_new(title);
1847 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1848 gtk_widget_show(scrolled);
1850 viewport = gtk_viewport_new(NULL, NULL);
1851 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1852 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1853 gtk_widget_show(viewport);
1855 vbox = gtk_vbox_new(FALSE, 0);
1856 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1857 gtk_widget_show(vbox);
1862 static void cache_standard_cb(GtkWidget *widget, gpointer data)
1864 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1866 c_options->thumbnails.spec_standard =TRUE;
1867 c_options->thumbnails.cache_into_dirs = FALSE;
1871 static void cache_geeqie_cb(GtkWidget *widget, gpointer data)
1873 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1875 c_options->thumbnails.spec_standard =FALSE;
1876 c_options->thumbnails.cache_into_dirs = FALSE;
1880 static void cache_local_cb(GtkWidget *widget, gpointer data)
1882 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1884 c_options->thumbnails.cache_into_dirs = TRUE;
1885 c_options->thumbnails.spec_standard =FALSE;
1889 static void help_search_engine_entry_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1890 GdkEvent *event, gpointer userdata)
1892 if (pos == GTK_ENTRY_ICON_PRIMARY)
1894 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1898 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1902 static void star_rating_star_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1903 GdkEvent *event, gpointer userdata)
1905 gchar *rating_symbol;
1907 if (pos == GTK_ENTRY_ICON_PRIMARY)
1909 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1910 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1911 g_free(rating_symbol);
1915 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1916 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1917 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1921 static void star_rating_rejected_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1922 GdkEvent *event, gpointer userdata)
1924 gchar *rating_symbol;
1926 if (pos == GTK_ENTRY_ICON_PRIMARY)
1928 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1929 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1930 g_free(rating_symbol);
1934 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1935 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1936 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1940 static guint star_rating_symbol_test(GtkWidget *widget, gpointer data)
1942 GtkContainer *hbox = data;
1943 GString *str = g_string_new(NULL);
1944 GtkEntry *hex_code_entry;
1945 gchar *hex_code_full;
1948 guint64 hex_value = 0;
1950 list = gtk_container_get_children(hbox);
1952 hex_code_entry = g_list_nth_data(list, 2);
1953 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1955 hex_code = g_strsplit(hex_code_full, "+", 2);
1956 if (hex_code[0] && hex_code[1])
1958 hex_value = strtoull(hex_code[1], NULL, 16);
1960 if (!hex_value || hex_value > 0x10FFFF)
1962 hex_value = 0x003F; // Unicode 'Question Mark'
1964 str = g_string_append_unichar(str, (gunichar)hex_value);
1965 gtk_label_set_text(g_list_nth_data(list, 1), str->str);
1967 g_strfreev(hex_code);
1968 g_string_free(str, TRUE);
1969 g_free(hex_code_full);
1974 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1976 guint64 star_symbol;
1978 star_symbol = star_rating_symbol_test(widget, data);
1979 c_options->star_rating.star = star_symbol;
1982 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1984 guint64 rejected_symbol;
1986 rejected_symbol = star_rating_symbol_test(widget, data);
1987 c_options->star_rating.rejected = rejected_symbol;
1990 /* general options tab */
1991 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1992 typedef struct _TZData TZData;
1996 GCancellable *cancellable;
1998 GtkWidget *progress;
2000 GFile *timezone_database_gq;
2001 gchar *timezone_database_user;
2004 static void config_tab_general(GtkWidget *notebook)
2009 GtkWidget *group_frame;
2010 GtkWidget *subgroup;
2012 GtkWidget *ct_button;
2015 gint hours, minutes, remainder;
2017 GtkWidget *star_rating_entry;
2019 gchar *rating_symbol;
2022 gchar *download_locn;
2023 GNetworkMonitor *net_mon;
2024 GSocketConnectable *tz_org;
2025 gboolean internet_available = FALSE;
2028 vbox = scrolled_notebook_page(notebook, _("General"));
2030 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
2032 table = pref_table_new(group, 2, 2, FALSE, FALSE);
2033 add_thumb_size_menu(table, 0, 0, _("Size:"));
2034 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
2036 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2037 pref_label_new(hbox, _("Custom size: "));
2038 pref_spin_new_int(hbox, _("Width:"), NULL, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
2039 pref_spin_new_int(hbox, _("Height:"), NULL, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
2041 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
2042 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
2044 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2045 pref_checkbox_link_sensitivity(ct_button, subgroup);
2047 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
2048 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
2049 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
2050 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2051 button = pref_radiobutton_new(group_frame, NULL, get_thumbnails_cache_dir(),
2052 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2053 G_CALLBACK(cache_geeqie_cb), NULL);
2055 group_frame = pref_frame_new(subgroup, TRUE,
2056 _("Store thumbnails local to image folder (non-standard)"),
2057 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2058 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
2059 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
2060 G_CALLBACK(cache_local_cb), NULL);
2062 group_frame = pref_frame_new(subgroup, TRUE,
2063 _("Use standard thumbnail style and cache, shared with other applications"),
2064 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2065 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
2066 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2067 G_CALLBACK(cache_standard_cb), NULL);
2069 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
2070 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
2072 pref_checkbox_new_int(group, _("Thumbnail color management"),
2073 options->thumbnails.use_color_management, &c_options->thumbnails.use_color_management);
2075 spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
2077 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
2078 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
2080 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
2081 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
2082 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
2084 // pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
2085 // options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
2088 pref_spacer(group, PREF_PAD_GROUP);
2090 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
2092 c_options->star_rating.star = options->star_rating.star;
2093 c_options->star_rating.rejected = options->star_rating.rejected;
2095 str = g_string_new(NULL);
2096 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2097 pref_label_new(hbox, _("Star character: "));
2098 str = g_string_append_unichar(str, options->star_rating.star);
2099 pref_label_new(hbox, g_strdup(str->str));
2100 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
2101 star_rating_entry = gtk_entry_new();
2102 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2103 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2104 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2105 gtk_widget_show(star_rating_entry);
2106 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2107 G_CALLBACK(star_rating_star_test_cb), hbox);
2108 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2109 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2110 gtk_widget_show(button);
2111 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."));
2112 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2113 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2114 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2115 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2116 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2117 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2118 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2119 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2120 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2121 G_CALLBACK(star_rating_star_icon_cb),
2124 g_string_free(str, TRUE);
2125 g_free(rating_symbol);
2127 str = g_string_new(NULL);
2128 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2129 pref_label_new(hbox, _("Rejected character: "));
2130 str = g_string_append_unichar(str, options->star_rating.rejected);
2131 pref_label_new(hbox, g_strdup(str->str));
2132 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2133 star_rating_entry = gtk_entry_new();
2134 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2135 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2136 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2137 gtk_widget_show(star_rating_entry);
2138 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2139 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2140 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2141 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2142 gtk_widget_show(button);
2143 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."));
2144 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2145 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2146 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2147 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2148 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2149 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2150 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2151 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2152 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2153 G_CALLBACK(star_rating_rejected_icon_cb),
2156 g_string_free(str, TRUE);
2157 g_free(rating_symbol);
2159 pref_spacer(group, PREF_PAD_GROUP);
2161 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2163 c_options->slideshow.delay = options->slideshow.delay;
2164 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2165 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2166 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2167 seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2168 SLIDESHOW_SUBSECOND_PRECISION;
2170 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2172 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2174 options->slideshow.delay ? hours : 0.0,
2175 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2176 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2177 spin = pref_spin_new(hbox, ":" , NULL,
2179 options->slideshow.delay ? minutes: 0.0,
2180 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2181 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2182 spin = pref_spin_new(hbox, ":", NULL,
2183 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2184 options->slideshow.delay ? seconds : 10.0,
2185 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2186 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2188 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2189 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2191 pref_spacer(group, PREF_PAD_GROUP);
2193 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2195 pref_spin_new_int(group, _("Decoded image cache size (MiB):"), NULL,
2196 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2197 pref_checkbox_new_int(group, _("Preload next image"),
2198 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2200 pref_checkbox_new_int(group, _("Refresh on file change"),
2201 options->update_on_time_change, &c_options->update_on_time_change);
2204 pref_spacer(group, PREF_PAD_GROUP);
2206 group = pref_group_new(vbox, FALSE, _("Expand menu and toolbar"), GTK_ORIENTATION_VERTICAL);
2208 pref_checkbox_new_int(group, _("Expand menu and toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2209 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2210 gtk_widget_set_tooltip_text(group, _("Expand the menu and toolbar to the full width of the window"));
2212 pref_spacer(group, PREF_PAD_GROUP);
2214 net_mon = g_network_monitor_get_default();
2215 tz_org = g_network_address_parse_uri(TIMEZONE_DATABASE_WEB, 80, NULL);
2218 internet_available = g_network_monitor_can_reach(net_mon, tz_org, NULL, NULL);
2219 g_object_unref(tz_org);
2222 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2223 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2225 if (!internet_available)
2227 gtk_widget_set_sensitive(group, FALSE);
2230 tz = g_new0(TZData, 1);
2232 path = path_from_utf8(TIMEZONE_DATABASE_WEB);
2233 basename = g_path_get_basename(path);
2234 tz->timezone_database_user = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
2238 if (isfile(tz->timezone_database_user))
2240 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2244 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2247 download_locn = g_strconcat(_("Download database from: "), TIMEZONE_DATABASE_WEB, NULL);
2248 pref_label_new(GTK_WIDGET(hbox), download_locn);
2249 g_free(download_locn);
2251 if (!internet_available)
2253 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"));
2257 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"));
2259 gtk_widget_show(button);
2261 pref_spacer(group, PREF_PAD_GROUP);
2263 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2265 help_search_engine_entry = gtk_entry_new();
2266 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2267 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2268 gtk_widget_show(help_search_engine_entry);
2270 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"));
2272 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2273 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2274 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2275 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2276 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2277 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2278 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2279 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2280 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2281 G_CALLBACK(help_search_engine_entry_icon_cb),
2282 help_search_engine_entry);
2286 static void config_tab_image(GtkWidget *notebook)
2291 GtkWidget *ct_button;
2292 GtkWidget *enlargement_button;
2295 GtkWidget *two_pass;
2297 GtkWidget *gpu_accel;
2300 vbox = scrolled_notebook_page(notebook, _("Image"));
2302 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2304 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2305 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2306 if (options->image.use_clutter_renderer && !options->disable_gpu)
2308 gtk_widget_set_sensitive(table, FALSE);
2312 gpu_accel = pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library (Requires restart)"),
2313 options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2314 if (options->disable_gpu && !options->override_disable_gpu)
2316 gtk_widget_set_sensitive(gpu_accel, FALSE);
2320 two_pass = pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2321 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2322 if (options->image.use_clutter_renderer && !options->disable_gpu)
2324 gtk_widget_set_sensitive(two_pass, FALSE);
2327 c_options->image.zoom_increment = options->image.zoom_increment;
2328 spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2329 0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2330 G_CALLBACK(zoom_increment_cb), NULL);
2331 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2333 c_options->image.zoom_style = options->image.zoom_style;
2334 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2335 add_zoom_style_selection_menu(table, 0, 0, _("Zoom style:"), options->image.zoom_style, &c_options->image.zoom_style);
2337 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2339 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2340 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2341 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2342 spin = pref_spin_new_int(hbox, NULL, NULL,
2344 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2345 pref_checkbox_link_sensitivity(enlargement_button, spin);
2346 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."));
2348 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2349 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2350 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2351 spin = pref_spin_new_int(hbox, NULL, NULL,
2353 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2354 pref_checkbox_link_sensitivity(ct_button, spin);
2355 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."));
2357 group = pref_group_new(vbox, FALSE, _("Tile size"), GTK_ORIENTATION_VERTICAL);
2358 gtk_widget_set_sensitive(group, !options->image.use_clutter_renderer);
2360 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2361 spin = pref_spin_new_int(hbox, _("Pixels"), _("(Requires restart)"),
2363 options->image.tile_size, &c_options->image.tile_size);
2364 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."));
2366 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2368 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2369 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2371 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2372 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2374 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2375 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2377 c_options->image.border_color = options->image.border_color;
2379 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2380 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2382 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2383 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2385 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2386 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2391 static void save_default_window_layout_cb(GtkWidget *widget, gpointer data)
2393 LayoutWindow *lw = NULL;
2394 gchar *default_path;
2397 /* Get current lw */
2400 tmp_id = lw->options.id;
2401 lw->options.id = g_strdup("lw_default");
2403 default_path = g_build_filename(get_rc_dir(), DEFAULT_WINDOW_LAYOUT, NULL);
2404 save_default_layout_options_to_file(default_path, options, lw);
2405 g_free(lw->options.id);
2406 lw->options.id = tmp_id;
2407 g_free(default_path);
2410 #if GTK_CHECK_VERSION(3,22,0)
2411 static gboolean popover_cb(gpointer data)
2413 GtkPopover *popover = data;
2415 gtk_popover_popdown(popover);
2420 static void default_layout_changed_cb(GtkWidget *button, GtkPopover *popover)
2422 gtk_popover_popup(popover);
2424 g_timeout_add(2000, popover_cb, popover);
2427 static GtkWidget *create_popover(GtkWidget *parent, GtkWidget *child, GtkPositionType pos)
2431 popover = gtk_popover_new(parent);
2432 gtk_popover_set_position(GTK_POPOVER (popover), pos);
2433 gtk_container_add (GTK_CONTAINER(popover), child);
2434 gtk_container_set_border_width(GTK_CONTAINER (popover), 6);
2435 gtk_widget_show (child);
2441 static void config_tab_windows(GtkWidget *notebook)
2446 GtkWidget *subgroup;
2448 GtkWidget *ct_button;
2451 vbox = scrolled_notebook_page(notebook, _("Windows"));
2453 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2455 ct_button = pref_checkbox_new_int(group, _("Remember session"),
2456 options->save_window_positions, &c_options->save_window_positions);
2458 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2459 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2460 pref_checkbox_link_sensitivity(ct_button, button);
2462 button = pref_checkbox_new_int(group, _("Remember window workspace"),
2463 options->save_window_workspace, &c_options->save_window_workspace);
2464 pref_checkbox_link_sensitivity(ct_button, button);
2466 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2467 options->tools_restore_state, &c_options->tools_restore_state);
2469 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2470 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2472 pref_checkbox_new_int(group, _("Show window IDs"),
2473 options->show_window_ids, &c_options->show_window_ids);
2475 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2476 pref_label_new(subgroup, _("Use current layout for default: "));
2477 button = pref_button_new(subgroup, NULL, _("Set"), FALSE, G_CALLBACK(save_default_window_layout_cb), NULL);
2479 #if GTK_CHECK_VERSION(3,22,0)
2482 popover = create_popover(button, gtk_label_new(_("Current window layout\nhas been set as default")), GTK_POS_TOP);
2483 gtk_popover_set_modal(GTK_POPOVER (popover), FALSE);
2484 g_signal_connect(button, "clicked", G_CALLBACK(default_layout_changed_cb), popover);
2487 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2489 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2490 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2492 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2493 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2494 options->image.limit_window_size, &c_options->image.limit_window_size);
2495 spin = pref_spin_new_int(hbox, NULL, NULL,
2497 options->image.max_window_size, &c_options->image.max_window_size);
2498 pref_checkbox_link_sensitivity(ct_button, spin);
2500 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2502 c_options->fullscreen.screen = options->fullscreen.screen;
2503 c_options->fullscreen.above = options->fullscreen.above;
2504 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2505 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2506 gtk_widget_show(hbox);
2508 pref_checkbox_new_int(group, _("Smooth image flip"),
2509 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2510 pref_checkbox_new_int(group, _("Disable screen saver"),
2511 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2514 #define PRE_FORMATTED_COLUMNS 5
2515 static void config_tab_osd(GtkWidget *notebook)
2521 GtkWidget *image_overlay_template_view;
2522 GtkWidget *scrolled;
2523 GtkWidget *scrolled_pre_formatted;
2524 GtkTextBuffer *buffer;
2526 GtkWidget *subgroup;
2528 vbox = scrolled_notebook_page(notebook, _("OSD"));
2530 image_overlay_template_view = gtk_text_view_new();
2532 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2534 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2536 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2537 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2538 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2539 gtk_widget_show(scrolled_pre_formatted);
2540 gtk_widget_show(subgroup);
2542 pref_line(group, PREF_PAD_GAP);
2544 pref_label_new(group, _("Image overlay template"));
2546 scrolled = gtk_scrolled_window_new(NULL, NULL);
2547 gtk_widget_set_size_request(scrolled, 200, 150);
2548 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2549 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2550 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2551 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2552 gtk_widget_show(scrolled);
2554 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2555 _("Extensive formatting options are shown in the Help file"));
2557 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2558 gtk_widget_show(image_overlay_template_view);
2560 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2562 #if GTK_CHECK_VERSION(3,4,0)
2563 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2564 G_CALLBACK(image_overlay_set_font_cb), notebook);
2566 button = gtk_font_button_new();
2567 gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
2568 gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
2569 g_signal_connect(G_OBJECT(button), "font-set",
2570 G_CALLBACK(image_overlay_set_font_cb),NULL);
2572 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2573 gtk_widget_show(button);
2575 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2576 G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2577 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2578 gtk_widget_show(button);
2580 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2581 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2582 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2583 gtk_widget_show(button);
2584 image_overlay_set_text_colours();
2586 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2587 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2588 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2589 gtk_widget_show(button);
2591 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2592 G_CALLBACK(image_overlay_help_cb), NULL);
2593 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2594 gtk_widget_show(button);
2596 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2597 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2598 g_signal_connect(G_OBJECT(buffer), "changed",
2599 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2601 pref_line(group, PREF_PAD_GAP);
2603 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2604 hbox = gtk_hbox_new(FALSE, 0);
2605 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2606 gtk_widget_show(hbox);
2607 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2608 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2609 gtk_widget_show(label);
2610 pref_spacer(group,TRUE);
2612 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2613 hbox = gtk_hbox_new(FALSE, 0);
2614 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2615 gtk_widget_show(hbox);
2616 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2617 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2618 gtk_widget_show(label);
2619 pref_spacer(group,TRUE);
2621 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2622 hbox = gtk_hbox_new(FALSE, 0);
2623 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2624 gtk_widget_show(hbox);
2625 label = gtk_label_new(_("%path:39%"));
2626 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2627 gtk_widget_show(label);
2628 pref_spacer(group,TRUE);
2630 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2631 hbox = gtk_hbox_new(FALSE, 0);
2632 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2633 gtk_widget_show(hbox);
2634 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%"));
2635 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2636 gtk_widget_show(label);
2637 pref_spacer(group,TRUE);
2639 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2640 hbox = gtk_hbox_new(FALSE, 0);
2641 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2642 gtk_widget_show(hbox);
2643 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2644 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2645 gtk_widget_show(label);
2648 static GtkTreeModel *create_class_model(void)
2650 GtkListStore *model;
2654 /* create list store */
2655 model = gtk_list_store_new(1, G_TYPE_STRING);
2656 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2658 gtk_list_store_append(model, &iter);
2659 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2661 return GTK_TREE_MODEL (model);
2666 static gint filter_table_sort_cb(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data)
2668 gint n = GPOINTER_TO_INT(data);
2670 FilterEntry *filter_a;
2671 FilterEntry *filter_b;
2673 gtk_tree_model_get(model, a, 0, &filter_a, -1);
2674 gtk_tree_model_get(model, b, 0, &filter_b, -1);
2678 case FILETYPES_COLUMN_ENABLED:
2680 ret = filter_a->enabled - filter_b->enabled;
2683 case FILETYPES_COLUMN_FILTER:
2685 ret = g_utf8_collate(filter_a->extensions, filter_b->extensions);
2688 case FILETYPES_COLUMN_DESCRIPTION:
2690 ret = g_utf8_collate(filter_a->description, filter_b->description);
2693 case FILETYPES_COLUMN_CLASS:
2695 ret = g_strcmp0(format_class_list[filter_a->file_class], format_class_list[filter_b->file_class]);
2698 case FILETYPES_COLUMN_WRITABLE:
2700 ret = filter_a->writable - filter_b->writable;
2703 case FILETYPES_COLUMN_SIDECAR:
2705 ret = filter_a->allow_sidecar - filter_b->allow_sidecar;
2709 g_return_val_if_reached(0);
2715 static gboolean search_function_cb(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer search_data)
2718 gboolean ret = TRUE;
2720 gtk_tree_model_get(model, iter, 0, &fe, -1);
2722 if (g_strstr_len(fe->extensions, -1, key))
2730 static void config_tab_files(GtkWidget *notebook)
2737 GtkWidget *ct_button;
2738 GtkWidget *scrolled;
2739 GtkWidget *filter_view;
2740 GtkCellRenderer *renderer;
2741 GtkTreeSelection *selection;
2742 GtkTreeViewColumn *column;
2744 vbox = scrolled_notebook_page(notebook, _("File Filters"));
2746 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2748 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2749 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2750 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2751 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2752 pref_checkbox_new_int(group, _("Case sensitive sort"),
2753 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2754 pref_checkbox_new_int(group, _("Natural sort order"),
2755 options->file_sort.natural, &c_options->file_sort.natural);
2756 pref_checkbox_new_int(group, _("Disable file extension checks"),
2757 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2759 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2760 options->file_filter.disable, &c_options->file_filter.disable);
2763 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2765 sidecar_ext_entry = gtk_entry_new();
2766 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2767 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2768 gtk_widget_show(sidecar_ext_entry);
2770 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2772 frame = pref_group_parent(group);
2773 g_signal_connect(G_OBJECT(ct_button), "toggled",
2774 G_CALLBACK(filter_disable_cb), frame);
2775 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2777 scrolled = gtk_scrolled_window_new(NULL, NULL);
2778 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2779 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2780 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2781 gtk_widget_show(scrolled);
2783 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2784 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2785 g_object_unref(filter_store);
2786 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2787 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2789 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2791 column = gtk_tree_view_column_new();
2792 gtk_tree_view_column_set_title(column, _("Enabled"));
2793 gtk_tree_view_column_set_resizable(column, TRUE);
2795 renderer = gtk_cell_renderer_toggle_new();
2796 g_signal_connect(G_OBJECT(renderer), "toggled",
2797 G_CALLBACK(filter_store_enable_cb), filter_store);
2798 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2799 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2800 GINT_TO_POINTER(FE_ENABLE), NULL);
2801 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_ENABLED, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_ENABLED), NULL);
2802 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_ENABLED);
2803 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2805 column = gtk_tree_view_column_new();
2806 gtk_tree_view_column_set_title(column, _("Filter"));
2807 gtk_tree_view_column_set_resizable(column, TRUE);
2808 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_FILTER, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_FILTER), NULL);
2809 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_FILTER);
2811 renderer = gtk_cell_renderer_text_new();
2812 g_signal_connect(G_OBJECT(renderer), "edited",
2813 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2814 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2815 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2816 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2817 GINT_TO_POINTER(FE_EXTENSION), NULL);
2818 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2820 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), TRUE);
2821 gtk_tree_view_set_search_column(GTK_TREE_VIEW(filter_view), FILETYPES_COLUMN_FILTER);
2822 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(filter_view), search_function_cb, NULL, NULL);
2824 column = gtk_tree_view_column_new();
2825 gtk_tree_view_column_set_title(column, _("Description"));
2826 gtk_tree_view_column_set_resizable(column, TRUE);
2827 gtk_tree_view_column_set_fixed_width(column, 200);
2828 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2830 renderer = gtk_cell_renderer_text_new();
2831 g_signal_connect(G_OBJECT(renderer), "edited",
2832 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2833 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2834 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2835 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2836 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2837 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2838 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_DESCRIPTION, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_DESCRIPTION), NULL);
2839 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_DESCRIPTION);
2841 column = gtk_tree_view_column_new();
2842 gtk_tree_view_column_set_title(column, _("Class"));
2843 gtk_tree_view_column_set_resizable(column, TRUE);
2844 renderer = gtk_cell_renderer_combo_new();
2845 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2846 "model", create_class_model(),
2851 g_signal_connect(G_OBJECT(renderer), "edited",
2852 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2853 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2854 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2855 GINT_TO_POINTER(FE_CLASS), NULL);
2856 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2857 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_CLASS, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_CLASS), NULL);
2858 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_CLASS);
2860 column = gtk_tree_view_column_new();
2861 gtk_tree_view_column_set_title(column, _("Writable"));
2862 gtk_tree_view_column_set_resizable(column, FALSE);
2863 renderer = gtk_cell_renderer_toggle_new();
2864 g_signal_connect(G_OBJECT(renderer), "toggled",
2865 G_CALLBACK(filter_store_writable_cb), filter_store);
2866 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2867 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2868 GINT_TO_POINTER(FE_WRITABLE), NULL);
2869 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2870 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_WRITABLE, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_WRITABLE), NULL);
2871 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_WRITABLE);
2873 column = gtk_tree_view_column_new();
2874 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2875 gtk_tree_view_column_set_resizable(column, FALSE);
2876 renderer = gtk_cell_renderer_toggle_new();
2877 g_signal_connect(G_OBJECT(renderer), "toggled",
2878 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2879 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2880 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2881 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2882 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2883 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_SIDECAR, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_SIDECAR), NULL);
2884 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_SIDECAR);
2886 filter_store_populate();
2887 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2888 gtk_widget_show(filter_view);
2890 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2892 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2893 G_CALLBACK(filter_default_cb), filter_view);
2894 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2895 gtk_widget_show(button);
2897 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2898 G_CALLBACK(filter_remove_cb), filter_view);
2899 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2900 gtk_widget_show(button);
2902 button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2903 G_CALLBACK(filter_add_cb), filter_view);
2904 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2905 gtk_widget_show(button);
2909 static void config_tab_metadata(GtkWidget *notebook)
2914 GtkWidget *ct_button;
2916 GtkWidget *tmp_widget;
2918 GtkWidget *text_label;
2920 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2923 group = pref_group_new(vbox, FALSE, _("Metadata writing sequence"), GTK_ORIENTATION_VERTICAL);
2925 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2927 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."));
2928 #if GTK_CHECK_VERSION(3,16,0)
2929 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2930 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2932 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2934 gtk_widget_set_tooltip_text(label, _("A flowchart of the sequence is shown in the Help file"));
2936 ct_button = pref_checkbox_new_int(group, "", options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2937 text_label = gtk_bin_get_child(GTK_BIN(ct_button));
2938 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"));
2939 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2941 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)"));
2942 gtk_widget_set_tooltip_markup(ct_button, markup);
2946 gtk_widget_set_sensitive(ct_button, FALSE);
2949 tmp_widget = pref_checkbox_new_int(group, "", options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2950 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2951 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)"));
2952 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2955 label = pref_label_new(group, "");
2956 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(), "/");
2957 gtk_label_set_markup (GTK_LABEL(label), markup);
2960 #if GTK_CHECK_VERSION(3,16,0)
2961 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2962 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2964 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2966 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2967 pref_spacer(group, PREF_PAD_GROUP);
2969 group = pref_group_new(vbox, FALSE, _("Step 1 Options:"), GTK_ORIENTATION_VERTICAL);
2971 gtk_widget_set_sensitive(group, FALSE);
2974 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2975 pref_checkbox_link_sensitivity(ct_button, hbox);
2977 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);
2978 gtk_widget_set_tooltip_text(tmp_widget, _("A simplified conversion list is in the Help file"));
2980 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);
2982 pref_checkbox_new_int(hbox, _("Ask before writing to image files"), options->metadata.confirm_write, &c_options->metadata.confirm_write);
2984 tmp_widget= pref_checkbox_new_int(hbox, "", options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2985 gtk_widget_set_tooltip_text(tmp_widget, _("This file naming convention is used by Darktable"));
2986 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2987 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", ")");
2988 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2991 pref_spacer(group, PREF_PAD_GROUP);
2993 group = pref_group_new(vbox, FALSE, _("Steps 2 and 3 Option:"), GTK_ORIENTATION_VERTICAL);
2995 gtk_widget_set_sensitive(group, FALSE);
2998 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);
3000 pref_spacer(group, PREF_PAD_GROUP);
3002 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
3003 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);
3004 gtk_widget_set_tooltip_text(tmp_widget, _("See the Help file for a list of the tags used"));
3006 tmp_widget = pref_checkbox_new_int(group, _("Permit Keywords to be case-sensitive"), options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
3007 gtk_widget_set_tooltip_text(tmp_widget, _("When selected, \"Place\" and \"place\" are two different keywords"));
3009 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"), options->metadata.write_orientation, &c_options->metadata.write_orientation);
3010 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"));
3013 gtk_widget_set_sensitive(ct_button, FALSE);
3016 pref_spacer(group, PREF_PAD_GROUP);
3018 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
3020 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"), options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
3022 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3023 pref_checkbox_link_sensitivity(ct_button, hbox);
3025 pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1, options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
3027 pref_checkbox_new_int(group, _("Write metadata on image change"), options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
3029 pref_checkbox_new_int(group, _("Write metadata on directory change"), options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
3031 pref_spacer(group, PREF_PAD_GROUP);
3034 #if GTK_CHECK_VERSION(3,20,0)
3035 group = pref_group_new(vbox, FALSE, _("Spelling checks"), GTK_ORIENTATION_VERTICAL);
3037 ct_button = pref_checkbox_new_int(group, _("Check spelling - Requires restart"), options->metadata.check_spelling, &c_options->metadata.check_spelling);
3038 gtk_widget_set_tooltip_text(ct_button, _("Spelling checks are performed on info sidebar panes Comment, Headline and Title"));
3042 pref_spacer(group, PREF_PAD_GROUP);
3044 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
3046 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"), options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
3047 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");
3052 typedef struct _KeywordFindData KeywordFindData;
3053 struct _KeywordFindData
3060 GtkWidget *button_close;
3061 GtkWidget *button_stop;
3062 GtkWidget *button_start;
3063 GtkWidget *progress;
3071 guint idle_id; /* event source id */
3074 #define KEYWORD_DIALOG_WIDTH 400
3076 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
3078 GList *list_d = NULL;
3079 GList *list_f = NULL;
3083 filelist_read(dir_fd, &list_f, &list_d);
3087 filelist_read(dir_fd, &list_f, NULL);
3090 list_f = filelist_filter(list_f, FALSE);
3091 list_d = filelist_filter(list_d, TRUE);
3093 kfd->list = g_list_concat(list_f, kfd->list);
3094 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
3097 static void keywords_find_reset(KeywordFindData *kfd)
3099 filelist_free(kfd->list);
3102 filelist_free(kfd->list_dir);
3103 kfd->list_dir = NULL;
3106 static void keywords_find_close_cb(GenericDialog *fd, gpointer data)
3108 KeywordFindData *kfd = data;
3110 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
3112 keywords_find_reset(kfd);
3113 generic_dialog_close(kfd->gd);
3117 static void keywords_find_finish(KeywordFindData *kfd)
3119 keywords_find_reset(kfd);
3121 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
3122 spinner_set_interval(kfd->spinner, -1);
3124 gtk_widget_set_sensitive(kfd->group, TRUE);
3125 gtk_widget_set_sensitive(kfd->button_start, TRUE);
3126 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3127 gtk_widget_set_sensitive(kfd->button_close, TRUE);
3130 static void keywords_find_stop_cb(GenericDialog *fd, gpointer data)
3132 KeywordFindData *kfd = data;
3134 g_idle_remove_by_data(kfd);
3136 keywords_find_finish(kfd);
3139 static gboolean keywords_find_file(gpointer data)
3141 KeywordFindData *kfd = data;
3143 GtkTextBuffer *buffer;
3151 fd = kfd->list->data;
3152 kfd->list = g_list_remove(kfd->list, fd);
3154 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
3155 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3159 gtk_text_buffer_get_end_iter(buffer, &iter);
3160 tmp = g_strconcat(keywords->data, "\n", NULL);
3161 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3163 keywords = keywords->next;
3166 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
3167 file_data_unref(fd);
3168 string_list_free(keywords);
3172 else if (kfd->list_dir)
3176 fd = kfd->list_dir->data;
3177 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
3179 keywords_find_folder(kfd, fd);
3181 file_data_unref(fd);
3186 keywords_find_finish(kfd);
3191 static void keywords_find_start_cb(GenericDialog *fd, gpointer data)
3193 KeywordFindData *kfd = data;
3196 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
3198 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
3199 parse_out_relatives(path);
3203 warning_dialog(_("Invalid folder"),
3204 _("The specified folder can not be found."),
3205 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
3211 gtk_widget_set_sensitive(kfd->group, FALSE);
3212 gtk_widget_set_sensitive(kfd->button_start, FALSE);
3213 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
3214 gtk_widget_set_sensitive(kfd->button_close, FALSE);
3215 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
3217 dir_fd = file_data_new_dir(path);
3218 keywords_find_folder(kfd, dir_fd);
3219 file_data_unref(dir_fd);
3220 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
3226 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
3228 KeywordFindData *kfd;
3232 kfd = g_new0(KeywordFindData, 1);
3234 kfd->gd = generic_dialog_new(_("Search for keywords"),
3235 "search_for_keywords",
3238 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
3239 kfd->gd->cancel_cb = keywords_find_close_cb;
3240 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
3241 keywords_find_close_cb, FALSE);
3242 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
3243 keywords_find_start_cb, FALSE);
3244 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
3245 keywords_find_stop_cb, FALSE);
3246 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3248 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
3250 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
3251 pref_spacer(hbox, PREF_PAD_INDENT);
3252 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
3254 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3255 pref_label_new(hbox, _("Folder:"));
3257 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
3258 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
3259 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
3260 gtk_widget_show(label);
3262 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
3264 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
3265 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3267 kfd->progress = gtk_entry_new();
3268 gtk_widget_set_can_focus(kfd->progress, FALSE);
3269 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
3270 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
3271 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
3272 gtk_widget_show(kfd->progress);
3274 kfd->spinner = spinner_new(NULL, -1);
3275 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
3276 gtk_widget_show(kfd->spinner);
3280 gtk_widget_show(kfd->gd->dialog);
3283 static void keywords_find_cb(GtkWidget *widget, gpointer data)
3285 const gchar *path = layout_get_path(NULL);
3287 if (!path || !*path) path = homedir();
3288 keywords_find_dialog(widget, path);
3291 static void config_tab_keywords_save()
3293 GtkTextIter start, end;
3294 GtkTextBuffer *buffer;
3295 GList *kw_list = NULL;
3301 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3302 gtk_text_buffer_get_bounds(buffer, &start, &end);
3304 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3306 kw_split = strtok(buffer_text, "\n");
3307 while (kw_split != NULL)
3313 if (g_strcmp0(work->data, kw_split) == 0)
3322 kw_list = g_list_append(kw_list, g_strdup(kw_split));
3324 kw_split = strtok(NULL, "\n");
3327 keyword_list_set(kw_list);
3329 string_list_free(kw_list);
3330 g_free(buffer_text);
3333 static void config_tab_keywords(GtkWidget *notebook)
3339 GtkWidget *scrolled;
3341 GtkTextBuffer *buffer;
3344 GspellTextView *gspell_view;
3347 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3349 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3351 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3353 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
3354 G_CALLBACK(keywords_find_cb), keyword_text);
3355 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
3358 keyword_text = gtk_text_view_new();
3359 gtk_widget_set_size_request(keyword_text, 20, 20);
3360 scrolled = gtk_scrolled_window_new(NULL, NULL);
3361 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3362 gtk_widget_show(scrolled);
3365 #if GTK_CHECK_VERSION(3,20,0)
3366 if (options->metadata.check_spelling)
3368 gspell_view = gspell_text_view_get_from_gtk_text_view(GTK_TEXT_VIEW(keyword_text));
3369 gspell_text_view_basic_setup(gspell_view);
3374 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
3375 gtk_widget_show(keyword_text);
3377 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3379 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3380 gtk_text_buffer_create_tag(buffer, "monospace",
3381 "family", "monospace", NULL);
3383 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3384 gtk_text_buffer_get_start_iter(buffer, &iter);
3385 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3388 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3390 GList *kwl = keyword_list_get();
3391 kwl = g_list_first(kwl);
3394 gtk_text_buffer_get_end_iter (buffer, &iter);
3395 tmp = g_strconcat(kwl->data, "\n", NULL);
3396 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3401 gtk_text_buffer_set_modified(buffer, FALSE);
3408 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3410 gint *option = data;
3412 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3416 *option = INTENT_PERCEPTUAL;
3419 *option = INTENT_RELATIVE_COLORIMETRIC;
3422 *option = INTENT_SATURATION;
3425 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3430 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3431 gint option, gint *option_c)
3438 pref_table_label(table, column, row, text, 0.0);
3440 combo = gtk_combo_box_text_new();
3442 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3443 if (option == INTENT_PERCEPTUAL) current = 0;
3444 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3445 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3446 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3447 if (option == INTENT_SATURATION) current = 2;
3448 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3449 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3451 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3453 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3455 g_signal_connect(G_OBJECT(combo), "changed",
3456 G_CALLBACK(intent_menu_cb), option_c);
3458 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
3459 gtk_widget_show(combo);
3463 static void config_tab_color(GtkWidget *notebook)
3472 vbox = scrolled_notebook_page(notebook, _("Color management"));
3474 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3476 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3479 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3480 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3482 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3483 pref_label_bold(label, TRUE, FALSE);
3485 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3486 pref_label_bold(label, TRUE, FALSE);
3488 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3489 pref_label_bold(label, TRUE, FALSE);
3491 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3496 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3497 pref_table_label(table, 0, i + 1, buf, 1.0);
3500 entry = gtk_entry_new();
3501 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3502 if (options->color_profile.input_name[i])
3504 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3506 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3507 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3508 gtk_widget_show(entry);
3509 color_profile_input_name_entry[i] = entry;
3511 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3512 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3513 gtk_widget_set_size_request(entry, 160, -1);
3514 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3515 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3516 gtk_widget_show(tabcomp);
3517 color_profile_input_file_entry[i] = entry;
3520 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3522 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3524 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3525 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3527 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3529 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3530 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3531 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3532 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3533 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3535 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3537 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3539 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3541 gtk_widget_show(tabcomp);
3544 /* advanced entry tab */
3545 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer data)
3547 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3549 c_options->file_ops.use_system_trash = FALSE;
3550 c_options->file_ops.no_trash = FALSE;
3554 static void use_system_trash_cb(GtkWidget *widget, gpointer data)
3556 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3558 c_options->file_ops.use_system_trash = TRUE;
3559 c_options->file_ops.no_trash = FALSE;
3563 static void use_no_cache_cb(GtkWidget *widget, gpointer data)
3565 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3567 c_options->file_ops.no_trash = TRUE;
3571 static void config_tab_behavior(GtkWidget *notebook)
3578 GtkWidget *ct_button;
3582 GtkWidget *with_rename;
3583 GtkWidget *collections_on_top;
3584 GtkWidget *hide_window_in_fullscreen;
3585 GtkWidget *checkbox;
3588 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3590 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3592 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3593 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3594 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3595 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3596 pref_checkbox_new_int(group, _("Enable Delete key"),
3597 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3599 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3600 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3602 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3603 pref_checkbox_link_sensitivity(ct_button, hbox);
3605 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3606 pref_label_new(hbox, _("Folder:"));
3608 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3609 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3610 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3611 gtk_widget_show(tabcomp);
3613 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3614 pref_checkbox_link_sensitivity(ct_button, hbox);
3616 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3617 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MiB"),
3618 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3619 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3620 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3621 G_CALLBACK(safe_delete_view_cb), NULL);
3622 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3623 gtk_widget_show(button);
3625 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3626 G_CALLBACK(safe_delete_clear_cb), NULL);
3627 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3629 c_options->file_ops.no_trash = options->file_ops.no_trash;
3630 c_options->file_ops.use_system_trash = options->file_ops.use_system_trash;
3632 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3633 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3635 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3636 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3638 gtk_widget_show(button);
3640 pref_spacer(group, PREF_PAD_GROUP);
3643 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3645 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3646 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3648 pref_checkbox_new_int(group, _("In place renaming"),
3649 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3651 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3652 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3654 tmp = pref_checkbox_new_int(group, _("Circular selection lists"),
3655 options->circular_selection_lists, &c_options->circular_selection_lists);
3656 gtk_widget_set_tooltip_text(tmp, _("Traverse selection lists in a circular manner"));
3658 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3659 options->marks_save, &c_options->marks_save);
3660 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3662 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3663 options->with_rename, &c_options->with_rename);
3664 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3666 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3667 options->collections_on_top, &c_options->collections_on_top);
3668 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3670 hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3671 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3672 gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice");
3674 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3675 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3677 tmp = pref_spin_new_int(group, _("Recent folder-image list maximum size"), NULL, 0, 50, 1, options->recent_folder_image_list_maxsize, &c_options->recent_folder_image_list_maxsize);
3678 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."));
3680 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3681 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3683 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3684 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3686 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3687 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3689 pref_spacer(group, PREF_PAD_GROUP);
3691 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3693 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3694 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3695 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3696 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3697 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3698 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3699 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3700 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3701 pref_checkbox_new_int(group, _("Open archive by left click on image"),
3702 options->image_l_click_archive, &c_options->image_l_click_archive);
3703 pref_checkbox_new_int(group, _("Play video by left click on image"),
3704 options->image_l_click_video, &c_options->image_l_click_video);
3705 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3706 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3708 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3709 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3710 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3711 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3712 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3714 pref_spacer(group, PREF_PAD_GROUP);
3716 group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3718 checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3719 options->override_disable_gpu, &c_options->override_disable_gpu);
3720 gtk_widget_set_tooltip_text(checkbox, "Contact the developers for usage");
3723 pref_spacer(group, PREF_PAD_GROUP);
3725 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3727 pref_spin_new_int(group, _("Debug level:"), NULL,
3728 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3730 pref_checkbox_new_int(group, _("Timer data"),
3731 options->log_window.timer_data, &c_options->log_window.timer_data);
3733 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3734 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3738 /* accelerators tab */
3739 static void config_tab_accelerators(GtkWidget *notebook)
3745 GtkWidget *scrolled;
3746 GtkWidget *accel_view;
3747 GtkCellRenderer *renderer;
3748 GtkTreeSelection *selection;
3749 GtkTreeViewColumn *column;
3751 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3753 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3755 scrolled = gtk_scrolled_window_new(NULL, NULL);
3756 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3757 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3758 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3759 gtk_widget_show(scrolled);
3761 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3763 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3764 g_object_unref(accel_store);
3765 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3766 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3768 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3770 renderer = gtk_cell_renderer_text_new();
3772 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3777 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3778 gtk_tree_view_column_set_resizable(column, TRUE);
3779 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3782 renderer = gtk_cell_renderer_accel_new();
3783 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3784 G_CALLBACK(accel_store_cleared_cb), accel_store);
3785 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3786 G_CALLBACK(accel_store_edited_cb), accel_store);
3789 g_object_set (renderer,
3791 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3794 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3799 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3800 gtk_tree_view_column_set_resizable(column, TRUE);
3801 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3803 renderer = gtk_cell_renderer_text_new();
3805 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3810 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3811 gtk_tree_view_column_set_resizable(column, TRUE);
3812 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3814 renderer = gtk_cell_renderer_text_new();
3816 column = gtk_tree_view_column_new_with_attributes("Accel",
3821 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3822 gtk_tree_view_column_set_resizable(column, TRUE);
3823 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3825 accel_store_populate();
3826 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3827 gtk_widget_show(accel_view);
3829 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3831 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3832 G_CALLBACK(accel_default_cb), accel_view);
3833 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3834 gtk_widget_show(button);
3836 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3837 G_CALLBACK(accel_reset_cb), accel_view);
3838 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3839 gtk_widget_show(button);
3842 /* toolbar main tab */
3843 static void config_tab_toolbar_main(GtkWidget *notebook)
3846 GtkWidget *toolbardata;
3849 lw = layout_window_list->data;
3851 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3853 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3854 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3855 gtk_widget_show(vbox);
3858 /* toolbar status tab */
3859 static void config_tab_toolbar_status(GtkWidget *notebook)
3862 GtkWidget *toolbardata;
3865 lw = layout_window_list->data;
3867 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3869 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3870 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3871 gtk_widget_show(vbox);
3875 static gint extension_sort_cb(gconstpointer a, gconstpointer b)
3877 return g_strcmp0((gchar *)a, (gchar *)b);
3880 static void config_tab_advanced(GtkWidget *notebook)
3884 GSList *formats_list;
3885 GList *extensions_list = NULL;
3888 GdkPixbufFormat *fm;
3890 GString *types_string = g_string_new(NULL);
3891 GtkWidget *types_string_label;
3892 GtkWidget *threads_string_label;
3893 GtkWidget *dupes_threads_spin;
3895 vbox = scrolled_notebook_page(notebook, _("Advanced"));
3896 group = pref_group_new(vbox, FALSE, _("External preview extraction"), GTK_ORIENTATION_VERTICAL);
3898 pref_checkbox_new_int(group, _("Use external preview extraction - Requires restart"), options->external_preview.enable, &c_options->external_preview.enable);
3900 pref_spacer(group, PREF_PAD_GROUP);
3902 formats_list = gdk_pixbuf_get_formats();
3904 while (formats_list)
3906 fm = formats_list->data;
3907 extensions = gdk_pixbuf_format_get_extensions(fm);
3910 while (extensions[i])
3912 extensions_list = g_list_insert_sorted(extensions_list, g_strdup(extensions[i]), extension_sort_cb);
3916 g_strfreev(extensions);
3917 formats_list = formats_list->next;
3920 while (extensions_list)
3922 if (types_string->len == 0)
3924 types_string = g_string_append(types_string, extensions_list->data);
3928 types_string = g_string_append(types_string, ", ");
3929 types_string = g_string_append(types_string, extensions_list->data);
3932 extensions_list = extensions_list->next;
3935 types_string = g_string_prepend(types_string, _("Usable file types:\n"));
3936 types_string_label = pref_label_new(group, types_string->str);
3937 gtk_label_set_line_wrap(GTK_LABEL(types_string_label), TRUE);
3939 pref_spacer(group, PREF_PAD_GROUP);
3941 group = pref_group_new(vbox, FALSE, _("File identification tool"), GTK_ORIENTATION_VERTICAL);
3942 external_preview_select_entry = gtk_entry_new();
3943 tabcomp = tab_completion_new(&external_preview_select_entry, options->external_preview.select, NULL, NULL, NULL, NULL);
3944 tab_completion_add_select_button(external_preview_select_entry, _("Select file identification tool"), FALSE);
3945 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3946 gtk_widget_show(tabcomp);
3948 group = pref_group_new(vbox, FALSE, _("Preview extraction tool"), GTK_ORIENTATION_VERTICAL);
3949 external_preview_extract_entry = gtk_entry_new();
3950 tabcomp = tab_completion_new(&external_preview_extract_entry, options->external_preview.extract, NULL, NULL, NULL, NULL);
3951 tab_completion_add_select_button(external_preview_extract_entry, _("Select preview extraction tool"), FALSE);
3952 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3953 gtk_widget_show(tabcomp);
3955 gtk_widget_show(vbox);
3957 g_slist_free(formats_list);
3958 string_list_free(extensions_list);
3959 g_string_free(types_string, TRUE);
3961 pref_spacer(group, PREF_PAD_GROUP);
3963 pref_line(vbox, PREF_PAD_SPACE);
3964 group = pref_group_new(vbox, FALSE, _("Thread pool limits"), GTK_ORIENTATION_VERTICAL);
3966 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.");
3967 gtk_label_set_line_wrap(GTK_LABEL(threads_string_label), TRUE);
3969 pref_spacer(vbox, PREF_PAD_GROUP);
3971 dupes_threads_spin = pref_spin_new_int(vbox, _("Duplicate check:"), _("max. threads"), 0, get_cpu_cores(), 1, options->threads.duplicates, &c_options->threads.duplicates);
3972 gtk_widget_set_tooltip_markup(dupes_threads_spin, _("Set to 0 for unlimited"));
3976 static void config_tab_stereo(GtkWidget *notebook)
3984 GtkWidget *fs_button;
3985 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3987 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3989 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3990 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3992 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3993 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3994 pref_checkbox_new_int(box, _("Mirror left image"),
3995 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3996 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3997 pref_checkbox_new_int(box, _("Flip left image"),
3998 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3999 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
4000 pref_checkbox_new_int(box, _("Mirror right image"),
4001 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
4002 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
4003 pref_checkbox_new_int(box, _("Flip right image"),
4004 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
4005 pref_checkbox_new_int(group, _("Swap left and right images"),
4006 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
4007 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
4008 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
4010 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
4011 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
4012 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
4013 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
4014 pref_checkbox_link_sensitivity(fs_button, box2);
4015 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
4016 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
4017 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
4018 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
4019 pref_checkbox_new_int(box, _("Mirror left image"),
4020 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
4021 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
4022 pref_checkbox_new_int(box, _("Flip left image"),
4023 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
4024 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
4025 pref_checkbox_new_int(box, _("Mirror right image"),
4026 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
4027 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
4028 pref_checkbox_new_int(box, _("Flip right image"),
4029 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
4030 pref_checkbox_new_int(box2, _("Swap left and right images"),
4031 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
4032 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
4033 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
4035 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
4036 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
4037 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
4038 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
4039 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
4040 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
4041 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
4042 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
4043 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
4044 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
4045 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
4046 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
4047 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
4048 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
4052 /* Main preferences window */
4053 static void config_window_create(LayoutWindow *lw)
4055 GtkWidget *win_vbox;
4057 GtkWidget *notebook;
4059 GtkWidget *ct_button;
4061 if (!c_options) c_options = init_options(NULL);
4063 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
4064 DEBUG_NAME(configwindow);
4065 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
4066 g_signal_connect(G_OBJECT(configwindow), "delete_event",
4067 G_CALLBACK(config_window_delete), NULL);
4068 if (options->save_dialog_window_positions)
4070 gtk_window_resize(GTK_WINDOW(configwindow), lw->options.preferences_window.w, lw->options.preferences_window.h);
4071 gtk_window_move(GTK_WINDOW(configwindow), lw->options.preferences_window.x, lw->options.preferences_window.y);
4075 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
4077 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
4078 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
4080 win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
4081 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
4082 gtk_widget_show(win_vbox);
4084 notebook = gtk_notebook_new();
4085 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
4086 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
4087 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
4089 config_tab_general(notebook);
4090 config_tab_image(notebook);
4091 config_tab_osd(notebook);
4092 config_tab_windows(notebook);
4093 config_tab_accelerators(notebook);
4094 config_tab_files(notebook);
4095 config_tab_metadata(notebook);
4096 config_tab_keywords(notebook);
4097 config_tab_color(notebook);
4098 config_tab_stereo(notebook);
4099 config_tab_behavior(notebook);
4100 config_tab_toolbar_main(notebook);
4101 config_tab_toolbar_status(notebook);
4102 config_tab_advanced(notebook);
4104 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), lw->options.preferences_window.page_number);
4106 hbox = gtk_hbutton_box_new();
4107 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
4108 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
4109 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
4110 gtk_widget_show(hbox);
4112 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
4113 G_CALLBACK(config_window_help_cb), notebook);
4114 gtk_container_add(GTK_CONTAINER(hbox), button);
4115 gtk_widget_set_can_default(button, TRUE);
4116 gtk_widget_show(button);
4118 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
4119 G_CALLBACK(config_window_ok_cb), notebook);
4120 gtk_container_add(GTK_CONTAINER(hbox), button);
4121 gtk_widget_set_can_default(button, TRUE);
4122 gtk_widget_grab_default(button);
4123 gtk_widget_show(button);
4127 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
4128 G_CALLBACK(config_window_close_cb), NULL);
4129 gtk_container_add(GTK_CONTAINER(hbox), button);
4130 gtk_widget_set_can_default(button, TRUE);
4131 gtk_widget_show(button);
4133 if (!generic_dialog_get_alternative_button_order(configwindow))
4135 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
4138 gtk_widget_show(notebook);
4140 gtk_widget_show(configwindow);
4144 *-----------------------------------------------------------------------------
4145 * config window show (public)
4146 *-----------------------------------------------------------------------------
4149 void show_config_window(LayoutWindow *lw)
4153 gtk_window_present(GTK_WINDOW(configwindow));
4157 config_window_create(lw);
4166 void show_about_window(LayoutWindow *lw)
4168 GdkPixbuf *pixbuf_logo;
4169 GdkPixbuf *pixbuf_icon;
4170 gchar *authors[1000];
4175 gchar *timezone_path;
4178 #define LINE_LENGTH 1000
4179 gchar line[LINE_LENGTH];
4181 copyright = g_string_new(NULL);
4182 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");
4184 timezone_path = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
4185 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
4187 cd = ZDOpenDatabase(timezone_path);
4190 copyright = g_string_append(copyright, ZDGetNotice(cd));
4194 log_printf("Error: Init of timezone database %s failed\n", timezone_path);
4196 ZDCloseDatabase(cd);
4198 g_free(timezone_path);
4201 path = g_build_filename(gq_helpdir, "AUTHORS", NULL);
4202 fp = fopen(path, "r");
4205 while(fgets(line, LINE_LENGTH, fp))
4207 /* get rid of ending \n from fgets */
4208 line[strlen(line) - 1] = '\0';
4209 authors[i_authors] = g_strdup(line);
4212 authors[i_authors] = NULL;
4217 comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
4218 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
4220 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
4221 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
4222 gtk_show_about_dialog(GTK_WINDOW(lw->window),
4223 "title", _("About Geeqie"),
4225 "program-name", GQ_APPNAME,
4227 "logo", pixbuf_logo,
4228 "icon", pixbuf_icon,
4229 "website", GQ_WEBSITE,
4230 "website-label", "Website",
4231 "comments", comment,
4233 "translator-credits", _("translator-credits"),
4234 "wrap-license", TRUE,
4235 "license", copyright->str,
4238 g_string_free(copyright, TRUE);
4241 while(n < i_authors)
4251 static void image_overlay_set_text_colours()
4253 c_options->image_overlay.text_red = options->image_overlay.text_red;
4254 c_options->image_overlay.text_green = options->image_overlay.text_green;
4255 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
4256 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
4257 c_options->image_overlay.background_red = options->image_overlay.background_red;
4258 c_options->image_overlay.background_green = options->image_overlay.background_green;
4259 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
4260 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
4264 *-----------------------------------------------------------------------------
4265 * timezone database routines
4266 *-----------------------------------------------------------------------------
4269 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
4271 GError *error = NULL;
4273 gchar *tmp_filename;
4274 gchar *timezone_bin;
4275 gchar *tmp_dir = NULL;
4278 if (!g_cancellable_is_cancelled(tz->cancellable))
4280 generic_dialog_close(tz->gd);
4284 if (g_file_copy_finish(G_FILE(source_object), res, &error))
4286 tmp_filename = g_file_get_path(tz->tmp_g_file);
4287 fd = file_data_new_simple(tmp_filename);
4288 tmp_dir = open_archive(fd);
4292 timezone_bin = g_build_filename(tmp_dir, TIMEZONE_DATABASE_VERSION, TIMEZONE_DATABASE_FILE, NULL);
4293 if (isfile(timezone_bin))
4295 move_file(timezone_bin, tz->timezone_database_user);
4299 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GTK_STOCK_DIALOG_WARNING, NULL);
4302 g_free(timezone_bin);
4303 g_free(tmp_dir); // The folder in /tmp is deleted in exit_program_final()
4307 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GTK_STOCK_DIALOG_WARNING, NULL);
4309 g_free(tmp_filename);
4310 file_data_unref(fd);
4314 file_util_warning_dialog(_("Error: Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4317 g_file_delete(tz->tmp_g_file, NULL, &error);
4318 g_object_unref(tz->tmp_g_file);
4319 tz->tmp_g_file = NULL;
4320 g_object_unref(tz->cancellable);
4321 g_object_unref(tz->timezone_database_gq);
4324 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
4328 if (!g_cancellable_is_cancelled(tz->cancellable))
4330 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
4334 static void timezone_cancel_button_cb(GenericDialog *gd, gpointer data)
4338 g_cancellable_cancel(tz->cancellable);
4341 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
4344 GError *error = NULL;
4345 GFileIOStream *io_stream;
4352 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
4356 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4357 log_printf("Error: Download timezone database failed:\n%s", error->message);
4358 g_error_free(error);
4359 g_object_unref(tz->tmp_g_file);
4363 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE_WEB);
4365 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
4367 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
4369 tz->progress = gtk_progress_bar_new();
4370 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
4371 gtk_widget_show(tz->progress);
4373 gtk_widget_show(tz->gd->dialog);
4374 tz->cancellable = g_cancellable_new();
4375 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);
4377 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
4380 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */