2 * Copyright (C) 2006 John Ellis
3 * Copyright (C) 2008 - 2016 The Geeqie Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "preferences.h"
25 #include "bar-keywords.h"
27 //~ #include "authors.h"
28 //~ #include "authors.c"
29 //~ #include "translators.h"
30 //~ #include "translators.c"
33 #include "filefilter.h"
34 #include "fullscreen.h"
36 #include "image-overlay.h"
37 #include "color-man.h"
39 #include "layout-util.h"
43 #include "pixbuf-util.h"
45 #include "slideshow.h"
49 #include "ui-fileops.h"
51 #include "ui-spinner.h"
52 #include "ui-tabcomp.h"
54 #include "zonedetect.h"
65 #include <gspell/gspell.h>
68 #define EDITOR_NAME_MAX_LENGTH 32
69 #define EDITOR_COMMAND_MAX_LENGTH 1024
71 static void image_overlay_set_text_colours();
73 GtkWidget *keyword_text;
74 static void config_tab_keywords_save();
76 typedef struct _ThumbSize ThumbSize;
83 static ThumbSize thumb_size_list[] =
118 FILETYPES_COLUMN_ENABLED = 0,
119 FILETYPES_COLUMN_FILTER,
120 FILETYPES_COLUMN_DESCRIPTION,
121 FILETYPES_COLUMN_CLASS,
122 FILETYPES_COLUMN_WRITABLE,
123 FILETYPES_COLUMN_SIDECAR,
124 FILETYPES_COLUMN_COUNT
127 const gchar *format_class_list[] = {
138 /* config memory values */
139 static ConfOptions *c_options = NULL;
146 static GtkWidget *configwindow = NULL;
147 static GtkListStore *filter_store = NULL;
148 static GtkTreeStore *accel_store = NULL;
150 static GtkWidget *safe_delete_path_entry;
152 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
153 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
154 static GtkWidget *color_profile_screen_file_entry;
155 static GtkWidget *external_preview_select_entry;
156 static GtkWidget *external_preview_extract_entry;
158 static GtkWidget *sidecar_ext_entry;
159 static GtkWidget *help_search_engine_entry;
162 #define CONFIG_WINDOW_DEF_WIDTH 700
163 #define CONFIG_WINDOW_DEF_HEIGHT 600
166 *-----------------------------------------------------------------------------
167 * option widget callbacks (private)
168 *-----------------------------------------------------------------------------
171 static void zoom_increment_cb(GtkWidget *spin, gpointer UNUSED(data))
173 c_options->image.zoom_increment = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
176 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer UNUSED(data))
178 gint mins_secs_tenths, delay;
180 mins_secs_tenths = c_options->slideshow.delay %
181 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
183 delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
184 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
187 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
188 SLIDESHOW_SUBSECOND_PRECISION;
191 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer UNUSED(data))
193 gint hours, secs_tenths, delay;
195 hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
196 secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
198 delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
199 (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
200 (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
202 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
203 SLIDESHOW_SUBSECOND_PRECISION;
206 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer UNUSED(data))
208 gint hours_mins, delay;
210 hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
212 delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
213 (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
214 (gdouble)(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
216 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
217 SLIDESHOW_SUBSECOND_PRECISION;
221 *-----------------------------------------------------------------------------
222 * sync program to config window routine (private)
223 *-----------------------------------------------------------------------------
226 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
232 buf = gtk_entry_get_text(GTK_ENTRY(entry));
233 if (buf && strlen(buf) > 0)
238 *option = g_strdup(buf);
243 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *UNUSED(path), GtkTreeIter *iter, gpointer UNUSED(data))
245 gchar *accel_path, *accel;
247 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
249 if (accel_path && accel_path[0])
252 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
253 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
263 static void config_window_apply(void)
265 gboolean refresh = FALSE;
270 config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
272 if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
273 if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
274 if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
275 if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
276 if (options->file_sort.natural != c_options->file_sort.natural) refresh = TRUE;
277 if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
278 if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
280 options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
281 options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
282 options->file_ops.confirm_move_to_trash = c_options->file_ops.confirm_move_to_trash;
283 options->file_ops.use_system_trash = c_options->file_ops.use_system_trash;
284 options->file_ops.no_trash = c_options->file_ops.no_trash;
285 options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
286 options->tools_restore_state = c_options->tools_restore_state;
287 options->save_window_positions = c_options->save_window_positions;
288 options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
289 options->save_window_workspace = c_options->save_window_workspace;
290 options->save_dialog_window_positions = c_options->save_dialog_window_positions;
291 options->show_window_ids = c_options->show_window_ids;
292 options->image.scroll_reset_method = c_options->image.scroll_reset_method;
293 options->image.zoom_2pass = c_options->image.zoom_2pass;
294 options->image.fit_window_to_image = c_options->image.fit_window_to_image;
295 options->image.limit_window_size = c_options->image.limit_window_size;
296 options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
297 options->image.max_window_size = c_options->image.max_window_size;
298 options->image.limit_autofit_size = c_options->image.limit_autofit_size;
299 options->image.max_autofit_size = c_options->image.max_autofit_size;
300 options->image.max_enlargement_size = c_options->image.max_enlargement_size;
301 //~ options->image.use_clutter_renderer = c_options->image.use_clutter_renderer;
302 options->image.tile_size = c_options->image.tile_size;
303 options->progressive_key_scrolling = c_options->progressive_key_scrolling;
304 options->keyboard_scroll_step = c_options->keyboard_scroll_step;
306 if (options->thumbnails.max_width != c_options->thumbnails.max_width
307 || options->thumbnails.max_height != c_options->thumbnails.max_height
308 || options->thumbnails.quality != c_options->thumbnails.quality)
310 thumb_format_changed = TRUE;
312 options->thumbnails.max_width = c_options->thumbnails.max_width;
313 options->thumbnails.max_height = c_options->thumbnails.max_height;
314 options->thumbnails.quality = c_options->thumbnails.quality;
316 options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
317 options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
318 options->thumbnails.use_exif = c_options->thumbnails.use_exif;
319 options->thumbnails.use_color_management = c_options->thumbnails.use_color_management;
320 options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
321 options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
322 // options->thumbnails.use_ft_metadata_small = c_options->thumbnails.use_ft_metadata_small;
323 options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
324 options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
325 options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
326 options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
327 options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
328 options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
330 options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
331 options->file_sort.natural = c_options->file_sort.natural;
332 options->file_filter.disable = c_options->file_filter.disable;
334 config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, NULL);
335 sidecar_ext_parse(options->sidecar.ext);
337 options->slideshow.random = c_options->slideshow.random;
338 options->slideshow.repeat = c_options->slideshow.repeat;
339 options->slideshow.delay = c_options->slideshow.delay;
341 options->mousewheel_scrolls = c_options->mousewheel_scrolls;
342 options->image_lm_click_nav = c_options->image_lm_click_nav;
343 options->image_l_click_archive = c_options->image_l_click_archive;
344 options->image_l_click_video = c_options->image_l_click_video;
345 options->image_l_click_video_editor = c_options->image_l_click_video_editor;
347 options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
349 options->image.tile_cache_max = c_options->image.tile_cache_max;
350 options->image.image_cache_max = c_options->image.image_cache_max;
352 options->image.zoom_quality = c_options->image.zoom_quality;
354 options->image.zoom_increment = c_options->image.zoom_increment;
356 options->image.zoom_style = c_options->image.zoom_style;
358 options->image.enable_read_ahead = c_options->image.enable_read_ahead;
360 options->appimage_notifications = c_options->appimage_notifications;
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 *UNUSED(widget), gpointer UNUSED(data))
520 gtk_widget_destroy(configwindow);
525 static void config_window_help_cb(GtkWidget *UNUSED(widget), gpointer data)
527 GtkWidget *notebook = static_cast<GtkWidget *>(data);
530 static const 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 *UNUSED(widget), GdkEventAny *UNUSED(event), gpointer UNUSED(data))
554 config_window_close_cb(NULL, NULL);
558 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
561 GtkNotebook *notebook = static_cast<GtkNotebook *>(data);
569 lw = static_cast<LayoutWindow *>(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)
597 gint *option = static_cast<gint *>(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)
616 gint *option = static_cast<gint *>(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)
634 gint *option = static_cast<gint *>(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, static_cast<GtkAttachOptions>(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, static_cast<GtkAttachOptions>(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, static_cast<GtkAttachOptions>(0), 0, 0);
732 gtk_widget_show(combo);
735 static void zoom_style_selection_menu_cb(GtkWidget *combo, gpointer data)
737 gint *option = static_cast<gint *>(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, static_cast<GtkAttachOptions>(0), 0, 0);
773 gtk_widget_show(combo);
776 typedef struct _UseableMouseItems UseableMouseItems;
777 struct _UseableMouseItems
779 const gchar *name; /* GtkActionEntry terminology */
781 const gchar *stock_id;
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 = static_cast<gchar **>(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, static_cast<GtkAttachOptions>(0), 0, 0);
913 gtk_widget_show(combo);
916 static void thumb_size_menu_cb(GtkWidget *combo, gpointer UNUSED(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, static_cast<GtkAttachOptions>(0), 0, 0);
980 gtk_widget_show(combo);
983 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
985 gint *option = static_cast<gint *>(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, static_cast<GtkAttachOptions>(0), 0, 0);
1099 gtk_widget_show(combo);
1102 static void video_menu_cb(GtkWidget *combo, gpointer data)
1104 gchar **option = static_cast<gchar **>(data);
1106 EditorDescription *ed = static_cast<EditorDescription *>(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 = static_cast<GtkWidget *>(user_data);
1113 EditorDescription *ed = static_cast<EditorDescription *>(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, static_cast<GtkAttachOptions>(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();
1157 fe = static_cast<FilterEntry *>(work->data);
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 *UNUSED(cell), gchar *path_str,
1166 gchar *new_text, gpointer data)
1168 GtkWidget *model = static_cast<GtkWidget *>(data);
1169 FilterEntry *fe = static_cast<FilterEntry *>(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 *UNUSED(cell), gchar *path_str,
1187 gchar *new_text, gpointer data)
1189 GtkWidget *model = static_cast<GtkWidget *>(data);
1190 FilterEntry *fe = static_cast<FilterEntry *>(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)
1205 fe->file_class = static_cast<FileFormatClass>(i);
1210 gtk_tree_path_free(tpath);
1214 static void filter_store_desc_edit_cb(GtkCellRendererText *UNUSED(cell), gchar *path_str,
1215 gchar *new_text, gpointer data)
1217 GtkWidget *model = static_cast<GtkWidget *>(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 *UNUSED(renderer),
1235 gchar *path_str, gpointer data)
1237 GtkWidget *model = static_cast<GtkWidget *>(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 *UNUSED(renderer),
1253 gchar *path_str, gpointer data)
1255 GtkWidget *model = static_cast<GtkWidget *>(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 *UNUSED(renderer),
1272 gchar *path_str, gpointer data)
1274 GtkWidget *model = static_cast<GtkWidget *>(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 *UNUSED(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 = static_cast<GtkCellRenderer *>(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 *UNUSED(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 *UNUSED(widget), gpointer data)
1383 GtkWidget *filter_view = static_cast<GtkWidget *>(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 UNUSED(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 *UNUSED(gd), gpointer UNUSED(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 = static_cast<GtkWidget *>(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 *UNUSED(widget), gpointer UNUSED(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 *UNUSED(gd), gpointer UNUSED(data))
1461 file_util_trash_clear();
1464 static void safe_delete_clear_cb(GtkWidget *widget, gpointer UNUSED(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 *UNUSED(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 *UNUSED(gd), gpointer data)
1502 GtkTextView *text_view = static_cast<GtkTextView *>(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 *UNUSED(widget), gpointer UNUSED(data))
1527 help_window_show("GuideOptionsOSD.html");
1530 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer UNUSED(data))
1534 PangoFontDescription *font_desc;
1536 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1537 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1539 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1541 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1542 font = pango_font_description_to_string(font_desc);
1543 g_free(c_options->image_overlay.font);
1544 c_options->image_overlay.font = g_strdup(font);
1548 gtk_widget_destroy(dialog);
1551 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer UNUSED(data))
1556 dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1557 colour.red = options->image_overlay.text_red;
1558 colour.green = options->image_overlay.text_green;
1559 colour.blue = options->image_overlay.text_blue;
1560 colour.alpha = options->image_overlay.text_alpha;
1561 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1562 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1564 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1566 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1567 c_options->image_overlay.text_red = colour.red*255;
1568 c_options->image_overlay.text_green = colour.green*255;
1569 c_options->image_overlay.text_blue = colour.blue*255;
1570 c_options->image_overlay.text_alpha = colour.alpha*255;
1572 gtk_widget_destroy(dialog);
1576 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer UNUSED(data))
1581 dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1582 colour.red = options->image_overlay.background_red;
1583 colour.green = options->image_overlay.background_green;
1584 colour.blue = options->image_overlay.background_blue;
1585 colour.alpha = options->image_overlay.background_alpha;
1586 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1587 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1589 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1591 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1592 c_options->image_overlay.background_red = colour.red*255;
1593 c_options->image_overlay.background_green = colour.green*255;
1594 c_options->image_overlay.background_blue = colour.blue*255;
1595 c_options->image_overlay.background_alpha = colour.alpha*255;
1597 gtk_widget_destroy(dialog);
1600 static void accel_store_populate(void)
1603 GList *groups, *actions;
1605 const gchar *accel_path;
1609 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1611 gtk_tree_store_clear(accel_store);
1612 lw = static_cast<LayoutWindow *>(layout_window_list->data); /* get the actions from the first window, it should not matter, they should be the same in all windows */
1614 g_assert(lw && lw->ui_manager);
1615 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1618 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1621 action = GTK_ACTION(actions->data);
1622 accel_path = gtk_action_get_accel_path(action);
1623 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1625 gchar *label, *label2, *tooltip, *accel;
1626 g_object_get(action,
1627 "tooltip", &tooltip,
1631 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1637 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1641 gtk_tree_store_append(accel_store, &iter, NULL);
1642 gtk_tree_store_set(accel_store, &iter,
1645 AE_TOOLTIP, tooltip ? tooltip : "",
1646 AE_ACCEL, accel_path,
1654 actions = actions->next;
1657 groups = groups->next;
1661 static void accel_store_cleared_cb(GtkCellRendererAccel *UNUSED(accel), gchar *UNUSED(path_string), gpointer UNUSED(user_data))
1666 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *UNUSED(path), GtkTreeIter *iter, gpointer data)
1668 gchar *accel1 = static_cast<gchar *>(data);
1673 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1675 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1676 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1678 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1680 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1681 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1690 static void accel_store_edited_cb(GtkCellRendererAccel *UNUSED(accel), gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint UNUSED(hardware_keycode), gpointer UNUSED(user_data))
1692 GtkTreeModel *model = (GtkTreeModel *)accel_store;
1696 GtkAccelKey old_key, key;
1697 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1699 gtk_tree_model_get_iter(model, &iter, path);
1700 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1702 /* test if the accelerator can be stored without conflicts*/
1703 gtk_accel_map_lookup_entry(accel_path, &old_key);
1705 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1706 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1707 gtk_accel_map_lookup_entry(accel_path, &key);
1709 /* restore the original for now, the key will be really changed when the changes are confirmed */
1710 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1712 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1713 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1715 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1716 gtk_tree_path_free(path);
1720 static gboolean accel_default_scroll(GtkTreeView *data)
1724 GtkTreeViewColumn *column;
1726 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1727 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1728 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1730 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1734 gtk_tree_path_free(path);
1739 static void accel_default_cb(GtkWidget *UNUSED(widget), gpointer data)
1741 accel_store_populate();
1743 g_idle_add((GSourceFunc)accel_default_scroll, data);
1746 //void accel_remove_selection(GtkTreeModel *UNUSED(model), GtkTreePath *UNUSED(path), GtkTreeIter *iter, gpointer UNUSED(data))
1748 //gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1751 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *UNUSED(path), GtkTreeIter *iter, gpointer UNUSED(data))
1754 gchar *accel_path, *accel;
1756 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1757 gtk_accel_map_lookup_entry(accel_path, &key);
1758 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1760 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1762 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1767 static void accel_reset_cb(GtkWidget *UNUSED(widget), gpointer data)
1769 GtkTreeSelection *selection;
1771 if (!accel_store) return;
1772 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1773 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1778 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1782 GtkWidget *scrolled;
1783 GtkWidget *viewport;
1785 scrolled = gtk_scrolled_window_new(NULL, NULL);
1786 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1787 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1788 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1789 label = gtk_label_new(title);
1790 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1791 gtk_widget_show(scrolled);
1793 viewport = gtk_viewport_new(NULL, NULL);
1794 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1795 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1796 gtk_widget_show(viewport);
1798 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
1799 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1800 gtk_widget_show(vbox);
1805 static void cache_standard_cb(GtkWidget *widget, gpointer UNUSED(data))
1807 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1809 c_options->thumbnails.spec_standard =TRUE;
1810 c_options->thumbnails.cache_into_dirs = FALSE;
1814 static void cache_geeqie_cb(GtkWidget *widget, gpointer UNUSED(data))
1816 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1818 c_options->thumbnails.spec_standard =FALSE;
1819 c_options->thumbnails.cache_into_dirs = FALSE;
1823 static void cache_local_cb(GtkWidget *widget, gpointer UNUSED(data))
1825 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1827 c_options->thumbnails.cache_into_dirs = TRUE;
1828 c_options->thumbnails.spec_standard =FALSE;
1832 static void help_search_engine_entry_icon_cb(GtkEntry *UNUSED(entry), GtkEntryIconPosition pos,
1833 GdkEvent *UNUSED(event), gpointer userdata)
1835 if (pos == GTK_ENTRY_ICON_PRIMARY)
1837 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1841 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1845 static void star_rating_star_icon_cb(GtkEntry *UNUSED(entry), GtkEntryIconPosition pos,
1846 GdkEvent *UNUSED(event), gpointer userdata)
1848 gchar *rating_symbol;
1850 if (pos == GTK_ENTRY_ICON_PRIMARY)
1852 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1853 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1854 g_free(rating_symbol);
1858 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1859 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1860 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1864 static void star_rating_rejected_icon_cb(GtkEntry *UNUSED(entry), GtkEntryIconPosition pos,
1865 GdkEvent *UNUSED(event), gpointer userdata)
1867 gchar *rating_symbol;
1869 if (pos == GTK_ENTRY_ICON_PRIMARY)
1871 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1872 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1873 g_free(rating_symbol);
1877 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1878 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1879 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1883 static guint star_rating_symbol_test(GtkWidget *UNUSED(widget), gpointer data)
1885 GtkContainer *hbox = static_cast<GtkContainer *>(data);
1886 GString *str = g_string_new(NULL);
1887 GtkEntry *hex_code_entry;
1888 gchar *hex_code_full;
1891 guint64 hex_value = 0;
1893 list = gtk_container_get_children(hbox);
1895 hex_code_entry = static_cast<GtkEntry *>(g_list_nth_data(list, 2));
1896 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1898 hex_code = g_strsplit(hex_code_full, "+", 2);
1899 if (hex_code[0] && hex_code[1])
1901 hex_value = strtoull(hex_code[1], NULL, 16);
1903 if (!hex_value || hex_value > 0x10FFFF)
1905 hex_value = 0x003F; // Unicode 'Question Mark'
1907 str = g_string_append_unichar(str, (gunichar)hex_value);
1908 gtk_label_set_text(static_cast<GtkLabel *>(g_list_nth_data(list, 1)), str->str);
1910 g_strfreev(hex_code);
1911 g_string_free(str, TRUE);
1912 g_free(hex_code_full);
1917 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1919 guint64 star_symbol;
1921 star_symbol = star_rating_symbol_test(widget, data);
1922 c_options->star_rating.star = star_symbol;
1925 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1927 guint64 rejected_symbol;
1929 rejected_symbol = star_rating_symbol_test(widget, data);
1930 c_options->star_rating.rejected = rejected_symbol;
1933 /* general options tab */
1934 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1935 typedef struct _TZData TZData;
1939 GCancellable *cancellable;
1941 GtkWidget *progress;
1943 GFile *timezone_database_gq;
1944 gchar *timezone_database_user;
1947 static void config_tab_general(GtkWidget *notebook)
1952 GtkWidget *group_frame;
1953 GtkWidget *subgroup;
1955 GtkWidget *ct_button;
1958 gint hours, minutes, remainder;
1960 GtkWidget *star_rating_entry;
1962 gchar *rating_symbol;
1965 gchar *download_locn;
1966 GNetworkMonitor *net_mon;
1967 GSocketConnectable *tz_org;
1968 gboolean internet_available = FALSE;
1971 vbox = scrolled_notebook_page(notebook, _("General"));
1973 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1975 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1976 add_thumb_size_menu(table, 0, 0, _("Size:"));
1977 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1979 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1980 pref_label_new(hbox, _("Custom size: "));
1981 pref_spin_new_int(hbox, _("Width:"), NULL, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
1982 pref_spin_new_int(hbox, _("Height:"), NULL, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
1984 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
1985 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1987 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1988 pref_checkbox_link_sensitivity(ct_button, subgroup);
1990 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
1991 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
1992 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
1993 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1994 button = pref_radiobutton_new(group_frame, NULL, get_thumbnails_cache_dir(),
1995 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1996 G_CALLBACK(cache_geeqie_cb), NULL);
1998 group_frame = pref_frame_new(subgroup, TRUE,
1999 _("Store thumbnails local to image folder (non-standard)"),
2000 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2001 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
2002 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
2003 G_CALLBACK(cache_local_cb), NULL);
2005 group_frame = pref_frame_new(subgroup, TRUE,
2006 _("Use standard thumbnail style and cache, shared with other applications"),
2007 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2008 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
2009 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2010 G_CALLBACK(cache_standard_cb), NULL);
2012 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
2013 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
2015 pref_checkbox_new_int(group, _("Thumbnail color management"),
2016 options->thumbnails.use_color_management, &c_options->thumbnails.use_color_management);
2018 spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
2020 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
2021 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
2023 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
2024 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
2025 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
2027 // pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
2028 // options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
2031 pref_spacer(group, PREF_PAD_GROUP);
2033 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
2035 c_options->star_rating.star = options->star_rating.star;
2036 c_options->star_rating.rejected = options->star_rating.rejected;
2038 str = g_string_new(NULL);
2039 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2040 pref_label_new(hbox, _("Star character: "));
2041 str = g_string_append_unichar(str, options->star_rating.star);
2042 pref_label_new(hbox, g_strdup(str->str));
2043 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
2044 star_rating_entry = gtk_entry_new();
2045 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2046 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2047 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2048 gtk_widget_show(star_rating_entry);
2049 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2050 G_CALLBACK(star_rating_star_test_cb), hbox);
2051 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2052 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2053 gtk_widget_show(button);
2054 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."));
2055 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2056 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2057 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2058 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2059 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2060 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2061 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2062 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2063 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2064 G_CALLBACK(star_rating_star_icon_cb),
2067 g_string_free(str, TRUE);
2068 g_free(rating_symbol);
2070 str = g_string_new(NULL);
2071 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2072 pref_label_new(hbox, _("Rejected character: "));
2073 str = g_string_append_unichar(str, options->star_rating.rejected);
2074 pref_label_new(hbox, g_strdup(str->str));
2075 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2076 star_rating_entry = gtk_entry_new();
2077 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2078 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2079 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2080 gtk_widget_show(star_rating_entry);
2081 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2082 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2083 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2084 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2085 gtk_widget_show(button);
2086 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."));
2087 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2088 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2089 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2090 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2091 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2092 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2093 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2094 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2095 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2096 G_CALLBACK(star_rating_rejected_icon_cb),
2099 g_string_free(str, TRUE);
2100 g_free(rating_symbol);
2102 pref_spacer(group, PREF_PAD_GROUP);
2104 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2106 c_options->slideshow.delay = options->slideshow.delay;
2107 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2108 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2109 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2110 seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2111 SLIDESHOW_SUBSECOND_PRECISION;
2113 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2115 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2117 options->slideshow.delay ? hours : 0.0,
2118 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2119 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2120 spin = pref_spin_new(hbox, ":" , NULL,
2122 options->slideshow.delay ? minutes: 0.0,
2123 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2124 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2125 spin = pref_spin_new(hbox, ":", NULL,
2126 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2127 options->slideshow.delay ? seconds : 10.0,
2128 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2129 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2131 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2132 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2134 pref_spacer(group, PREF_PAD_GROUP);
2136 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2138 pref_spin_new_int(group, _("Decoded image cache size (MiB):"), NULL,
2139 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2140 pref_checkbox_new_int(group, _("Preload next image"),
2141 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2143 pref_checkbox_new_int(group, _("Refresh on file change"),
2144 options->update_on_time_change, &c_options->update_on_time_change);
2147 pref_spacer(group, PREF_PAD_GROUP);
2149 group = pref_group_new(vbox, FALSE, _("Expand menu and toolbar"), GTK_ORIENTATION_VERTICAL);
2151 pref_checkbox_new_int(group, _("Expand menu and toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2152 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2153 gtk_widget_set_tooltip_text(group, _("Expand the menu and toolbar to the full width of the window"));
2155 pref_spacer(group, PREF_PAD_GROUP);
2157 if (g_getenv("APPDIR") && strstr(g_getenv("APPDIR"), "/tmp/.mount_Geeqie"))
2159 group = pref_group_new(vbox, FALSE, _("AppImage updates notifications"), GTK_ORIENTATION_VERTICAL);
2160 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2161 pref_checkbox_new_int(group, _("Enable"), options->appimage_notifications, &c_options->appimage_notifications);
2162 gtk_widget_set_tooltip_text(group, _("Show a notification on start-up if the server has a newer version than the current. Requires an Internet connection"));
2164 pref_spacer(group, PREF_PAD_GROUP);
2168 net_mon = g_network_monitor_get_default();
2169 tz_org = g_network_address_parse_uri(TIMEZONE_DATABASE_WEB, 80, NULL);
2172 internet_available = g_network_monitor_can_reach(net_mon, tz_org, NULL, NULL);
2173 g_object_unref(tz_org);
2176 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2177 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2179 if (!internet_available)
2181 gtk_widget_set_sensitive(group, FALSE);
2184 tz = g_new0(TZData, 1);
2186 path = path_from_utf8(TIMEZONE_DATABASE_WEB);
2187 basename = g_path_get_basename(path);
2188 tz->timezone_database_user = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
2192 if (isfile(tz->timezone_database_user))
2194 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2198 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2201 download_locn = g_strconcat(_("Download database from: "), TIMEZONE_DATABASE_WEB, NULL);
2202 pref_label_new(GTK_WIDGET(hbox), download_locn);
2203 g_free(download_locn);
2205 if (!internet_available)
2207 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"));
2211 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"));
2213 gtk_widget_show(button);
2215 pref_spacer(group, PREF_PAD_GROUP);
2217 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2219 help_search_engine_entry = gtk_entry_new();
2220 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2221 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2222 gtk_widget_show(help_search_engine_entry);
2224 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"));
2226 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2227 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2228 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2229 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2230 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2231 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2232 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2233 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2234 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2235 G_CALLBACK(help_search_engine_entry_icon_cb),
2236 help_search_engine_entry);
2240 static void config_tab_image(GtkWidget *notebook)
2245 GtkWidget *ct_button;
2246 GtkWidget *enlargement_button;
2249 //~ #ifdef HAVE_CLUTTER
2250 //~ GtkWidget *gpu_accel;
2253 vbox = scrolled_notebook_page(notebook, _("Image"));
2255 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2257 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2258 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2259 //~ if (options->image.use_clutter_renderer && !options->disable_gpu)
2261 //~ gtk_widget_set_sensitive(table, FALSE);
2264 //~ #ifdef HAVE_CLUTTER
2265 //~ gpu_accel = pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library (Requires restart)"),
2266 //~ options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2267 //~ if (options->disable_gpu && !options->override_disable_gpu)
2269 //~ gtk_widget_set_sensitive(gpu_accel, FALSE);
2273 pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2274 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2275 //~ if (options->image.use_clutter_renderer && !options->disable_gpu)
2277 //~ gtk_widget_set_sensitive(two_pass, FALSE);
2280 c_options->image.zoom_increment = options->image.zoom_increment;
2281 spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2282 0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2283 G_CALLBACK(zoom_increment_cb), NULL);
2284 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2286 c_options->image.zoom_style = options->image.zoom_style;
2287 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2288 add_zoom_style_selection_menu(table, 0, 0, _("Zoom style:"), options->image.zoom_style, &c_options->image.zoom_style);
2290 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2292 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2293 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2294 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2295 spin = pref_spin_new_int(hbox, NULL, NULL,
2297 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2298 pref_checkbox_link_sensitivity(enlargement_button, spin);
2299 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."));
2301 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2302 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2303 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2304 spin = pref_spin_new_int(hbox, NULL, NULL,
2306 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2307 pref_checkbox_link_sensitivity(ct_button, spin);
2308 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."));
2310 group = pref_group_new(vbox, FALSE, _("Tile size"), GTK_ORIENTATION_VERTICAL);
2311 //~ gtk_widget_set_sensitive(group, !options->image.use_clutter_renderer);
2313 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2314 spin = pref_spin_new_int(hbox, _("Pixels"), _("(Requires restart)"),
2316 options->image.tile_size, &c_options->image.tile_size);
2317 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."));
2319 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2321 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2322 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2324 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2325 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2327 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2328 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2330 c_options->image.border_color = options->image.border_color;
2332 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2333 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2335 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2336 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2338 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2339 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2344 static void save_default_window_layout_cb(GtkWidget *UNUSED(widget), gpointer UNUSED(data))
2346 LayoutWindow *lw = NULL;
2347 gchar *default_path;
2350 /* Get current lw */
2353 tmp_id = lw->options.id;
2354 lw->options.id = g_strdup("lw_default");
2356 default_path = g_build_filename(get_rc_dir(), DEFAULT_WINDOW_LAYOUT, NULL);
2357 save_default_layout_options_to_file(default_path, options, lw);
2358 g_free(lw->options.id);
2359 lw->options.id = tmp_id;
2360 g_free(default_path);
2363 static gboolean popover_cb(gpointer data)
2365 GtkPopover *popover = static_cast<GtkPopover *>(data);
2367 gtk_popover_popdown(popover);
2372 static void default_layout_changed_cb(GtkWidget *UNUSED(button), GtkPopover *popover)
2374 gtk_popover_popup(popover);
2376 g_timeout_add(2000, popover_cb, popover);
2379 static GtkWidget *create_popover(GtkWidget *parent, GtkWidget *child, GtkPositionType pos)
2383 popover = gtk_popover_new(parent);
2384 gtk_popover_set_position(GTK_POPOVER (popover), pos);
2385 gtk_container_add (GTK_CONTAINER(popover), child);
2386 gtk_container_set_border_width(GTK_CONTAINER (popover), 6);
2387 gtk_widget_show (child);
2392 static void config_tab_windows(GtkWidget *notebook)
2397 GtkWidget *subgroup;
2399 GtkWidget *ct_button;
2402 vbox = scrolled_notebook_page(notebook, _("Windows"));
2404 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2406 ct_button = pref_checkbox_new_int(group, _("Remember session"),
2407 options->save_window_positions, &c_options->save_window_positions);
2409 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2410 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2411 pref_checkbox_link_sensitivity(ct_button, button);
2413 button = pref_checkbox_new_int(group, _("Remember window workspace"),
2414 options->save_window_workspace, &c_options->save_window_workspace);
2415 pref_checkbox_link_sensitivity(ct_button, button);
2417 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2418 options->tools_restore_state, &c_options->tools_restore_state);
2420 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2421 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2423 pref_checkbox_new_int(group, _("Show window IDs"),
2424 options->show_window_ids, &c_options->show_window_ids);
2426 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2427 pref_label_new(subgroup, _("Use current layout for default: "));
2428 button = pref_button_new(subgroup, NULL, _("Set"), FALSE, G_CALLBACK(save_default_window_layout_cb), NULL);
2432 popover = create_popover(button, gtk_label_new(_("Current window layout\nhas been set as default")), GTK_POS_TOP);
2433 gtk_popover_set_modal(GTK_POPOVER (popover), FALSE);
2434 g_signal_connect(button, "clicked", G_CALLBACK(default_layout_changed_cb), popover);
2436 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2438 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2439 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2441 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2442 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2443 options->image.limit_window_size, &c_options->image.limit_window_size);
2444 spin = pref_spin_new_int(hbox, NULL, NULL,
2446 options->image.max_window_size, &c_options->image.max_window_size);
2447 pref_checkbox_link_sensitivity(ct_button, spin);
2449 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2451 c_options->fullscreen.screen = options->fullscreen.screen;
2452 c_options->fullscreen.above = options->fullscreen.above;
2453 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2454 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2455 gtk_widget_show(hbox);
2457 pref_checkbox_new_int(group, _("Smooth image flip"),
2458 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2459 pref_checkbox_new_int(group, _("Disable screen saver"),
2460 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2463 #define PRE_FORMATTED_COLUMNS 5
2464 static void config_tab_osd(GtkWidget *notebook)
2470 GtkWidget *image_overlay_template_view;
2471 GtkWidget *scrolled;
2472 GtkWidget *scrolled_pre_formatted;
2473 GtkTextBuffer *buffer;
2475 GtkWidget *subgroup;
2477 vbox = scrolled_notebook_page(notebook, _("OSD"));
2479 image_overlay_template_view = gtk_text_view_new();
2481 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2483 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2485 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2486 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2487 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2488 gtk_widget_show(scrolled_pre_formatted);
2489 gtk_widget_show(subgroup);
2491 pref_line(group, PREF_PAD_GAP);
2493 pref_label_new(group, _("Image overlay template"));
2495 scrolled = gtk_scrolled_window_new(NULL, NULL);
2496 gtk_widget_set_size_request(scrolled, 200, 150);
2497 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2498 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2499 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2500 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2501 gtk_widget_show(scrolled);
2503 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2504 _("Extensive formatting options are shown in the Help file"));
2506 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2507 gtk_widget_show(image_overlay_template_view);
2509 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2511 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2512 G_CALLBACK(image_overlay_set_font_cb), notebook);
2514 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2515 gtk_widget_show(button);
2517 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2518 G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2519 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2520 gtk_widget_show(button);
2522 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2523 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2524 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2525 gtk_widget_show(button);
2526 image_overlay_set_text_colours();
2528 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2529 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2530 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2531 gtk_widget_show(button);
2533 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2534 G_CALLBACK(image_overlay_help_cb), NULL);
2535 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2536 gtk_widget_show(button);
2538 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2539 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2540 g_signal_connect(G_OBJECT(buffer), "changed",
2541 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2543 pref_line(group, PREF_PAD_GAP);
2545 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2546 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2547 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2548 gtk_widget_show(hbox);
2549 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2550 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2551 gtk_widget_show(label);
2552 pref_spacer(group,TRUE);
2554 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2555 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2556 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2557 gtk_widget_show(hbox);
2558 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2559 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2560 gtk_widget_show(label);
2561 pref_spacer(group,TRUE);
2563 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2564 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2565 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2566 gtk_widget_show(hbox);
2567 label = gtk_label_new(_("%path:39%"));
2568 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2569 gtk_widget_show(label);
2570 pref_spacer(group,TRUE);
2572 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2573 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2574 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2575 gtk_widget_show(hbox);
2576 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%"));
2577 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2578 gtk_widget_show(label);
2579 pref_spacer(group,TRUE);
2581 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2582 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2583 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2584 gtk_widget_show(hbox);
2585 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2586 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2587 gtk_widget_show(label);
2590 static GtkTreeModel *create_class_model(void)
2592 GtkListStore *model;
2596 /* create list store */
2597 model = gtk_list_store_new(1, G_TYPE_STRING);
2598 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2600 gtk_list_store_append(model, &iter);
2601 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2603 return GTK_TREE_MODEL (model);
2608 static gint filter_table_sort_cb(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data)
2610 gint n = GPOINTER_TO_INT(data);
2612 FilterEntry *filter_a;
2613 FilterEntry *filter_b;
2615 gtk_tree_model_get(model, a, 0, &filter_a, -1);
2616 gtk_tree_model_get(model, b, 0, &filter_b, -1);
2620 case FILETYPES_COLUMN_ENABLED:
2622 ret = filter_a->enabled - filter_b->enabled;
2625 case FILETYPES_COLUMN_FILTER:
2627 ret = g_utf8_collate(filter_a->extensions, filter_b->extensions);
2630 case FILETYPES_COLUMN_DESCRIPTION:
2632 ret = g_utf8_collate(filter_a->description, filter_b->description);
2635 case FILETYPES_COLUMN_CLASS:
2637 ret = g_strcmp0(format_class_list[filter_a->file_class], format_class_list[filter_b->file_class]);
2640 case FILETYPES_COLUMN_WRITABLE:
2642 ret = filter_a->writable - filter_b->writable;
2645 case FILETYPES_COLUMN_SIDECAR:
2647 ret = filter_a->allow_sidecar - filter_b->allow_sidecar;
2651 g_return_val_if_reached(0);
2657 static gboolean search_function_cb(GtkTreeModel *model, gint UNUSED(column), const gchar *key, GtkTreeIter *iter, gpointer UNUSED(search_data))
2660 gboolean ret = TRUE;
2662 gtk_tree_model_get(model, iter, 0, &fe, -1);
2664 if (g_strstr_len(fe->extensions, -1, key))
2672 static void config_tab_files(GtkWidget *notebook)
2679 GtkWidget *ct_button;
2680 GtkWidget *scrolled;
2681 GtkWidget *filter_view;
2682 GtkCellRenderer *renderer;
2683 GtkTreeSelection *selection;
2684 GtkTreeViewColumn *column;
2686 vbox = scrolled_notebook_page(notebook, _("File Filters"));
2688 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2690 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2691 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2692 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2693 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2694 pref_checkbox_new_int(group, _("Case sensitive sort"),
2695 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2696 pref_checkbox_new_int(group, _("Natural sort order - Requires restart"),
2697 options->file_sort.natural, &c_options->file_sort.natural);
2698 pref_checkbox_new_int(group, _("Disable file extension checks"),
2699 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2701 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2702 options->file_filter.disable, &c_options->file_filter.disable);
2705 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2707 sidecar_ext_entry = gtk_entry_new();
2708 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2709 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2710 gtk_widget_show(sidecar_ext_entry);
2712 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2714 frame = pref_group_parent(group);
2715 g_signal_connect(G_OBJECT(ct_button), "toggled",
2716 G_CALLBACK(filter_disable_cb), frame);
2717 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2719 scrolled = gtk_scrolled_window_new(NULL, NULL);
2720 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2721 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2722 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2723 gtk_widget_show(scrolled);
2725 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2726 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2727 g_object_unref(filter_store);
2728 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2729 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2731 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2733 column = gtk_tree_view_column_new();
2734 gtk_tree_view_column_set_title(column, _("Enabled"));
2735 gtk_tree_view_column_set_resizable(column, TRUE);
2737 renderer = gtk_cell_renderer_toggle_new();
2738 g_signal_connect(G_OBJECT(renderer), "toggled",
2739 G_CALLBACK(filter_store_enable_cb), filter_store);
2740 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2741 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2742 GINT_TO_POINTER(FE_ENABLE), NULL);
2743 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);
2744 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_ENABLED);
2745 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2747 column = gtk_tree_view_column_new();
2748 gtk_tree_view_column_set_title(column, _("Filter"));
2749 gtk_tree_view_column_set_resizable(column, TRUE);
2750 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);
2751 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_FILTER);
2753 renderer = gtk_cell_renderer_text_new();
2754 g_signal_connect(G_OBJECT(renderer), "edited",
2755 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2756 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2757 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2758 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2759 GINT_TO_POINTER(FE_EXTENSION), NULL);
2760 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2762 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), TRUE);
2763 gtk_tree_view_set_search_column(GTK_TREE_VIEW(filter_view), FILETYPES_COLUMN_FILTER);
2764 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(filter_view), search_function_cb, NULL, NULL);
2766 column = gtk_tree_view_column_new();
2767 gtk_tree_view_column_set_title(column, _("Description"));
2768 gtk_tree_view_column_set_resizable(column, TRUE);
2769 gtk_tree_view_column_set_fixed_width(column, 200);
2770 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2772 renderer = gtk_cell_renderer_text_new();
2773 g_signal_connect(G_OBJECT(renderer), "edited",
2774 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2775 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2776 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2777 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2778 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2779 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2780 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);
2781 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_DESCRIPTION);
2783 column = gtk_tree_view_column_new();
2784 gtk_tree_view_column_set_title(column, _("Class"));
2785 gtk_tree_view_column_set_resizable(column, TRUE);
2786 renderer = gtk_cell_renderer_combo_new();
2787 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2788 "model", create_class_model(),
2793 g_signal_connect(G_OBJECT(renderer), "edited",
2794 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2795 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2796 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2797 GINT_TO_POINTER(FE_CLASS), NULL);
2798 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2799 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);
2800 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_CLASS);
2802 column = gtk_tree_view_column_new();
2803 gtk_tree_view_column_set_title(column, _("Writable"));
2804 gtk_tree_view_column_set_resizable(column, FALSE);
2805 renderer = gtk_cell_renderer_toggle_new();
2806 g_signal_connect(G_OBJECT(renderer), "toggled",
2807 G_CALLBACK(filter_store_writable_cb), filter_store);
2808 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2809 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2810 GINT_TO_POINTER(FE_WRITABLE), NULL);
2811 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2812 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);
2813 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_WRITABLE);
2815 column = gtk_tree_view_column_new();
2816 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2817 gtk_tree_view_column_set_resizable(column, FALSE);
2818 renderer = gtk_cell_renderer_toggle_new();
2819 g_signal_connect(G_OBJECT(renderer), "toggled",
2820 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2821 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2822 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2823 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2824 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2825 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);
2826 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_SIDECAR);
2828 filter_store_populate();
2829 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2830 gtk_widget_show(filter_view);
2832 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2834 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2835 G_CALLBACK(filter_default_cb), filter_view);
2836 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2837 gtk_widget_show(button);
2839 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2840 G_CALLBACK(filter_remove_cb), filter_view);
2841 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2842 gtk_widget_show(button);
2844 button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2845 G_CALLBACK(filter_add_cb), filter_view);
2846 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2847 gtk_widget_show(button);
2851 static void config_tab_metadata(GtkWidget *notebook)
2856 GtkWidget *ct_button;
2858 GtkWidget *tmp_widget;
2860 GtkWidget *text_label;
2862 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2865 group = pref_group_new(vbox, FALSE, _("Metadata writing sequence"), GTK_ORIENTATION_VERTICAL);
2867 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2869 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."));
2870 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2871 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2873 gtk_widget_set_tooltip_text(label, _("A flowchart of the sequence is shown in the Help file"));
2875 ct_button = pref_checkbox_new_int(group, "", options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2876 text_label = gtk_bin_get_child(GTK_BIN(ct_button));
2877 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"));
2878 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2880 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)"));
2881 gtk_widget_set_tooltip_markup(ct_button, markup);
2885 gtk_widget_set_sensitive(ct_button, FALSE);
2888 tmp_widget = pref_checkbox_new_int(group, "", options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2889 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2890 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)"));
2891 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2894 label = pref_label_new(group, "");
2895 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(), "/");
2896 gtk_label_set_markup (GTK_LABEL(label), markup);
2899 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2900 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2901 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2902 pref_spacer(group, PREF_PAD_GROUP);
2904 group = pref_group_new(vbox, FALSE, _("Step 1 Options:"), GTK_ORIENTATION_VERTICAL);
2906 gtk_widget_set_sensitive(group, FALSE);
2909 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2910 pref_checkbox_link_sensitivity(ct_button, hbox);
2912 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);
2913 gtk_widget_set_tooltip_text(tmp_widget, _("A simplified conversion list is in the Help file"));
2915 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);
2917 pref_checkbox_new_int(hbox, _("Ask before writing to image files"), options->metadata.confirm_write, &c_options->metadata.confirm_write);
2919 tmp_widget= pref_checkbox_new_int(hbox, "", options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2920 gtk_widget_set_tooltip_text(tmp_widget, _("This file naming convention is used by Darktable"));
2921 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2922 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", ")");
2923 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2926 pref_spacer(group, PREF_PAD_GROUP);
2928 group = pref_group_new(vbox, FALSE, _("Steps 2 and 3 Option:"), GTK_ORIENTATION_VERTICAL);
2930 gtk_widget_set_sensitive(group, FALSE);
2933 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);
2935 pref_spacer(group, PREF_PAD_GROUP);
2937 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2938 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);
2939 gtk_widget_set_tooltip_text(tmp_widget, _("See the Help file for a list of the tags used"));
2941 tmp_widget = pref_checkbox_new_int(group, _("Permit Keywords to be case-sensitive"), options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2942 gtk_widget_set_tooltip_text(tmp_widget, _("When selected, \"Place\" and \"place\" are two different keywords"));
2944 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"), options->metadata.write_orientation, &c_options->metadata.write_orientation);
2945 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"));
2948 gtk_widget_set_sensitive(ct_button, FALSE);
2951 pref_spacer(group, PREF_PAD_GROUP);
2953 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2955 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"), options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2957 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2958 pref_checkbox_link_sensitivity(ct_button, hbox);
2960 pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1, options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2962 pref_checkbox_new_int(group, _("Write metadata on image change"), options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2964 pref_checkbox_new_int(group, _("Write metadata on directory change"), options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2966 pref_spacer(group, PREF_PAD_GROUP);
2969 group = pref_group_new(vbox, FALSE, _("Spelling checks"), GTK_ORIENTATION_VERTICAL);
2971 ct_button = pref_checkbox_new_int(group, _("Check spelling - Requires restart"), options->metadata.check_spelling, &c_options->metadata.check_spelling);
2972 gtk_widget_set_tooltip_text(ct_button, _("Spelling checks are performed on info sidebar panes Comment, Headline and Title"));
2975 pref_spacer(group, PREF_PAD_GROUP);
2977 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2979 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"), options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2980 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");
2985 typedef struct _KeywordFindData KeywordFindData;
2986 struct _KeywordFindData
2993 GtkWidget *button_close;
2994 GtkWidget *button_stop;
2995 GtkWidget *button_start;
2996 GtkWidget *progress;
3004 guint idle_id; /* event source id */
3007 #define KEYWORD_DIALOG_WIDTH 400
3009 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
3011 GList *list_d = NULL;
3012 GList *list_f = NULL;
3016 filelist_read(dir_fd, &list_f, &list_d);
3020 filelist_read(dir_fd, &list_f, NULL);
3023 list_f = filelist_filter(list_f, FALSE);
3024 list_d = filelist_filter(list_d, TRUE);
3026 kfd->list = g_list_concat(list_f, kfd->list);
3027 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
3030 static void keywords_find_reset(KeywordFindData *kfd)
3032 filelist_free(kfd->list);
3035 filelist_free(kfd->list_dir);
3036 kfd->list_dir = NULL;
3039 static void keywords_find_close_cb(GenericDialog *UNUSED(fd), gpointer data)
3041 KeywordFindData *kfd = static_cast<KeywordFindData *>(data);
3043 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
3045 keywords_find_reset(kfd);
3046 generic_dialog_close(kfd->gd);
3050 static void keywords_find_finish(KeywordFindData *kfd)
3052 keywords_find_reset(kfd);
3054 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
3055 spinner_set_interval(kfd->spinner, -1);
3057 gtk_widget_set_sensitive(kfd->group, TRUE);
3058 gtk_widget_set_sensitive(kfd->button_start, TRUE);
3059 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3060 gtk_widget_set_sensitive(kfd->button_close, TRUE);
3063 static void keywords_find_stop_cb(GenericDialog *UNUSED(fd), gpointer data)
3065 KeywordFindData *kfd = static_cast<KeywordFindData *>(data);
3067 g_idle_remove_by_data(kfd);
3069 keywords_find_finish(kfd);
3072 static gboolean keywords_find_file(gpointer data)
3074 KeywordFindData *kfd = static_cast<KeywordFindData *>(data);
3076 GtkTextBuffer *buffer;
3084 fd = static_cast<FileData *>(kfd->list->data);
3085 kfd->list = g_list_remove(kfd->list, fd);
3087 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
3088 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3092 gtk_text_buffer_get_end_iter(buffer, &iter);
3093 tmp = g_strconcat(static_cast<const gchar *>(keywords->data), "\n", NULL);
3094 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3096 keywords = keywords->next;
3099 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
3100 file_data_unref(fd);
3101 string_list_free(keywords);
3105 else if (kfd->list_dir)
3109 fd = static_cast<FileData *>(kfd->list_dir->data);
3110 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
3112 keywords_find_folder(kfd, fd);
3114 file_data_unref(fd);
3119 keywords_find_finish(kfd);
3124 static void keywords_find_start_cb(GenericDialog *UNUSED(fd), gpointer data)
3126 KeywordFindData *kfd = static_cast<KeywordFindData *>(data);
3129 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
3131 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
3132 parse_out_relatives(path);
3136 warning_dialog(_("Invalid folder"),
3137 _("The specified folder can not be found."),
3138 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
3144 gtk_widget_set_sensitive(kfd->group, FALSE);
3145 gtk_widget_set_sensitive(kfd->button_start, FALSE);
3146 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
3147 gtk_widget_set_sensitive(kfd->button_close, FALSE);
3148 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
3150 dir_fd = file_data_new_dir(path);
3151 keywords_find_folder(kfd, dir_fd);
3152 file_data_unref(dir_fd);
3153 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
3159 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
3161 KeywordFindData *kfd;
3165 kfd = g_new0(KeywordFindData, 1);
3167 kfd->gd = generic_dialog_new(_("Search for keywords"),
3168 "search_for_keywords",
3171 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
3172 kfd->gd->cancel_cb = keywords_find_close_cb;
3173 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
3174 keywords_find_close_cb, FALSE);
3175 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
3176 keywords_find_start_cb, FALSE);
3177 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
3178 keywords_find_stop_cb, FALSE);
3179 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3181 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
3183 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
3184 pref_spacer(hbox, PREF_PAD_INDENT);
3185 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
3187 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3188 pref_label_new(hbox, _("Folder:"));
3190 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
3191 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
3192 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
3193 gtk_widget_show(label);
3195 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
3197 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
3198 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3200 kfd->progress = gtk_entry_new();
3201 gtk_widget_set_can_focus(kfd->progress, FALSE);
3202 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
3203 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
3204 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
3205 gtk_widget_show(kfd->progress);
3207 kfd->spinner = spinner_new(NULL, -1);
3208 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
3209 gtk_widget_show(kfd->spinner);
3213 gtk_widget_show(kfd->gd->dialog);
3216 static void keywords_find_cb(GtkWidget *widget, gpointer UNUSED(data))
3218 const gchar *path = layout_get_path(NULL);
3220 if (!path || !*path) path = homedir();
3221 keywords_find_dialog(widget, path);
3224 static void config_tab_keywords_save()
3226 GtkTextIter start, end;
3227 GtkTextBuffer *buffer;
3228 GList *kw_list = NULL;
3234 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3235 gtk_text_buffer_get_bounds(buffer, &start, &end);
3237 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3239 kw_split = strtok(buffer_text, "\n");
3240 while (kw_split != NULL)
3246 if (g_strcmp0(static_cast<const gchar *>(work->data), kw_split) == 0)
3255 kw_list = g_list_append(kw_list, g_strdup(kw_split));
3257 kw_split = strtok(NULL, "\n");
3260 keyword_list_set(kw_list);
3262 string_list_free(kw_list);
3263 g_free(buffer_text);
3266 static void config_tab_keywords(GtkWidget *notebook)
3272 GtkWidget *scrolled;
3274 GtkTextBuffer *buffer;
3277 GspellTextView *gspell_view;
3280 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3282 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3284 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3286 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
3287 G_CALLBACK(keywords_find_cb), keyword_text);
3288 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
3291 keyword_text = gtk_text_view_new();
3292 gtk_widget_set_size_request(keyword_text, 20, 20);
3293 scrolled = gtk_scrolled_window_new(NULL, NULL);
3294 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3295 gtk_widget_show(scrolled);
3298 if (options->metadata.check_spelling)
3300 gspell_view = gspell_text_view_get_from_gtk_text_view(GTK_TEXT_VIEW(keyword_text));
3301 gspell_text_view_basic_setup(gspell_view);
3305 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
3306 gtk_widget_show(keyword_text);
3308 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3310 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3311 gtk_text_buffer_create_tag(buffer, "monospace",
3312 "family", "monospace", NULL);
3314 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3315 gtk_text_buffer_get_start_iter(buffer, &iter);
3316 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3319 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3321 GList *kwl = keyword_list_get();
3322 kwl = g_list_first(kwl);
3325 gtk_text_buffer_get_end_iter (buffer, &iter);
3326 tmp = g_strconcat(static_cast<const gchar *>(kwl->data), "\n", NULL);
3327 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3332 gtk_text_buffer_set_modified(buffer, FALSE);
3339 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3341 gint *option = static_cast<gint *>(data);
3343 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3347 *option = INTENT_PERCEPTUAL;
3350 *option = INTENT_RELATIVE_COLORIMETRIC;
3353 *option = INTENT_SATURATION;
3356 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3361 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3362 gint option, gint *option_c)
3369 pref_table_label(table, column, row, text, 0.0);
3371 combo = gtk_combo_box_text_new();
3373 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3374 if (option == INTENT_PERCEPTUAL) current = 0;
3375 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3376 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3377 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3378 if (option == INTENT_SATURATION) current = 2;
3379 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3380 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3382 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3384 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3386 g_signal_connect(G_OBJECT(combo), "changed",
3387 G_CALLBACK(intent_menu_cb), option_c);
3389 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
3390 gtk_widget_show(combo);
3394 static void config_tab_color(GtkWidget *notebook)
3403 vbox = scrolled_notebook_page(notebook, _("Color management"));
3405 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3407 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3410 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3411 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3413 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3414 pref_label_bold(label, TRUE, FALSE);
3416 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3417 pref_label_bold(label, TRUE, FALSE);
3419 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3420 pref_label_bold(label, TRUE, FALSE);
3422 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3427 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3428 pref_table_label(table, 0, i + 1, buf, 1.0);
3431 entry = gtk_entry_new();
3432 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3433 if (options->color_profile.input_name[i])
3435 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3437 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3438 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), static_cast<GtkAttachOptions>(0), 0, 0);
3439 gtk_widget_show(entry);
3440 color_profile_input_name_entry[i] = entry;
3442 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3443 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3444 gtk_widget_set_size_request(entry, 160, -1);
3445 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3446 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), static_cast<GtkAttachOptions>(0), 0, 0);
3447 gtk_widget_show(tabcomp);
3448 color_profile_input_file_entry[i] = entry;
3451 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3453 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3455 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3456 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3458 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3460 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3461 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3462 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3463 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3464 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3466 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3468 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3470 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), static_cast<GtkAttachOptions>(0), 0, 0);
3472 gtk_widget_show(tabcomp);
3475 /* advanced entry tab */
3476 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer UNUSED(data))
3478 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3480 c_options->file_ops.use_system_trash = FALSE;
3481 c_options->file_ops.no_trash = FALSE;
3485 static void use_system_trash_cb(GtkWidget *widget, gpointer UNUSED(data))
3487 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3489 c_options->file_ops.use_system_trash = TRUE;
3490 c_options->file_ops.no_trash = FALSE;
3494 static void use_no_cache_cb(GtkWidget *widget, gpointer UNUSED(data))
3496 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3498 c_options->file_ops.no_trash = TRUE;
3502 static void config_tab_behavior(GtkWidget *notebook)
3509 GtkWidget *ct_button;
3513 GtkWidget *with_rename;
3514 GtkWidget *collections_on_top;
3515 GtkWidget *hide_window_in_fullscreen;
3516 GtkWidget *checkbox;
3519 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3521 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3523 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3524 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3525 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3526 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3527 pref_checkbox_new_int(group, _("Enable Delete key"),
3528 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3530 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3531 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3533 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3534 pref_checkbox_link_sensitivity(ct_button, hbox);
3536 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3537 pref_label_new(hbox, _("Folder:"));
3539 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3540 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3541 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3542 gtk_widget_show(tabcomp);
3544 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3545 pref_checkbox_link_sensitivity(ct_button, hbox);
3547 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3548 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MiB"),
3549 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3550 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3551 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3552 G_CALLBACK(safe_delete_view_cb), NULL);
3553 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3554 gtk_widget_show(button);
3556 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3557 G_CALLBACK(safe_delete_clear_cb), NULL);
3558 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3560 c_options->file_ops.no_trash = options->file_ops.no_trash;
3561 c_options->file_ops.use_system_trash = options->file_ops.use_system_trash;
3563 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3564 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3566 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3567 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3569 gtk_widget_show(button);
3571 pref_spacer(group, PREF_PAD_GROUP);
3574 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3576 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3577 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3579 pref_checkbox_new_int(group, _("In place renaming"),
3580 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3582 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3583 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3585 tmp = pref_checkbox_new_int(group, _("Circular selection lists"),
3586 options->circular_selection_lists, &c_options->circular_selection_lists);
3587 gtk_widget_set_tooltip_text(tmp, _("Traverse selection lists in a circular manner"));
3589 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3590 options->marks_save, &c_options->marks_save);
3591 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3593 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3594 options->with_rename, &c_options->with_rename);
3595 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3597 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3598 options->collections_on_top, &c_options->collections_on_top);
3599 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3601 hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3602 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3603 gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice");
3605 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3606 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3608 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);
3609 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."));
3611 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3612 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3614 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3615 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3617 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3618 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3620 pref_spacer(group, PREF_PAD_GROUP);
3622 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3624 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3625 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3626 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3627 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3628 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3629 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3630 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3631 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3632 pref_checkbox_new_int(group, _("Open archive by left click on image"),
3633 options->image_l_click_archive, &c_options->image_l_click_archive);
3634 pref_checkbox_new_int(group, _("Play video by left click on image"),
3635 options->image_l_click_video, &c_options->image_l_click_video);
3636 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3637 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3639 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3640 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3641 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3642 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3643 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3645 pref_spacer(group, PREF_PAD_GROUP);
3647 group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3649 checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3650 options->override_disable_gpu, &c_options->override_disable_gpu);
3651 gtk_widget_set_tooltip_text(checkbox, "Contact the developers for usage");
3654 pref_spacer(group, PREF_PAD_GROUP);
3656 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3658 pref_spin_new_int(group, _("Debug level:"), NULL,
3659 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3661 pref_checkbox_new_int(group, _("Timer data"),
3662 options->log_window.timer_data, &c_options->log_window.timer_data);
3664 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3665 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3669 /* accelerators tab */
3670 static void config_tab_accelerators(GtkWidget *notebook)
3676 GtkWidget *scrolled;
3677 GtkWidget *accel_view;
3678 GtkCellRenderer *renderer;
3679 GtkTreeSelection *selection;
3680 GtkTreeViewColumn *column;
3682 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3684 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3686 scrolled = gtk_scrolled_window_new(NULL, NULL);
3687 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3688 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3689 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3690 gtk_widget_show(scrolled);
3692 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3694 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3695 g_object_unref(accel_store);
3696 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3697 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3699 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3701 renderer = gtk_cell_renderer_text_new();
3703 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3708 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3709 gtk_tree_view_column_set_resizable(column, TRUE);
3710 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3713 renderer = gtk_cell_renderer_accel_new();
3714 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3715 G_CALLBACK(accel_store_cleared_cb), accel_store);
3716 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3717 G_CALLBACK(accel_store_edited_cb), accel_store);
3720 g_object_set (renderer,
3722 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3725 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3730 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3731 gtk_tree_view_column_set_resizable(column, TRUE);
3732 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3734 renderer = gtk_cell_renderer_text_new();
3736 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3741 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3742 gtk_tree_view_column_set_resizable(column, TRUE);
3743 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3745 renderer = gtk_cell_renderer_text_new();
3747 column = gtk_tree_view_column_new_with_attributes("Accel",
3752 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3753 gtk_tree_view_column_set_resizable(column, TRUE);
3754 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3756 accel_store_populate();
3757 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3758 gtk_widget_show(accel_view);
3760 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3762 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3763 G_CALLBACK(accel_default_cb), accel_view);
3764 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3765 gtk_widget_show(button);
3767 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3768 G_CALLBACK(accel_reset_cb), accel_view);
3769 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3770 gtk_widget_show(button);
3773 /* toolbar main tab */
3774 static void config_tab_toolbar_main(GtkWidget *notebook)
3777 GtkWidget *toolbardata;
3780 lw = static_cast<LayoutWindow *>(layout_window_list->data);
3782 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3784 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3785 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3786 gtk_widget_show(vbox);
3789 /* toolbar status tab */
3790 static void config_tab_toolbar_status(GtkWidget *notebook)
3793 GtkWidget *toolbardata;
3796 lw = static_cast<LayoutWindow *>(layout_window_list->data);
3798 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3800 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3801 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3802 gtk_widget_show(vbox);
3806 static gint extension_sort_cb(gconstpointer a, gconstpointer b)
3808 return g_strcmp0((gchar *)a, (gchar *)b);
3811 static void config_tab_advanced(GtkWidget *notebook)
3815 GSList *formats_list;
3816 GList *extensions_list = NULL;
3819 GdkPixbufFormat *fm;
3821 GString *types_string = g_string_new(NULL);
3822 GtkWidget *types_string_label;
3823 GtkWidget *threads_string_label;
3824 GtkWidget *dupes_threads_spin;
3826 vbox = scrolled_notebook_page(notebook, _("Advanced"));
3827 group = pref_group_new(vbox, FALSE, _("External preview extraction"), GTK_ORIENTATION_VERTICAL);
3829 pref_checkbox_new_int(group, _("Use external preview extraction - Requires restart"), options->external_preview.enable, &c_options->external_preview.enable);
3831 pref_spacer(group, PREF_PAD_GROUP);
3833 formats_list = gdk_pixbuf_get_formats();
3835 while (formats_list)
3837 fm = static_cast<GdkPixbufFormat *>(formats_list->data);
3838 extensions = gdk_pixbuf_format_get_extensions(fm);
3841 while (extensions[i])
3843 extensions_list = g_list_insert_sorted(extensions_list, g_strdup(extensions[i]), extension_sort_cb);
3847 g_strfreev(extensions);
3848 formats_list = formats_list->next;
3851 while (extensions_list)
3853 if (types_string->len == 0)
3855 types_string = g_string_append(types_string, static_cast<const gchar *>(extensions_list->data));
3859 types_string = g_string_append(types_string, ", ");
3860 types_string = g_string_append(types_string, static_cast<const gchar *>(extensions_list->data));
3863 extensions_list = extensions_list->next;
3866 types_string = g_string_prepend(types_string, _("Usable file types:\n"));
3867 types_string_label = pref_label_new(group, types_string->str);
3868 gtk_label_set_line_wrap(GTK_LABEL(types_string_label), TRUE);
3870 pref_spacer(group, PREF_PAD_GROUP);
3872 group = pref_group_new(vbox, FALSE, _("File identification tool"), GTK_ORIENTATION_VERTICAL);
3873 external_preview_select_entry = gtk_entry_new();
3874 tabcomp = tab_completion_new(&external_preview_select_entry, options->external_preview.select, NULL, NULL, NULL, NULL);
3875 tab_completion_add_select_button(external_preview_select_entry, _("Select file identification tool"), FALSE);
3876 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3877 gtk_widget_show(tabcomp);
3879 group = pref_group_new(vbox, FALSE, _("Preview extraction tool"), GTK_ORIENTATION_VERTICAL);
3880 external_preview_extract_entry = gtk_entry_new();
3881 tabcomp = tab_completion_new(&external_preview_extract_entry, options->external_preview.extract, NULL, NULL, NULL, NULL);
3882 tab_completion_add_select_button(external_preview_extract_entry, _("Select preview extraction tool"), FALSE);
3883 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3884 gtk_widget_show(tabcomp);
3886 gtk_widget_show(vbox);
3888 g_slist_free(formats_list);
3889 string_list_free(extensions_list);
3890 g_string_free(types_string, TRUE);
3892 pref_spacer(group, PREF_PAD_GROUP);
3894 pref_line(vbox, PREF_PAD_SPACE);
3895 group = pref_group_new(vbox, FALSE, _("Thread pool limits"), GTK_ORIENTATION_VERTICAL);
3897 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.");
3898 gtk_label_set_line_wrap(GTK_LABEL(threads_string_label), TRUE);
3900 pref_spacer(vbox, PREF_PAD_GROUP);
3902 dupes_threads_spin = pref_spin_new_int(vbox, _("Duplicate check:"), _("max. threads"), 0, get_cpu_cores(), 1, options->threads.duplicates, &c_options->threads.duplicates);
3903 gtk_widget_set_tooltip_markup(dupes_threads_spin, _("Set to 0 for unlimited"));
3907 static void config_tab_stereo(GtkWidget *notebook)
3915 GtkWidget *fs_button;
3916 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3918 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3920 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3921 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3923 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3924 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3925 pref_checkbox_new_int(box, _("Mirror left image"),
3926 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3927 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3928 pref_checkbox_new_int(box, _("Flip left image"),
3929 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3930 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3931 pref_checkbox_new_int(box, _("Mirror right image"),
3932 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3933 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3934 pref_checkbox_new_int(box, _("Flip right image"),
3935 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3936 pref_checkbox_new_int(group, _("Swap left and right images"),
3937 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3938 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3939 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3941 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3942 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3943 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3944 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3945 pref_checkbox_link_sensitivity(fs_button, box2);
3946 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3947 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3948 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3949 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3950 pref_checkbox_new_int(box, _("Mirror left image"),
3951 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3952 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3953 pref_checkbox_new_int(box, _("Flip left image"),
3954 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3955 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3956 pref_checkbox_new_int(box, _("Mirror right image"),
3957 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3958 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3959 pref_checkbox_new_int(box, _("Flip right image"),
3960 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3961 pref_checkbox_new_int(box2, _("Swap left and right images"),
3962 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3963 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3964 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3966 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3967 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3968 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3969 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3970 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
3971 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3972 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
3973 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3974 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
3975 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3976 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
3977 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3978 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
3979 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3983 /* Main preferences window */
3984 static void config_window_create(LayoutWindow *lw)
3986 GtkWidget *win_vbox;
3988 GtkWidget *notebook;
3990 GtkWidget *ct_button;
3992 if (!c_options) c_options = init_options(NULL);
3994 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3995 DEBUG_NAME(configwindow);
3996 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3997 g_signal_connect(G_OBJECT(configwindow), "delete_event",
3998 G_CALLBACK(config_window_delete), NULL);
3999 if (options->save_dialog_window_positions)
4001 gtk_window_resize(GTK_WINDOW(configwindow), lw->options.preferences_window.w, lw->options.preferences_window.h);
4002 gtk_window_move(GTK_WINDOW(configwindow), lw->options.preferences_window.x, lw->options.preferences_window.y);
4006 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
4008 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
4009 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
4011 win_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
4012 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
4013 gtk_widget_show(win_vbox);
4015 notebook = gtk_notebook_new();
4016 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
4017 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
4018 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
4020 config_tab_general(notebook);
4021 config_tab_image(notebook);
4022 config_tab_osd(notebook);
4023 config_tab_windows(notebook);
4024 config_tab_accelerators(notebook);
4025 config_tab_files(notebook);
4026 config_tab_metadata(notebook);
4027 config_tab_keywords(notebook);
4028 config_tab_color(notebook);
4029 config_tab_stereo(notebook);
4030 config_tab_behavior(notebook);
4031 config_tab_toolbar_main(notebook);
4032 config_tab_toolbar_status(notebook);
4033 config_tab_advanced(notebook);
4035 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), lw->options.preferences_window.page_number);
4037 hbox = gtk_hbutton_box_new();
4038 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
4039 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
4040 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
4041 gtk_widget_show(hbox);
4043 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
4044 G_CALLBACK(config_window_help_cb), notebook);
4045 gtk_container_add(GTK_CONTAINER(hbox), button);
4046 gtk_widget_set_can_default(button, TRUE);
4047 gtk_widget_show(button);
4049 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
4050 G_CALLBACK(config_window_ok_cb), notebook);
4051 gtk_container_add(GTK_CONTAINER(hbox), button);
4052 gtk_widget_set_can_default(button, TRUE);
4053 gtk_widget_grab_default(button);
4054 gtk_widget_show(button);
4058 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
4059 G_CALLBACK(config_window_close_cb), NULL);
4060 gtk_container_add(GTK_CONTAINER(hbox), button);
4061 gtk_widget_set_can_default(button, TRUE);
4062 gtk_widget_show(button);
4064 if (!generic_dialog_get_alternative_button_order(configwindow))
4066 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
4069 gtk_widget_show(notebook);
4071 gtk_widget_show(configwindow);
4075 *-----------------------------------------------------------------------------
4076 * config window show (public)
4077 *-----------------------------------------------------------------------------
4080 void show_config_window(LayoutWindow *lw)
4084 gtk_window_present(GTK_WINDOW(configwindow));
4088 config_window_create(lw);
4097 void show_about_window(LayoutWindow *lw)
4099 GDataInputStream *data_stream;
4100 GInputStream *in_stream_authors;
4101 GInputStream *in_stream_translators;
4102 GResource *credits_resource;
4104 GdkPixbuf *pixbuf_icon;
4105 GdkPixbuf *pixbuf_logo;
4108 gchar *authors[1000];
4109 gchar *authors_path;
4111 gchar *timezone_path;
4113 gchar *translators_path;
4121 copyright = g_string_new(NULL);
4122 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");
4124 timezone_path = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
4125 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
4127 cd = ZDOpenDatabase(timezone_path);
4130 copyright = g_string_append(copyright, ZDGetNotice(cd));
4134 log_printf("Error: Init of timezone database %s failed\n", timezone_path);
4136 ZDCloseDatabase(cd);
4138 g_free(timezone_path);
4140 authors_path = g_build_filename(GQ_RESOURCE_PATH_CREDITS, "authors", NULL);
4142 in_stream_authors = g_resources_open_stream(authors_path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
4144 data_stream = g_data_input_stream_new(in_stream_authors);
4147 while ((author_line = g_data_input_stream_read_line(G_DATA_INPUT_STREAM(data_stream), &length, NULL, NULL)))
4149 authors[i_authors] = g_strdup(author_line);
4151 g_free(author_line);
4153 authors[i_authors] = NULL;
4155 g_input_stream_close(in_stream_authors, NULL, NULL);
4157 translators_path = g_build_filename(GQ_RESOURCE_PATH_CREDITS, "translators", NULL);
4159 g_resources_get_info(translators_path, G_RESOURCE_LOOKUP_FLAGS_NONE, &size, &flags, NULL);
4161 in_stream_translators = g_resources_open_stream(translators_path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
4162 translators = static_cast<gchar *>(g_malloc0(size));
4163 g_input_stream_read_all(in_stream_translators, translators, size, &bytes_read, NULL, NULL);
4164 g_input_stream_close(in_stream_translators, NULL, NULL);
4166 comment = g_strconcat("Project created by John Ellis\nGQview 1998\nGeeqie 2007\n\n\nDevelopment and bug reports:\n", GQ_EMAIL_ADDRESS, "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
4168 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
4169 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
4170 gtk_show_about_dialog(GTK_WINDOW(lw->window),
4171 "title", _("About Geeqie"),
4173 "program-name", GQ_APPNAME,
4175 "logo", pixbuf_logo,
4176 "icon", pixbuf_icon,
4177 "website", GQ_WEBSITE,
4178 "website-label", "Website",
4179 "comments", comment,
4181 "translator-credits", translators,
4182 "wrap-license", TRUE,
4183 "license", copyright->str,
4186 g_string_free(copyright, TRUE);
4188 while(n < i_authors)
4194 g_free(authors_path);
4196 g_free(translators);
4197 g_free(translators_path);
4198 g_object_unref(data_stream);
4199 g_object_unref(in_stream_authors);
4200 g_object_unref(in_stream_translators);
4205 static void image_overlay_set_text_colours()
4207 c_options->image_overlay.text_red = options->image_overlay.text_red;
4208 c_options->image_overlay.text_green = options->image_overlay.text_green;
4209 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
4210 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
4211 c_options->image_overlay.background_red = options->image_overlay.background_red;
4212 c_options->image_overlay.background_green = options->image_overlay.background_green;
4213 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
4214 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
4218 *-----------------------------------------------------------------------------
4219 * timezone database routines
4220 *-----------------------------------------------------------------------------
4223 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
4225 GError *error = NULL;
4226 TZData *tz = static_cast<TZData *>(data);
4227 gchar *tmp_filename;
4228 gchar *timezone_bin;
4229 gchar *tmp_dir = NULL;
4232 if (!g_cancellable_is_cancelled(tz->cancellable))
4234 generic_dialog_close(tz->gd);
4238 if (g_file_copy_finish(G_FILE(source_object), res, &error))
4240 tmp_filename = g_file_get_path(tz->tmp_g_file);
4241 fd = file_data_new_simple(tmp_filename);
4242 tmp_dir = open_archive(fd);
4246 timezone_bin = g_build_filename(tmp_dir, TIMEZONE_DATABASE_VERSION, TIMEZONE_DATABASE_FILE, NULL);
4247 if (isfile(timezone_bin))
4249 move_file(timezone_bin, tz->timezone_database_user);
4253 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GTK_STOCK_DIALOG_WARNING, NULL);
4256 g_free(timezone_bin);
4257 g_free(tmp_dir); // The folder in /tmp is deleted in exit_program_final()
4261 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GTK_STOCK_DIALOG_WARNING, NULL);
4263 g_free(tmp_filename);
4264 file_data_unref(fd);
4268 file_util_warning_dialog(_("Error: Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4271 g_file_delete(tz->tmp_g_file, NULL, &error);
4272 g_object_unref(tz->tmp_g_file);
4273 tz->tmp_g_file = NULL;
4274 g_object_unref(tz->cancellable);
4275 g_object_unref(tz->timezone_database_gq);
4278 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
4280 TZData *tz = static_cast<TZData *>(data);
4282 if (!g_cancellable_is_cancelled(tz->cancellable))
4284 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
4288 static void timezone_cancel_button_cb(GenericDialog *UNUSED(gd), gpointer data)
4290 TZData *tz = static_cast<TZData *>(data);
4292 g_cancellable_cancel(tz->cancellable);
4295 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
4297 TZData *tz = static_cast<TZData *>(data);
4298 GError *error = NULL;
4299 GFileIOStream *io_stream;
4306 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
4310 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4311 log_printf("Error: Download timezone database failed:\n%s", error->message);
4312 g_error_free(error);
4313 g_object_unref(tz->tmp_g_file);
4317 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE_WEB);
4319 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
4321 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
4323 tz->progress = gtk_progress_bar_new();
4324 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
4325 gtk_widget_show(tz->progress);
4327 gtk_widget_show(tz->gd->dialog);
4328 tz->cancellable = g_cancellable_new();
4329 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);
4331 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
4334 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */