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_clear_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_clear_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_clear_selection, NULL);
1776 static void accel_reset_cb(GtkWidget *UNUSED(widget), gpointer data)
1778 GtkTreeSelection *selection;
1780 if (!accel_store) return;
1781 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1782 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1787 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1791 GtkWidget *scrolled;
1792 GtkWidget *viewport;
1794 scrolled = gtk_scrolled_window_new(NULL, NULL);
1795 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1796 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1797 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1798 label = gtk_label_new(title);
1799 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1800 gtk_widget_show(scrolled);
1802 viewport = gtk_viewport_new(NULL, NULL);
1803 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1804 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1805 gtk_widget_show(viewport);
1807 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
1808 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1809 gtk_widget_show(vbox);
1814 static void cache_standard_cb(GtkWidget *widget, gpointer UNUSED(data))
1816 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1818 c_options->thumbnails.spec_standard =TRUE;
1819 c_options->thumbnails.cache_into_dirs = FALSE;
1823 static void cache_geeqie_cb(GtkWidget *widget, gpointer UNUSED(data))
1825 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1827 c_options->thumbnails.spec_standard =FALSE;
1828 c_options->thumbnails.cache_into_dirs = FALSE;
1832 static void cache_local_cb(GtkWidget *widget, gpointer UNUSED(data))
1834 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1836 c_options->thumbnails.cache_into_dirs = TRUE;
1837 c_options->thumbnails.spec_standard =FALSE;
1841 static void help_search_engine_entry_icon_cb(GtkEntry *UNUSED(entry), GtkEntryIconPosition pos,
1842 GdkEvent *UNUSED(event), gpointer userdata)
1844 if (pos == GTK_ENTRY_ICON_PRIMARY)
1846 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1850 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1854 static void star_rating_star_icon_cb(GtkEntry *UNUSED(entry), GtkEntryIconPosition pos,
1855 GdkEvent *UNUSED(event), gpointer userdata)
1857 gchar *rating_symbol;
1859 if (pos == GTK_ENTRY_ICON_PRIMARY)
1861 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1862 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1863 g_free(rating_symbol);
1867 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1868 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1869 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1873 static void star_rating_rejected_icon_cb(GtkEntry *UNUSED(entry), GtkEntryIconPosition pos,
1874 GdkEvent *UNUSED(event), gpointer userdata)
1876 gchar *rating_symbol;
1878 if (pos == GTK_ENTRY_ICON_PRIMARY)
1880 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1881 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1882 g_free(rating_symbol);
1886 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1887 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1888 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1892 static guint star_rating_symbol_test(GtkWidget *UNUSED(widget), gpointer data)
1894 GtkContainer *hbox = static_cast<GtkContainer *>(data);
1895 GString *str = g_string_new(NULL);
1896 GtkEntry *hex_code_entry;
1897 gchar *hex_code_full;
1900 guint64 hex_value = 0;
1902 list = gtk_container_get_children(hbox);
1904 hex_code_entry = static_cast<GtkEntry *>(g_list_nth_data(list, 2));
1905 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1907 hex_code = g_strsplit(hex_code_full, "+", 2);
1908 if (hex_code[0] && hex_code[1])
1910 hex_value = strtoull(hex_code[1], NULL, 16);
1912 if (!hex_value || hex_value > 0x10FFFF)
1914 hex_value = 0x003F; // Unicode 'Question Mark'
1916 str = g_string_append_unichar(str, (gunichar)hex_value);
1917 gtk_label_set_text(static_cast<GtkLabel *>(g_list_nth_data(list, 1)), str->str);
1919 g_strfreev(hex_code);
1920 g_string_free(str, TRUE);
1921 g_free(hex_code_full);
1926 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1928 guint64 star_symbol;
1930 star_symbol = star_rating_symbol_test(widget, data);
1931 c_options->star_rating.star = star_symbol;
1934 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1936 guint64 rejected_symbol;
1938 rejected_symbol = star_rating_symbol_test(widget, data);
1939 c_options->star_rating.rejected = rejected_symbol;
1942 /* general options tab */
1943 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1944 typedef struct _TZData TZData;
1948 GCancellable *cancellable;
1950 GtkWidget *progress;
1952 GFile *timezone_database_gq;
1953 gchar *timezone_database_user;
1956 static void config_tab_general(GtkWidget *notebook)
1961 GtkWidget *group_frame;
1962 GtkWidget *subgroup;
1964 GtkWidget *ct_button;
1967 gint hours, minutes, remainder;
1969 GtkWidget *star_rating_entry;
1971 gchar *rating_symbol;
1974 gchar *download_locn;
1975 GNetworkMonitor *net_mon;
1976 GSocketConnectable *tz_org;
1977 gboolean internet_available = FALSE;
1980 vbox = scrolled_notebook_page(notebook, _("General"));
1982 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1984 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1985 add_thumb_size_menu(table, 0, 0, _("Size:"));
1986 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1988 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1989 pref_label_new(hbox, _("Custom size: "));
1990 pref_spin_new_int(hbox, _("Width:"), NULL, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
1991 pref_spin_new_int(hbox, _("Height:"), NULL, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
1993 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
1994 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1996 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1997 pref_checkbox_link_sensitivity(ct_button, subgroup);
1999 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
2000 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
2001 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
2002 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2003 button = pref_radiobutton_new(group_frame, NULL, get_thumbnails_cache_dir(),
2004 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2005 G_CALLBACK(cache_geeqie_cb), NULL);
2007 group_frame = pref_frame_new(subgroup, TRUE,
2008 _("Store thumbnails local to image folder (non-standard)"),
2009 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2010 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
2011 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
2012 G_CALLBACK(cache_local_cb), NULL);
2014 group_frame = pref_frame_new(subgroup, TRUE,
2015 _("Use standard thumbnail style and cache, shared with other applications"),
2016 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2017 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
2018 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2019 G_CALLBACK(cache_standard_cb), NULL);
2021 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
2022 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
2024 pref_checkbox_new_int(group, _("Thumbnail color management"),
2025 options->thumbnails.use_color_management, &c_options->thumbnails.use_color_management);
2027 spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
2029 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
2030 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
2032 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
2033 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
2034 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
2036 // pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
2037 // options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
2040 pref_spacer(group, PREF_PAD_GROUP);
2042 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
2044 c_options->star_rating.star = options->star_rating.star;
2045 c_options->star_rating.rejected = options->star_rating.rejected;
2047 str = g_string_new(NULL);
2048 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2049 pref_label_new(hbox, _("Star character: "));
2050 str = g_string_append_unichar(str, options->star_rating.star);
2051 pref_label_new(hbox, g_strdup(str->str));
2052 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
2053 star_rating_entry = gtk_entry_new();
2054 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2055 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2056 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2057 gtk_widget_show(star_rating_entry);
2058 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2059 G_CALLBACK(star_rating_star_test_cb), hbox);
2060 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2061 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2062 gtk_widget_show(button);
2063 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."));
2064 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2065 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2066 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2067 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2068 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2069 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2070 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2071 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2072 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2073 G_CALLBACK(star_rating_star_icon_cb),
2076 g_string_free(str, TRUE);
2077 g_free(rating_symbol);
2079 str = g_string_new(NULL);
2080 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2081 pref_label_new(hbox, _("Rejected character: "));
2082 str = g_string_append_unichar(str, options->star_rating.rejected);
2083 pref_label_new(hbox, g_strdup(str->str));
2084 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2085 star_rating_entry = gtk_entry_new();
2086 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2087 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2088 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2089 gtk_widget_show(star_rating_entry);
2090 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2091 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2092 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2093 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2094 gtk_widget_show(button);
2095 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."));
2096 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2097 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2098 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2099 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2100 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2101 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2102 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2103 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2104 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2105 G_CALLBACK(star_rating_rejected_icon_cb),
2108 g_string_free(str, TRUE);
2109 g_free(rating_symbol);
2111 pref_spacer(group, PREF_PAD_GROUP);
2113 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2115 c_options->slideshow.delay = options->slideshow.delay;
2116 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2117 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2118 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2119 seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2120 SLIDESHOW_SUBSECOND_PRECISION;
2122 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2124 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2126 options->slideshow.delay ? hours : 0.0,
2127 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2128 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2129 spin = pref_spin_new(hbox, ":" , NULL,
2131 options->slideshow.delay ? minutes: 0.0,
2132 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2133 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2134 spin = pref_spin_new(hbox, ":", NULL,
2135 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2136 options->slideshow.delay ? seconds : 10.0,
2137 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2138 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2140 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2141 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2143 pref_spacer(group, PREF_PAD_GROUP);
2145 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2147 pref_spin_new_int(group, _("Decoded image cache size (MiB):"), NULL,
2148 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2149 pref_checkbox_new_int(group, _("Preload next image"),
2150 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2152 pref_checkbox_new_int(group, _("Refresh on file change"),
2153 options->update_on_time_change, &c_options->update_on_time_change);
2156 pref_spacer(group, PREF_PAD_GROUP);
2158 group = pref_group_new(vbox, FALSE, _("Expand menu and toolbar"), GTK_ORIENTATION_VERTICAL);
2160 pref_checkbox_new_int(group, _("Expand menu and toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2161 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2162 gtk_widget_set_tooltip_text(group, _("Expand the menu and toolbar to the full width of the window"));
2164 pref_spacer(group, PREF_PAD_GROUP);
2166 if (g_getenv("APPDIR") && strstr(g_getenv("APPDIR"), "/tmp/.mount_Geeqie"))
2168 group = pref_group_new(vbox, FALSE, _("AppImage updates notifications"), GTK_ORIENTATION_VERTICAL);
2169 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2170 pref_checkbox_new_int(group, _("Enable"), options->appimage_notifications, &c_options->appimage_notifications);
2171 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"));
2173 pref_spacer(group, PREF_PAD_GROUP);
2177 net_mon = g_network_monitor_get_default();
2178 tz_org = g_network_address_parse_uri(TIMEZONE_DATABASE_WEB, 80, NULL);
2181 internet_available = g_network_monitor_can_reach(net_mon, tz_org, NULL, NULL);
2182 g_object_unref(tz_org);
2185 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2186 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2188 if (!internet_available)
2190 gtk_widget_set_sensitive(group, FALSE);
2193 tz = g_new0(TZData, 1);
2195 path = path_from_utf8(TIMEZONE_DATABASE_WEB);
2196 basename = g_path_get_basename(path);
2197 tz->timezone_database_user = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
2201 if (isfile(tz->timezone_database_user))
2203 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2207 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2210 download_locn = g_strconcat(_("Download database from: "), TIMEZONE_DATABASE_WEB, NULL);
2211 pref_label_new(GTK_WIDGET(hbox), download_locn);
2212 g_free(download_locn);
2214 if (!internet_available)
2216 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"));
2220 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"));
2222 gtk_widget_show(button);
2224 pref_spacer(group, PREF_PAD_GROUP);
2226 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2228 help_search_engine_entry = gtk_entry_new();
2229 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2230 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2231 gtk_widget_show(help_search_engine_entry);
2233 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"));
2235 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2236 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2237 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2238 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2239 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2240 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2241 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2242 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2243 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2244 G_CALLBACK(help_search_engine_entry_icon_cb),
2245 help_search_engine_entry);
2249 static void config_tab_image(GtkWidget *notebook)
2254 GtkWidget *ct_button;
2255 GtkWidget *enlargement_button;
2258 //~ #ifdef HAVE_CLUTTER
2259 //~ GtkWidget *gpu_accel;
2262 vbox = scrolled_notebook_page(notebook, _("Image"));
2264 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2266 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2267 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2268 //~ if (options->image.use_clutter_renderer && !options->disable_gpu)
2270 //~ gtk_widget_set_sensitive(table, FALSE);
2273 //~ #ifdef HAVE_CLUTTER
2274 //~ gpu_accel = pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library (Requires restart)"),
2275 //~ options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2276 //~ if (options->disable_gpu && !options->override_disable_gpu)
2278 //~ gtk_widget_set_sensitive(gpu_accel, FALSE);
2282 pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2283 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2284 //~ if (options->image.use_clutter_renderer && !options->disable_gpu)
2286 //~ gtk_widget_set_sensitive(two_pass, FALSE);
2289 c_options->image.zoom_increment = options->image.zoom_increment;
2290 spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2291 0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2292 G_CALLBACK(zoom_increment_cb), NULL);
2293 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2295 c_options->image.zoom_style = options->image.zoom_style;
2296 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2297 add_zoom_style_selection_menu(table, 0, 0, _("Zoom style:"), options->image.zoom_style, &c_options->image.zoom_style);
2299 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2301 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2302 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2303 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2304 spin = pref_spin_new_int(hbox, NULL, NULL,
2306 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2307 pref_checkbox_link_sensitivity(enlargement_button, spin);
2308 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."));
2310 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2311 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2312 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2313 spin = pref_spin_new_int(hbox, NULL, NULL,
2315 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2316 pref_checkbox_link_sensitivity(ct_button, spin);
2317 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."));
2319 group = pref_group_new(vbox, FALSE, _("Tile size"), GTK_ORIENTATION_VERTICAL);
2320 //~ gtk_widget_set_sensitive(group, !options->image.use_clutter_renderer);
2322 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2323 spin = pref_spin_new_int(hbox, _("Pixels"), _("(Requires restart)"),
2325 options->image.tile_size, &c_options->image.tile_size);
2326 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."));
2328 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2330 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2331 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2333 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2334 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2336 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2337 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2339 c_options->image.border_color = options->image.border_color;
2341 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2342 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2344 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2345 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2347 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2348 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2353 static void save_default_window_layout_cb(GtkWidget *UNUSED(widget), gpointer UNUSED(data))
2355 LayoutWindow *lw = NULL;
2356 gchar *default_path;
2359 /* Get current lw */
2362 tmp_id = lw->options.id;
2363 lw->options.id = g_strdup("lw_default");
2365 default_path = g_build_filename(get_rc_dir(), DEFAULT_WINDOW_LAYOUT, NULL);
2366 save_default_layout_options_to_file(default_path, options, lw);
2367 g_free(lw->options.id);
2368 lw->options.id = tmp_id;
2369 g_free(default_path);
2372 static gboolean popover_cb(gpointer data)
2374 GtkPopover *popover = static_cast<GtkPopover *>(data);
2376 gtk_popover_popdown(popover);
2381 static void default_layout_changed_cb(GtkWidget *UNUSED(button), GtkPopover *popover)
2383 gtk_popover_popup(popover);
2385 g_timeout_add(2000, popover_cb, popover);
2388 static GtkWidget *create_popover(GtkWidget *parent, GtkWidget *child, GtkPositionType pos)
2392 popover = gtk_popover_new(parent);
2393 gtk_popover_set_position(GTK_POPOVER (popover), pos);
2394 gtk_container_add (GTK_CONTAINER(popover), child);
2395 gtk_container_set_border_width(GTK_CONTAINER (popover), 6);
2396 gtk_widget_show (child);
2401 static void config_tab_windows(GtkWidget *notebook)
2406 GtkWidget *subgroup;
2408 GtkWidget *ct_button;
2411 vbox = scrolled_notebook_page(notebook, _("Windows"));
2413 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2415 ct_button = pref_checkbox_new_int(group, _("Remember session"),
2416 options->save_window_positions, &c_options->save_window_positions);
2418 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2419 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2420 pref_checkbox_link_sensitivity(ct_button, button);
2422 button = pref_checkbox_new_int(group, _("Remember window workspace"),
2423 options->save_window_workspace, &c_options->save_window_workspace);
2424 pref_checkbox_link_sensitivity(ct_button, button);
2426 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2427 options->tools_restore_state, &c_options->tools_restore_state);
2429 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2430 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2432 pref_checkbox_new_int(group, _("Show window IDs"),
2433 options->show_window_ids, &c_options->show_window_ids);
2435 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2436 pref_label_new(subgroup, _("Use current layout for default: "));
2437 button = pref_button_new(subgroup, NULL, _("Set"), FALSE, G_CALLBACK(save_default_window_layout_cb), NULL);
2441 popover = create_popover(button, gtk_label_new(_("Current window layout\nhas been set as default")), GTK_POS_TOP);
2442 gtk_popover_set_modal(GTK_POPOVER (popover), FALSE);
2443 g_signal_connect(button, "clicked", G_CALLBACK(default_layout_changed_cb), popover);
2445 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2447 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2448 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2450 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2451 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2452 options->image.limit_window_size, &c_options->image.limit_window_size);
2453 spin = pref_spin_new_int(hbox, NULL, NULL,
2455 options->image.max_window_size, &c_options->image.max_window_size);
2456 pref_checkbox_link_sensitivity(ct_button, spin);
2458 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2460 c_options->fullscreen.screen = options->fullscreen.screen;
2461 c_options->fullscreen.above = options->fullscreen.above;
2462 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2463 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2464 gtk_widget_show(hbox);
2466 pref_checkbox_new_int(group, _("Smooth image flip"),
2467 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2468 pref_checkbox_new_int(group, _("Disable screen saver"),
2469 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2472 #define PRE_FORMATTED_COLUMNS 5
2473 static void config_tab_osd(GtkWidget *notebook)
2479 GtkWidget *image_overlay_template_view;
2480 GtkWidget *scrolled;
2481 GtkWidget *scrolled_pre_formatted;
2482 GtkTextBuffer *buffer;
2484 GtkWidget *subgroup;
2486 vbox = scrolled_notebook_page(notebook, _("OSD"));
2488 image_overlay_template_view = gtk_text_view_new();
2490 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2492 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2494 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2495 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2496 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2497 gtk_widget_show(scrolled_pre_formatted);
2498 gtk_widget_show(subgroup);
2500 pref_line(group, PREF_PAD_GAP);
2502 pref_label_new(group, _("Image overlay template"));
2504 scrolled = gtk_scrolled_window_new(NULL, NULL);
2505 gtk_widget_set_size_request(scrolled, 200, 150);
2506 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2507 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2508 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2509 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2510 gtk_widget_show(scrolled);
2512 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2513 _("Extensive formatting options are shown in the Help file"));
2515 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2516 gtk_widget_show(image_overlay_template_view);
2518 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2520 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2521 G_CALLBACK(image_overlay_set_font_cb), notebook);
2523 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2524 gtk_widget_show(button);
2526 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2527 G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2528 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2529 gtk_widget_show(button);
2531 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2532 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2533 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2534 gtk_widget_show(button);
2535 image_overlay_set_text_colours();
2537 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2538 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2539 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2540 gtk_widget_show(button);
2542 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2543 G_CALLBACK(image_overlay_help_cb), NULL);
2544 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2545 gtk_widget_show(button);
2547 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2548 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2549 g_signal_connect(G_OBJECT(buffer), "changed",
2550 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2552 pref_line(group, PREF_PAD_GAP);
2554 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), 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(_("%Exif.Image.Orientation%"));
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 separators"), 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(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
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, _("Field maximum length"), 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(_("%path:39%"));
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, _("Pre- and post- text"), 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(_("Text shown only if the field is non-null:\n%formatted.Aperture:F no. * setting%\n %formatted.Aperture:10:F no. * setting%"));
2586 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2587 gtk_widget_show(label);
2588 pref_spacer(group,TRUE);
2590 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2591 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2592 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2593 gtk_widget_show(hbox);
2594 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2595 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2596 gtk_widget_show(label);
2599 static GtkTreeModel *create_class_model(void)
2601 GtkListStore *model;
2605 /* create list store */
2606 model = gtk_list_store_new(1, G_TYPE_STRING);
2607 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2609 gtk_list_store_append(model, &iter);
2610 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2612 return GTK_TREE_MODEL (model);
2617 static gint filter_table_sort_cb(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data)
2619 gint n = GPOINTER_TO_INT(data);
2621 FilterEntry *filter_a;
2622 FilterEntry *filter_b;
2624 gtk_tree_model_get(model, a, 0, &filter_a, -1);
2625 gtk_tree_model_get(model, b, 0, &filter_b, -1);
2629 case FILETYPES_COLUMN_ENABLED:
2631 ret = filter_a->enabled - filter_b->enabled;
2634 case FILETYPES_COLUMN_FILTER:
2636 ret = g_utf8_collate(filter_a->extensions, filter_b->extensions);
2639 case FILETYPES_COLUMN_DESCRIPTION:
2641 ret = g_utf8_collate(filter_a->description, filter_b->description);
2644 case FILETYPES_COLUMN_CLASS:
2646 ret = g_strcmp0(format_class_list[filter_a->file_class], format_class_list[filter_b->file_class]);
2649 case FILETYPES_COLUMN_WRITABLE:
2651 ret = filter_a->writable - filter_b->writable;
2654 case FILETYPES_COLUMN_SIDECAR:
2656 ret = filter_a->allow_sidecar - filter_b->allow_sidecar;
2660 g_return_val_if_reached(0);
2666 static gboolean search_function_cb(GtkTreeModel *model, gint UNUSED(column), const gchar *key, GtkTreeIter *iter, gpointer UNUSED(search_data))
2669 gboolean ret = TRUE;
2671 gtk_tree_model_get(model, iter, 0, &fe, -1);
2673 if (g_strstr_len(fe->extensions, -1, key))
2681 static void config_tab_files(GtkWidget *notebook)
2688 GtkWidget *ct_button;
2689 GtkWidget *scrolled;
2690 GtkWidget *filter_view;
2691 GtkCellRenderer *renderer;
2692 GtkTreeSelection *selection;
2693 GtkTreeViewColumn *column;
2695 vbox = scrolled_notebook_page(notebook, _("File Filters"));
2697 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2699 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2700 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2701 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2702 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2703 pref_checkbox_new_int(group, _("Case sensitive sort"),
2704 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2705 pref_checkbox_new_int(group, _("Natural sort order - Requires restart"),
2706 options->file_sort.natural, &c_options->file_sort.natural);
2707 pref_checkbox_new_int(group, _("Disable file extension checks"),
2708 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2710 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2711 options->file_filter.disable, &c_options->file_filter.disable);
2714 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2716 sidecar_ext_entry = gtk_entry_new();
2717 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2718 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2719 gtk_widget_show(sidecar_ext_entry);
2721 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2723 frame = pref_group_parent(group);
2724 g_signal_connect(G_OBJECT(ct_button), "toggled",
2725 G_CALLBACK(filter_disable_cb), frame);
2726 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2728 scrolled = gtk_scrolled_window_new(NULL, NULL);
2729 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2730 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2731 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2732 gtk_widget_show(scrolled);
2734 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2735 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2736 g_object_unref(filter_store);
2737 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2738 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2740 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2742 column = gtk_tree_view_column_new();
2743 gtk_tree_view_column_set_title(column, _("Enabled"));
2744 gtk_tree_view_column_set_resizable(column, TRUE);
2746 renderer = gtk_cell_renderer_toggle_new();
2747 g_signal_connect(G_OBJECT(renderer), "toggled",
2748 G_CALLBACK(filter_store_enable_cb), filter_store);
2749 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2750 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2751 GINT_TO_POINTER(FE_ENABLE), NULL);
2752 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);
2753 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_ENABLED);
2754 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2756 column = gtk_tree_view_column_new();
2757 gtk_tree_view_column_set_title(column, _("Filter"));
2758 gtk_tree_view_column_set_resizable(column, TRUE);
2759 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);
2760 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_FILTER);
2762 renderer = gtk_cell_renderer_text_new();
2763 g_signal_connect(G_OBJECT(renderer), "edited",
2764 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2765 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2766 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2767 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2768 GINT_TO_POINTER(FE_EXTENSION), NULL);
2769 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2771 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), TRUE);
2772 gtk_tree_view_set_search_column(GTK_TREE_VIEW(filter_view), FILETYPES_COLUMN_FILTER);
2773 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(filter_view), search_function_cb, NULL, NULL);
2775 column = gtk_tree_view_column_new();
2776 gtk_tree_view_column_set_title(column, _("Description"));
2777 gtk_tree_view_column_set_resizable(column, TRUE);
2778 gtk_tree_view_column_set_fixed_width(column, 200);
2779 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2781 renderer = gtk_cell_renderer_text_new();
2782 g_signal_connect(G_OBJECT(renderer), "edited",
2783 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2784 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2785 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2786 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2787 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2788 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2789 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);
2790 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_DESCRIPTION);
2792 column = gtk_tree_view_column_new();
2793 gtk_tree_view_column_set_title(column, _("Class"));
2794 gtk_tree_view_column_set_resizable(column, TRUE);
2795 renderer = gtk_cell_renderer_combo_new();
2796 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2797 "model", create_class_model(),
2802 g_signal_connect(G_OBJECT(renderer), "edited",
2803 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2804 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2805 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2806 GINT_TO_POINTER(FE_CLASS), NULL);
2807 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2808 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);
2809 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_CLASS);
2811 column = gtk_tree_view_column_new();
2812 gtk_tree_view_column_set_title(column, _("Writable"));
2813 gtk_tree_view_column_set_resizable(column, FALSE);
2814 renderer = gtk_cell_renderer_toggle_new();
2815 g_signal_connect(G_OBJECT(renderer), "toggled",
2816 G_CALLBACK(filter_store_writable_cb), filter_store);
2817 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2818 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2819 GINT_TO_POINTER(FE_WRITABLE), NULL);
2820 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2821 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);
2822 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_WRITABLE);
2824 column = gtk_tree_view_column_new();
2825 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2826 gtk_tree_view_column_set_resizable(column, FALSE);
2827 renderer = gtk_cell_renderer_toggle_new();
2828 g_signal_connect(G_OBJECT(renderer), "toggled",
2829 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2830 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2831 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2832 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2833 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2834 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_SIDECAR, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_SIDECAR), NULL);
2835 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_SIDECAR);
2837 filter_store_populate();
2838 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2839 gtk_widget_show(filter_view);
2841 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2843 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2844 G_CALLBACK(filter_default_cb), filter_view);
2845 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2846 gtk_widget_show(button);
2848 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2849 G_CALLBACK(filter_remove_cb), filter_view);
2850 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2851 gtk_widget_show(button);
2853 button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2854 G_CALLBACK(filter_add_cb), filter_view);
2855 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2856 gtk_widget_show(button);
2860 static void config_tab_metadata(GtkWidget *notebook)
2865 GtkWidget *ct_button;
2867 GtkWidget *tmp_widget;
2869 GtkWidget *text_label;
2871 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2874 group = pref_group_new(vbox, FALSE, _("Metadata writing sequence"), GTK_ORIENTATION_VERTICAL);
2876 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2878 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."));
2879 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2880 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2882 gtk_widget_set_tooltip_text(label, _("A flowchart of the sequence is shown in the Help file"));
2884 ct_button = pref_checkbox_new_int(group, "", options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2885 text_label = gtk_bin_get_child(GTK_BIN(ct_button));
2886 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"));
2887 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2889 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)"));
2890 gtk_widget_set_tooltip_markup(ct_button, markup);
2894 gtk_widget_set_sensitive(ct_button, FALSE);
2897 tmp_widget = pref_checkbox_new_int(group, "", options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2898 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2899 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)"));
2900 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2903 label = pref_label_new(group, "");
2904 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(), "/");
2905 gtk_label_set_markup (GTK_LABEL(label), markup);
2908 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2909 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2910 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2911 pref_spacer(group, PREF_PAD_GROUP);
2913 group = pref_group_new(vbox, FALSE, _("Step 1 Options:"), GTK_ORIENTATION_VERTICAL);
2915 gtk_widget_set_sensitive(group, FALSE);
2918 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2919 pref_checkbox_link_sensitivity(ct_button, hbox);
2921 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);
2922 gtk_widget_set_tooltip_text(tmp_widget, _("A simplified conversion list is in the Help file"));
2924 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);
2926 pref_checkbox_new_int(hbox, _("Ask before writing to image files"), options->metadata.confirm_write, &c_options->metadata.confirm_write);
2928 tmp_widget= pref_checkbox_new_int(hbox, "", options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2929 gtk_widget_set_tooltip_text(tmp_widget, _("This file naming convention is used by Darktable"));
2930 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2931 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", ")");
2932 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2935 pref_spacer(group, PREF_PAD_GROUP);
2937 group = pref_group_new(vbox, FALSE, _("Steps 2 and 3 Option:"), GTK_ORIENTATION_VERTICAL);
2939 gtk_widget_set_sensitive(group, FALSE);
2942 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);
2944 pref_spacer(group, PREF_PAD_GROUP);
2946 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2947 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);
2948 gtk_widget_set_tooltip_text(tmp_widget, _("See the Help file for a list of the tags used"));
2950 tmp_widget = pref_checkbox_new_int(group, _("Permit Keywords to be case-sensitive"), options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2951 gtk_widget_set_tooltip_text(tmp_widget, _("When selected, \"Place\" and \"place\" are two different keywords"));
2953 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"), options->metadata.write_orientation, &c_options->metadata.write_orientation);
2954 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"));
2957 gtk_widget_set_sensitive(ct_button, FALSE);
2960 pref_spacer(group, PREF_PAD_GROUP);
2962 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2964 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"), options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2966 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2967 pref_checkbox_link_sensitivity(ct_button, hbox);
2969 pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1, options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2971 pref_checkbox_new_int(group, _("Write metadata on image change"), options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2973 pref_checkbox_new_int(group, _("Write metadata on directory change"), options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2975 pref_spacer(group, PREF_PAD_GROUP);
2978 group = pref_group_new(vbox, FALSE, _("Spelling checks"), GTK_ORIENTATION_VERTICAL);
2980 ct_button = pref_checkbox_new_int(group, _("Check spelling - Requires restart"), options->metadata.check_spelling, &c_options->metadata.check_spelling);
2981 gtk_widget_set_tooltip_text(ct_button, _("Spelling checks are performed on info sidebar panes Comment, Headline and Title"));
2984 pref_spacer(group, PREF_PAD_GROUP);
2986 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2988 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"), options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2989 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");
2994 typedef struct _KeywordFindData KeywordFindData;
2995 struct _KeywordFindData
3002 GtkWidget *button_close;
3003 GtkWidget *button_stop;
3004 GtkWidget *button_start;
3005 GtkWidget *progress;
3013 guint idle_id; /* event source id */
3016 #define KEYWORD_DIALOG_WIDTH 400
3018 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
3020 GList *list_d = NULL;
3021 GList *list_f = NULL;
3025 filelist_read(dir_fd, &list_f, &list_d);
3029 filelist_read(dir_fd, &list_f, NULL);
3032 list_f = filelist_filter(list_f, FALSE);
3033 list_d = filelist_filter(list_d, TRUE);
3035 kfd->list = g_list_concat(list_f, kfd->list);
3036 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
3039 static void keywords_find_reset(KeywordFindData *kfd)
3041 filelist_free(kfd->list);
3044 filelist_free(kfd->list_dir);
3045 kfd->list_dir = NULL;
3048 static void keywords_find_close_cb(GenericDialog *UNUSED(fd), gpointer data)
3050 KeywordFindData *kfd = static_cast<KeywordFindData *>(data);
3052 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
3054 keywords_find_reset(kfd);
3055 generic_dialog_close(kfd->gd);
3059 static void keywords_find_finish(KeywordFindData *kfd)
3061 keywords_find_reset(kfd);
3063 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
3064 spinner_set_interval(kfd->spinner, -1);
3066 gtk_widget_set_sensitive(kfd->group, TRUE);
3067 gtk_widget_set_sensitive(kfd->button_start, TRUE);
3068 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3069 gtk_widget_set_sensitive(kfd->button_close, TRUE);
3072 static void keywords_find_stop_cb(GenericDialog *UNUSED(fd), gpointer data)
3074 KeywordFindData *kfd = static_cast<KeywordFindData *>(data);
3076 g_idle_remove_by_data(kfd);
3078 keywords_find_finish(kfd);
3081 static gboolean keywords_find_file(gpointer data)
3083 KeywordFindData *kfd = static_cast<KeywordFindData *>(data);
3085 GtkTextBuffer *buffer;
3093 fd = static_cast<FileData *>(kfd->list->data);
3094 kfd->list = g_list_remove(kfd->list, fd);
3096 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
3097 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3101 gtk_text_buffer_get_end_iter(buffer, &iter);
3102 tmp = g_strconcat(static_cast<const gchar *>(keywords->data), "\n", NULL);
3103 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3105 keywords = keywords->next;
3108 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
3109 file_data_unref(fd);
3110 string_list_free(keywords);
3114 else if (kfd->list_dir)
3118 fd = static_cast<FileData *>(kfd->list_dir->data);
3119 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
3121 keywords_find_folder(kfd, fd);
3123 file_data_unref(fd);
3128 keywords_find_finish(kfd);
3133 static void keywords_find_start_cb(GenericDialog *UNUSED(fd), gpointer data)
3135 KeywordFindData *kfd = static_cast<KeywordFindData *>(data);
3138 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
3140 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
3141 parse_out_relatives(path);
3145 warning_dialog(_("Invalid folder"),
3146 _("The specified folder can not be found."),
3147 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
3153 gtk_widget_set_sensitive(kfd->group, FALSE);
3154 gtk_widget_set_sensitive(kfd->button_start, FALSE);
3155 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
3156 gtk_widget_set_sensitive(kfd->button_close, FALSE);
3157 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
3159 dir_fd = file_data_new_dir(path);
3160 keywords_find_folder(kfd, dir_fd);
3161 file_data_unref(dir_fd);
3162 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
3168 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
3170 KeywordFindData *kfd;
3174 kfd = g_new0(KeywordFindData, 1);
3176 kfd->gd = generic_dialog_new(_("Search for keywords"),
3177 "search_for_keywords",
3180 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
3181 kfd->gd->cancel_cb = keywords_find_close_cb;
3182 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
3183 keywords_find_close_cb, FALSE);
3184 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
3185 keywords_find_start_cb, FALSE);
3186 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
3187 keywords_find_stop_cb, FALSE);
3188 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3190 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
3192 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
3193 pref_spacer(hbox, PREF_PAD_INDENT);
3194 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
3196 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3197 pref_label_new(hbox, _("Folder:"));
3199 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
3200 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
3201 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
3202 gtk_widget_show(label);
3204 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
3206 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
3207 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3209 kfd->progress = gtk_entry_new();
3210 gtk_widget_set_can_focus(kfd->progress, FALSE);
3211 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
3212 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
3213 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
3214 gtk_widget_show(kfd->progress);
3216 kfd->spinner = spinner_new(NULL, -1);
3217 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
3218 gtk_widget_show(kfd->spinner);
3222 gtk_widget_show(kfd->gd->dialog);
3225 static void keywords_find_cb(GtkWidget *widget, gpointer UNUSED(data))
3227 const gchar *path = layout_get_path(NULL);
3229 if (!path || !*path) path = homedir();
3230 keywords_find_dialog(widget, path);
3233 static void config_tab_keywords_save()
3235 GtkTextIter start, end;
3236 GtkTextBuffer *buffer;
3237 GList *kw_list = NULL;
3243 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3244 gtk_text_buffer_get_bounds(buffer, &start, &end);
3246 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3248 kw_split = strtok(buffer_text, "\n");
3249 while (kw_split != NULL)
3255 if (g_strcmp0(static_cast<const gchar *>(work->data), kw_split) == 0)
3264 kw_list = g_list_append(kw_list, g_strdup(kw_split));
3266 kw_split = strtok(NULL, "\n");
3269 keyword_list_set(kw_list);
3271 string_list_free(kw_list);
3272 g_free(buffer_text);
3275 static void config_tab_keywords(GtkWidget *notebook)
3281 GtkWidget *scrolled;
3283 GtkTextBuffer *buffer;
3286 GspellTextView *gspell_view;
3289 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3291 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3293 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3295 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
3296 G_CALLBACK(keywords_find_cb), keyword_text);
3297 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
3300 keyword_text = gtk_text_view_new();
3301 gtk_widget_set_size_request(keyword_text, 20, 20);
3302 scrolled = gtk_scrolled_window_new(NULL, NULL);
3303 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3304 gtk_widget_show(scrolled);
3307 if (options->metadata.check_spelling)
3309 gspell_view = gspell_text_view_get_from_gtk_text_view(GTK_TEXT_VIEW(keyword_text));
3310 gspell_text_view_basic_setup(gspell_view);
3314 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
3315 gtk_widget_show(keyword_text);
3317 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3319 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3320 gtk_text_buffer_create_tag(buffer, "monospace",
3321 "family", "monospace", NULL);
3323 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3324 gtk_text_buffer_get_start_iter(buffer, &iter);
3325 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3328 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3330 GList *kwl = keyword_list_get();
3331 kwl = g_list_first(kwl);
3334 gtk_text_buffer_get_end_iter (buffer, &iter);
3335 tmp = g_strconcat(static_cast<const gchar *>(kwl->data), "\n", NULL);
3336 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3341 gtk_text_buffer_set_modified(buffer, FALSE);
3348 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3350 gint *option = static_cast<gint *>(data);
3352 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3356 *option = INTENT_PERCEPTUAL;
3359 *option = INTENT_RELATIVE_COLORIMETRIC;
3362 *option = INTENT_SATURATION;
3365 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3370 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3371 gint option, gint *option_c)
3378 pref_table_label(table, column, row, text, 0.0);
3380 combo = gtk_combo_box_text_new();
3382 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3383 if (option == INTENT_PERCEPTUAL) current = 0;
3384 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3385 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3386 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3387 if (option == INTENT_SATURATION) current = 2;
3388 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3389 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3391 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3393 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3395 g_signal_connect(G_OBJECT(combo), "changed",
3396 G_CALLBACK(intent_menu_cb), option_c);
3398 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
3399 gtk_widget_show(combo);
3403 static void config_tab_color(GtkWidget *notebook)
3412 vbox = scrolled_notebook_page(notebook, _("Color management"));
3414 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3416 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3419 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3420 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3422 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3423 pref_label_bold(label, TRUE, FALSE);
3425 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3426 pref_label_bold(label, TRUE, FALSE);
3428 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3429 pref_label_bold(label, TRUE, FALSE);
3431 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3436 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3437 pref_table_label(table, 0, i + 1, buf, 1.0);
3440 entry = gtk_entry_new();
3441 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3442 if (options->color_profile.input_name[i])
3444 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3446 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3447 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), static_cast<GtkAttachOptions>(0), 0, 0);
3448 gtk_widget_show(entry);
3449 color_profile_input_name_entry[i] = entry;
3451 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3452 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3453 gtk_widget_set_size_request(entry, 160, -1);
3454 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3455 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), static_cast<GtkAttachOptions>(0), 0, 0);
3456 gtk_widget_show(tabcomp);
3457 color_profile_input_file_entry[i] = entry;
3460 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3462 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3464 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3465 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3467 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3469 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3470 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3471 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3472 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3473 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3475 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3477 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3479 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), static_cast<GtkAttachOptions>(0), 0, 0);
3481 gtk_widget_show(tabcomp);
3484 /* advanced entry tab */
3485 static void use_geeqie_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 = FALSE;
3490 c_options->file_ops.no_trash = FALSE;
3494 static void use_system_trash_cb(GtkWidget *widget, gpointer UNUSED(data))
3496 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3498 c_options->file_ops.use_system_trash = TRUE;
3499 c_options->file_ops.no_trash = FALSE;
3503 static void use_no_cache_cb(GtkWidget *widget, gpointer UNUSED(data))
3505 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3507 c_options->file_ops.no_trash = TRUE;
3511 static void config_tab_behavior(GtkWidget *notebook)
3518 GtkWidget *ct_button;
3522 GtkWidget *with_rename;
3523 GtkWidget *collections_on_top;
3524 GtkWidget *hide_window_in_fullscreen;
3525 GtkWidget *checkbox;
3528 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3530 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3532 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3533 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3534 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3535 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3536 pref_checkbox_new_int(group, _("Enable Delete key"),
3537 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3539 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3540 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3542 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3543 pref_checkbox_link_sensitivity(ct_button, hbox);
3545 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3546 pref_label_new(hbox, _("Folder:"));
3548 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3549 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3550 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3551 gtk_widget_show(tabcomp);
3553 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3554 pref_checkbox_link_sensitivity(ct_button, hbox);
3556 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3557 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MiB"),
3558 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3559 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3560 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3561 G_CALLBACK(safe_delete_view_cb), NULL);
3562 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3563 gtk_widget_show(button);
3565 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3566 G_CALLBACK(safe_delete_clear_cb), NULL);
3567 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3569 c_options->file_ops.no_trash = options->file_ops.no_trash;
3570 c_options->file_ops.use_system_trash = options->file_ops.use_system_trash;
3572 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3573 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3575 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3576 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3578 gtk_widget_show(button);
3580 pref_spacer(group, PREF_PAD_GROUP);
3583 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3585 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3586 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3588 pref_checkbox_new_int(group, _("In place renaming"),
3589 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3591 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3592 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3594 tmp = pref_checkbox_new_int(group, _("Circular selection lists"),
3595 options->circular_selection_lists, &c_options->circular_selection_lists);
3596 gtk_widget_set_tooltip_text(tmp, _("Traverse selection lists in a circular manner"));
3598 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3599 options->marks_save, &c_options->marks_save);
3600 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3602 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3603 options->with_rename, &c_options->with_rename);
3604 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3606 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3607 options->collections_on_top, &c_options->collections_on_top);
3608 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3610 hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3611 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3612 gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice");
3614 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3615 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3617 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);
3618 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."));
3620 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3621 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3623 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3624 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3626 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3627 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3629 pref_spacer(group, PREF_PAD_GROUP);
3631 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3633 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3634 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3635 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3636 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3637 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3638 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3639 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3640 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3641 pref_checkbox_new_int(group, _("Open archive by left click on image"),
3642 options->image_l_click_archive, &c_options->image_l_click_archive);
3643 pref_checkbox_new_int(group, _("Play video by left click on image"),
3644 options->image_l_click_video, &c_options->image_l_click_video);
3645 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3646 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3648 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3649 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3650 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3651 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3652 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3654 pref_spacer(group, PREF_PAD_GROUP);
3656 group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3658 checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3659 options->override_disable_gpu, &c_options->override_disable_gpu);
3660 gtk_widget_set_tooltip_text(checkbox, "Contact the developers for usage");
3663 pref_spacer(group, PREF_PAD_GROUP);
3665 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3667 pref_spin_new_int(group, _("Debug level:"), NULL,
3668 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3670 pref_checkbox_new_int(group, _("Timer data"),
3671 options->log_window.timer_data, &c_options->log_window.timer_data);
3673 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3674 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3678 /* accelerators tab */
3679 static void config_tab_accelerators(GtkWidget *notebook)
3685 GtkWidget *scrolled;
3686 GtkWidget *accel_view;
3687 GtkCellRenderer *renderer;
3688 GtkTreeSelection *selection;
3689 GtkTreeViewColumn *column;
3691 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3693 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3695 scrolled = gtk_scrolled_window_new(NULL, NULL);
3696 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3697 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3698 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3699 gtk_widget_show(scrolled);
3701 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3703 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3704 g_object_unref(accel_store);
3705 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3706 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3708 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3710 renderer = gtk_cell_renderer_text_new();
3712 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3717 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3718 gtk_tree_view_column_set_resizable(column, TRUE);
3719 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3722 renderer = gtk_cell_renderer_accel_new();
3723 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3724 G_CALLBACK(accel_store_cleared_cb), accel_store);
3725 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3726 G_CALLBACK(accel_store_edited_cb), accel_store);
3729 g_object_set (renderer,
3731 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3734 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3739 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3740 gtk_tree_view_column_set_resizable(column, TRUE);
3741 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3743 renderer = gtk_cell_renderer_text_new();
3745 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3750 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3751 gtk_tree_view_column_set_resizable(column, TRUE);
3752 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3754 renderer = gtk_cell_renderer_text_new();
3756 column = gtk_tree_view_column_new_with_attributes("Accel",
3761 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3762 gtk_tree_view_column_set_resizable(column, TRUE);
3763 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3765 accel_store_populate();
3766 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3767 gtk_widget_show(accel_view);
3769 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3771 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3772 G_CALLBACK(accel_default_cb), accel_view);
3773 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3774 gtk_widget_show(button);
3776 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3777 G_CALLBACK(accel_reset_cb), accel_view);
3778 gtk_widget_set_tooltip_text(button, _("Will only reset changes made before the settings are saved"));
3779 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3780 gtk_widget_show(button);
3782 button = pref_button_new(NULL, NULL, _("Clear selected"), FALSE,
3783 G_CALLBACK(accel_clear_cb), accel_view);
3784 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3785 gtk_widget_show(button);
3788 /* toolbar main tab */
3789 static void config_tab_toolbar_main(GtkWidget *notebook)
3792 GtkWidget *toolbardata;
3795 lw = static_cast<LayoutWindow *>(layout_window_list->data);
3797 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3799 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3800 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3801 gtk_widget_show(vbox);
3804 /* toolbar status tab */
3805 static void config_tab_toolbar_status(GtkWidget *notebook)
3808 GtkWidget *toolbardata;
3811 lw = static_cast<LayoutWindow *>(layout_window_list->data);
3813 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3815 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3816 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3817 gtk_widget_show(vbox);
3821 static gint extension_sort_cb(gconstpointer a, gconstpointer b)
3823 return g_strcmp0((gchar *)a, (gchar *)b);
3826 static void config_tab_advanced(GtkWidget *notebook)
3830 GSList *formats_list;
3831 GList *extensions_list = NULL;
3834 GdkPixbufFormat *fm;
3836 GString *types_string = g_string_new(NULL);
3837 GtkWidget *types_string_label;
3838 GtkWidget *threads_string_label;
3839 GtkWidget *dupes_threads_spin;
3841 vbox = scrolled_notebook_page(notebook, _("Advanced"));
3842 group = pref_group_new(vbox, FALSE, _("External preview extraction"), GTK_ORIENTATION_VERTICAL);
3844 pref_checkbox_new_int(group, _("Use external preview extraction - Requires restart"), options->external_preview.enable, &c_options->external_preview.enable);
3846 pref_spacer(group, PREF_PAD_GROUP);
3848 formats_list = gdk_pixbuf_get_formats();
3850 while (formats_list)
3852 fm = static_cast<GdkPixbufFormat *>(formats_list->data);
3853 extensions = gdk_pixbuf_format_get_extensions(fm);
3856 while (extensions[i])
3858 extensions_list = g_list_insert_sorted(extensions_list, g_strdup(extensions[i]), extension_sort_cb);
3862 g_strfreev(extensions);
3863 formats_list = formats_list->next;
3866 while (extensions_list)
3868 if (types_string->len == 0)
3870 types_string = g_string_append(types_string, static_cast<const gchar *>(extensions_list->data));
3874 types_string = g_string_append(types_string, ", ");
3875 types_string = g_string_append(types_string, static_cast<const gchar *>(extensions_list->data));
3878 extensions_list = extensions_list->next;
3881 types_string = g_string_prepend(types_string, _("Usable file types:\n"));
3882 types_string_label = pref_label_new(group, types_string->str);
3883 gtk_label_set_line_wrap(GTK_LABEL(types_string_label), TRUE);
3885 pref_spacer(group, PREF_PAD_GROUP);
3887 group = pref_group_new(vbox, FALSE, _("File identification tool"), GTK_ORIENTATION_VERTICAL);
3888 external_preview_select_entry = gtk_entry_new();
3889 tabcomp = tab_completion_new(&external_preview_select_entry, options->external_preview.select, NULL, NULL, NULL, NULL);
3890 tab_completion_add_select_button(external_preview_select_entry, _("Select file identification tool"), FALSE);
3891 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3892 gtk_widget_show(tabcomp);
3894 group = pref_group_new(vbox, FALSE, _("Preview extraction tool"), GTK_ORIENTATION_VERTICAL);
3895 external_preview_extract_entry = gtk_entry_new();
3896 tabcomp = tab_completion_new(&external_preview_extract_entry, options->external_preview.extract, NULL, NULL, NULL, NULL);
3897 tab_completion_add_select_button(external_preview_extract_entry, _("Select preview extraction tool"), FALSE);
3898 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3899 gtk_widget_show(tabcomp);
3901 gtk_widget_show(vbox);
3903 g_slist_free(formats_list);
3904 string_list_free(extensions_list);
3905 g_string_free(types_string, TRUE);
3907 pref_spacer(group, PREF_PAD_GROUP);
3909 pref_line(vbox, PREF_PAD_SPACE);
3910 group = pref_group_new(vbox, FALSE, _("Thread pool limits"), GTK_ORIENTATION_VERTICAL);
3912 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.");
3913 gtk_label_set_line_wrap(GTK_LABEL(threads_string_label), TRUE);
3915 pref_spacer(vbox, PREF_PAD_GROUP);
3917 dupes_threads_spin = pref_spin_new_int(vbox, _("Duplicate check:"), _("max. threads"), 0, get_cpu_cores(), 1, options->threads.duplicates, &c_options->threads.duplicates);
3918 gtk_widget_set_tooltip_markup(dupes_threads_spin, _("Set to 0 for unlimited"));
3922 static void config_tab_stereo(GtkWidget *notebook)
3930 GtkWidget *fs_button;
3931 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3933 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3935 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3936 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3938 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3939 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3940 pref_checkbox_new_int(box, _("Mirror left image"),
3941 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3942 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3943 pref_checkbox_new_int(box, _("Flip left image"),
3944 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3945 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3946 pref_checkbox_new_int(box, _("Mirror right image"),
3947 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3948 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3949 pref_checkbox_new_int(box, _("Flip right image"),
3950 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3951 pref_checkbox_new_int(group, _("Swap left and right images"),
3952 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3953 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3954 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3956 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3957 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3958 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3959 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3960 pref_checkbox_link_sensitivity(fs_button, box2);
3961 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3962 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3963 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3964 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3965 pref_checkbox_new_int(box, _("Mirror left image"),
3966 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3967 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3968 pref_checkbox_new_int(box, _("Flip left image"),
3969 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3970 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3971 pref_checkbox_new_int(box, _("Mirror right image"),
3972 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3973 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3974 pref_checkbox_new_int(box, _("Flip right image"),
3975 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3976 pref_checkbox_new_int(box2, _("Swap left and right images"),
3977 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3978 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3979 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3981 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3982 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3983 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3984 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3985 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
3986 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3987 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
3988 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3989 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
3990 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3991 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
3992 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3993 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
3994 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3998 /* Main preferences window */
3999 static void config_window_create(LayoutWindow *lw)
4001 GtkWidget *win_vbox;
4003 GtkWidget *notebook;
4005 GtkWidget *ct_button;
4007 if (!c_options) c_options = init_options(NULL);
4009 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
4010 DEBUG_NAME(configwindow);
4011 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
4012 g_signal_connect(G_OBJECT(configwindow), "delete_event",
4013 G_CALLBACK(config_window_delete), NULL);
4014 if (options->save_dialog_window_positions)
4016 gtk_window_resize(GTK_WINDOW(configwindow), lw->options.preferences_window.w, lw->options.preferences_window.h);
4017 gtk_window_move(GTK_WINDOW(configwindow), lw->options.preferences_window.x, lw->options.preferences_window.y);
4021 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
4023 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
4024 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
4026 win_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
4027 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
4028 gtk_widget_show(win_vbox);
4030 notebook = gtk_notebook_new();
4031 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
4032 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
4033 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
4035 config_tab_general(notebook);
4036 config_tab_image(notebook);
4037 config_tab_osd(notebook);
4038 config_tab_windows(notebook);
4039 config_tab_accelerators(notebook);
4040 config_tab_files(notebook);
4041 config_tab_metadata(notebook);
4042 config_tab_keywords(notebook);
4043 config_tab_color(notebook);
4044 config_tab_stereo(notebook);
4045 config_tab_behavior(notebook);
4046 config_tab_toolbar_main(notebook);
4047 config_tab_toolbar_status(notebook);
4048 config_tab_advanced(notebook);
4050 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), lw->options.preferences_window.page_number);
4052 hbox = gtk_hbutton_box_new();
4053 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
4054 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
4055 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
4056 gtk_widget_show(hbox);
4058 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
4059 G_CALLBACK(config_window_help_cb), notebook);
4060 gtk_container_add(GTK_CONTAINER(hbox), button);
4061 gtk_widget_set_can_default(button, TRUE);
4062 gtk_widget_show(button);
4064 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
4065 G_CALLBACK(config_window_ok_cb), notebook);
4066 gtk_container_add(GTK_CONTAINER(hbox), button);
4067 gtk_widget_set_can_default(button, TRUE);
4068 gtk_widget_grab_default(button);
4069 gtk_widget_show(button);
4073 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
4074 G_CALLBACK(config_window_close_cb), NULL);
4075 gtk_container_add(GTK_CONTAINER(hbox), button);
4076 gtk_widget_set_can_default(button, TRUE);
4077 gtk_widget_show(button);
4079 if (!generic_dialog_get_alternative_button_order(configwindow))
4081 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
4084 gtk_widget_show(notebook);
4086 gtk_widget_show(configwindow);
4090 *-----------------------------------------------------------------------------
4091 * config window show (public)
4092 *-----------------------------------------------------------------------------
4095 void show_config_window(LayoutWindow *lw)
4099 gtk_window_present(GTK_WINDOW(configwindow));
4103 config_window_create(lw);
4112 void show_about_window(LayoutWindow *lw)
4114 GDataInputStream *data_stream;
4115 GInputStream *in_stream_authors;
4116 GInputStream *in_stream_translators;
4118 GdkPixbuf *pixbuf_icon;
4119 GdkPixbuf *pixbuf_logo;
4123 gchar *authors[1000];
4124 gchar *authors_path;
4126 gchar *timezone_path;
4128 gchar *translators_path;
4136 copyright = g_string_new(NULL);
4137 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");
4139 timezone_path = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
4140 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
4142 cd = ZDOpenDatabase(timezone_path);
4145 copyright = g_string_append(copyright, ZDGetNotice(cd));
4149 log_printf("Error: Init of timezone database %s failed\n", timezone_path);
4151 ZDCloseDatabase(cd);
4153 g_free(timezone_path);
4155 authors_path = g_build_filename(GQ_RESOURCE_PATH_CREDITS, "authors", NULL);
4157 in_stream_authors = g_resources_open_stream(authors_path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
4159 data_stream = g_data_input_stream_new(in_stream_authors);
4162 while ((author_line = g_data_input_stream_read_line(G_DATA_INPUT_STREAM(data_stream), &length, NULL, NULL)))
4164 authors[i_authors] = g_strdup(author_line);
4166 g_free(author_line);
4168 authors[i_authors] = NULL;
4170 g_input_stream_close(in_stream_authors, NULL, NULL);
4172 translators_path = g_build_filename(GQ_RESOURCE_PATH_CREDITS, "translators", NULL);
4174 g_resources_get_info(translators_path, G_RESOURCE_LOOKUP_FLAGS_NONE, &size, &flags, NULL);
4176 in_stream_translators = g_resources_open_stream(translators_path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
4177 translators = static_cast<gchar *>(g_malloc0(size));
4178 g_input_stream_read_all(in_stream_translators, translators, size, &bytes_read, NULL, NULL);
4179 g_input_stream_close(in_stream_translators, NULL, NULL);
4181 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);
4183 artists[0] = g_strdup("Néstor Díaz Valencia <nestor@estudionexos.com>");
4186 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
4187 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
4188 gtk_show_about_dialog(GTK_WINDOW(lw->window),
4189 "title", _("About Geeqie"),
4191 "program-name", GQ_APPNAME,
4193 "logo", pixbuf_logo,
4194 "icon", pixbuf_icon,
4195 "website", GQ_WEBSITE,
4196 "website-label", "Website",
4197 "comments", comment,
4200 "translator-credits", translators,
4201 "wrap-license", TRUE,
4202 "license", copyright->str,
4205 g_string_free(copyright, TRUE);
4207 while(n < i_authors)
4214 g_free(authors_path);
4216 g_free(translators);
4217 g_free(translators_path);
4218 g_object_unref(data_stream);
4219 g_object_unref(in_stream_authors);
4220 g_object_unref(in_stream_translators);
4225 static void image_overlay_set_text_colours()
4227 c_options->image_overlay.text_red = options->image_overlay.text_red;
4228 c_options->image_overlay.text_green = options->image_overlay.text_green;
4229 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
4230 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
4231 c_options->image_overlay.background_red = options->image_overlay.background_red;
4232 c_options->image_overlay.background_green = options->image_overlay.background_green;
4233 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
4234 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
4238 *-----------------------------------------------------------------------------
4239 * timezone database routines
4240 *-----------------------------------------------------------------------------
4243 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
4245 GError *error = NULL;
4246 TZData *tz = static_cast<TZData *>(data);
4247 gchar *tmp_filename;
4248 gchar *timezone_bin;
4249 gchar *tmp_dir = NULL;
4252 if (!g_cancellable_is_cancelled(tz->cancellable))
4254 generic_dialog_close(tz->gd);
4258 if (g_file_copy_finish(G_FILE(source_object), res, &error))
4260 tmp_filename = g_file_get_path(tz->tmp_g_file);
4261 fd = file_data_new_simple(tmp_filename);
4262 tmp_dir = open_archive(fd);
4266 timezone_bin = g_build_filename(tmp_dir, TIMEZONE_DATABASE_VERSION, TIMEZONE_DATABASE_FILE, NULL);
4267 if (isfile(timezone_bin))
4269 move_file(timezone_bin, tz->timezone_database_user);
4273 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GTK_STOCK_DIALOG_WARNING, NULL);
4276 g_free(timezone_bin);
4277 g_free(tmp_dir); // The folder in /tmp is deleted in exit_program_final()
4281 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GTK_STOCK_DIALOG_WARNING, NULL);
4283 g_free(tmp_filename);
4284 file_data_unref(fd);
4288 file_util_warning_dialog(_("Error: Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4291 g_file_delete(tz->tmp_g_file, NULL, &error);
4292 g_object_unref(tz->tmp_g_file);
4293 tz->tmp_g_file = NULL;
4294 g_object_unref(tz->cancellable);
4295 g_object_unref(tz->timezone_database_gq);
4298 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
4300 TZData *tz = static_cast<TZData *>(data);
4302 if (!g_cancellable_is_cancelled(tz->cancellable))
4304 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
4308 static void timezone_cancel_button_cb(GenericDialog *UNUSED(gd), gpointer data)
4310 TZData *tz = static_cast<TZData *>(data);
4312 g_cancellable_cancel(tz->cancellable);
4315 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
4317 TZData *tz = static_cast<TZData *>(data);
4318 GError *error = NULL;
4319 GFileIOStream *io_stream;
4326 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
4330 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4331 log_printf("Error: Download timezone database failed:\n%s", error->message);
4332 g_error_free(error);
4333 g_object_unref(tz->tmp_g_file);
4337 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE_WEB);
4339 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
4341 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
4343 tz->progress = gtk_progress_bar_new();
4344 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
4345 gtk_widget_show(tz->progress);
4347 gtk_widget_show(tz->gd->dialog);
4348 tz->cancellable = g_cancellable_new();
4349 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);
4351 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
4354 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */