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"
31 #include "filefilter.h"
32 #include "fullscreen.h"
34 #include "image-overlay.h"
35 #include "color-man.h"
37 #include "layout-util.h"
41 #include "pixbuf-util.h"
43 #include "slideshow.h"
47 #include "ui-fileops.h"
49 #include "ui-spinner.h"
50 #include "ui-tabcomp.h"
52 #include "zonedetect.h"
63 #include <gspell/gspell.h>
66 #define EDITOR_NAME_MAX_LENGTH 32
67 #define EDITOR_COMMAND_MAX_LENGTH 1024
69 static void image_overlay_set_text_colours();
71 GtkWidget *keyword_text;
72 static void config_tab_keywords_save();
74 typedef struct _ThumbSize ThumbSize;
81 static ThumbSize thumb_size_list[] =
116 FILETYPES_COLUMN_ENABLED = 0,
117 FILETYPES_COLUMN_FILTER,
118 FILETYPES_COLUMN_DESCRIPTION,
119 FILETYPES_COLUMN_CLASS,
120 FILETYPES_COLUMN_WRITABLE,
121 FILETYPES_COLUMN_SIDECAR,
122 FILETYPES_COLUMN_COUNT
125 const gchar *format_class_list[] = {
136 /* config memory values */
137 static ConfOptions *c_options = NULL;
144 static GtkWidget *configwindow = NULL;
145 static GtkListStore *filter_store = NULL;
146 static GtkTreeStore *accel_store = NULL;
148 static GtkWidget *safe_delete_path_entry;
150 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
151 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
152 static GtkWidget *color_profile_screen_file_entry;
153 static GtkWidget *external_preview_select_entry;
154 static GtkWidget *external_preview_extract_entry;
156 static GtkWidget *sidecar_ext_entry;
157 static GtkWidget *help_search_engine_entry;
160 #define CONFIG_WINDOW_DEF_WIDTH 700
161 #define CONFIG_WINDOW_DEF_HEIGHT 600
164 *-----------------------------------------------------------------------------
165 * option widget callbacks (private)
166 *-----------------------------------------------------------------------------
169 static void zoom_increment_cb(GtkWidget *spin, gpointer UNUSED(data))
171 c_options->image.zoom_increment = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
174 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer UNUSED(data))
176 gint mins_secs_tenths, delay;
178 mins_secs_tenths = c_options->slideshow.delay %
179 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
181 delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
182 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
185 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
186 SLIDESHOW_SUBSECOND_PRECISION;
189 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer UNUSED(data))
191 gint hours, secs_tenths, delay;
193 hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
194 secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
196 delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
197 (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
198 (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
200 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
201 SLIDESHOW_SUBSECOND_PRECISION;
204 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer UNUSED(data))
206 gint hours_mins, delay;
208 hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
210 delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
211 (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
212 (gdouble)(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
214 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
215 SLIDESHOW_SUBSECOND_PRECISION;
219 *-----------------------------------------------------------------------------
220 * sync program to config window routine (private)
221 *-----------------------------------------------------------------------------
224 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
230 buf = gtk_entry_get_text(GTK_ENTRY(entry));
231 if (buf && strlen(buf) > 0)
236 *option = g_strdup(buf);
241 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *UNUSED(path), GtkTreeIter *iter, gpointer UNUSED(data))
243 gchar *accel_path, *accel;
245 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
247 if (accel_path && accel_path[0])
250 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
251 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
261 static void config_window_apply(void)
263 gboolean refresh = FALSE;
268 config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
270 if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
271 if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
272 if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
273 if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
274 if (options->file_sort.natural != c_options->file_sort.natural) refresh = TRUE;
275 if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
276 if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
278 options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
279 options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
280 options->file_ops.confirm_move_to_trash = c_options->file_ops.confirm_move_to_trash;
281 options->file_ops.use_system_trash = c_options->file_ops.use_system_trash;
282 options->file_ops.no_trash = c_options->file_ops.no_trash;
283 options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
284 options->tools_restore_state = c_options->tools_restore_state;
285 options->save_window_positions = c_options->save_window_positions;
286 options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
287 options->save_window_workspace = c_options->save_window_workspace;
288 options->save_dialog_window_positions = c_options->save_dialog_window_positions;
289 options->show_window_ids = c_options->show_window_ids;
290 options->image.scroll_reset_method = c_options->image.scroll_reset_method;
291 options->image.zoom_2pass = c_options->image.zoom_2pass;
292 options->image.fit_window_to_image = c_options->image.fit_window_to_image;
293 options->image.limit_window_size = c_options->image.limit_window_size;
294 options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
295 options->image.max_window_size = c_options->image.max_window_size;
296 options->image.limit_autofit_size = c_options->image.limit_autofit_size;
297 options->image.max_autofit_size = c_options->image.max_autofit_size;
298 options->image.max_enlargement_size = c_options->image.max_enlargement_size;
299 //~ options->image.use_clutter_renderer = c_options->image.use_clutter_renderer;
300 options->image.tile_size = c_options->image.tile_size;
301 options->progressive_key_scrolling = c_options->progressive_key_scrolling;
302 options->keyboard_scroll_step = c_options->keyboard_scroll_step;
304 if (options->thumbnails.max_width != c_options->thumbnails.max_width
305 || options->thumbnails.max_height != c_options->thumbnails.max_height
306 || options->thumbnails.quality != c_options->thumbnails.quality)
308 thumb_format_changed = TRUE;
310 options->thumbnails.max_width = c_options->thumbnails.max_width;
311 options->thumbnails.max_height = c_options->thumbnails.max_height;
312 options->thumbnails.quality = c_options->thumbnails.quality;
314 options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
315 options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
316 options->thumbnails.use_exif = c_options->thumbnails.use_exif;
317 options->thumbnails.use_color_management = c_options->thumbnails.use_color_management;
318 options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
319 options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
320 // options->thumbnails.use_ft_metadata_small = c_options->thumbnails.use_ft_metadata_small;
321 options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
322 options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
323 options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
324 options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
325 options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
326 options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
328 options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
329 options->file_sort.natural = c_options->file_sort.natural;
330 options->file_filter.disable = c_options->file_filter.disable;
332 config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, NULL);
333 sidecar_ext_parse(options->sidecar.ext);
335 options->slideshow.random = c_options->slideshow.random;
336 options->slideshow.repeat = c_options->slideshow.repeat;
337 options->slideshow.delay = c_options->slideshow.delay;
339 options->mousewheel_scrolls = c_options->mousewheel_scrolls;
340 options->image_lm_click_nav = c_options->image_lm_click_nav;
341 options->image_l_click_archive = c_options->image_l_click_archive;
342 options->image_l_click_video = c_options->image_l_click_video;
343 options->image_l_click_video_editor = c_options->image_l_click_video_editor;
345 options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
347 options->image.tile_cache_max = c_options->image.tile_cache_max;
348 options->image.image_cache_max = c_options->image.image_cache_max;
350 options->image.zoom_quality = c_options->image.zoom_quality;
352 options->image.zoom_increment = c_options->image.zoom_increment;
354 options->image.zoom_style = c_options->image.zoom_style;
356 options->image.enable_read_ahead = c_options->image.enable_read_ahead;
358 options->appimage_notifications = c_options->appimage_notifications;
361 if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
362 || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
363 || !gdk_color_equal(&options->image.border_color, &c_options->image.border_color))
365 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
366 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
367 options->image.border_color = c_options->image.border_color;
368 layout_colors_update();
369 view_window_colors_update();
372 options->image.alpha_color_1 = c_options->image.alpha_color_1;
373 options->image.alpha_color_2 = c_options->image.alpha_color_2;
375 options->fullscreen.screen = c_options->fullscreen.screen;
376 options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
377 options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
378 options->fullscreen.above = c_options->fullscreen.above;
379 if (c_options->image_overlay.template_string)
380 set_image_overlay_template_string(&options->image_overlay.template_string,
381 c_options->image_overlay.template_string);
382 if (c_options->image_overlay.font)
383 set_image_overlay_font_string(&options->image_overlay.font,
384 c_options->image_overlay.font);
385 options->image_overlay.text_red = c_options->image_overlay.text_red;
386 options->image_overlay.text_green = c_options->image_overlay.text_green;
387 options->image_overlay.text_blue = c_options->image_overlay.text_blue;
388 options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
389 options->image_overlay.background_red = c_options->image_overlay.background_red;
390 options->image_overlay.background_green = c_options->image_overlay.background_green;
391 options->image_overlay.background_blue = c_options->image_overlay.background_blue;
392 options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
393 options->update_on_time_change = c_options->update_on_time_change;
395 options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
396 options->rot_invariant_sim = c_options->rot_invariant_sim;
398 options->tree_descend_subdirs = c_options->tree_descend_subdirs;
400 options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
401 options->circular_selection_lists = c_options->circular_selection_lists;
403 options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
404 options->recent_folder_image_list_maxsize = c_options->recent_folder_image_list_maxsize;
405 options->dnd_icon_size = c_options->dnd_icon_size;
406 options->clipboard_selection = c_options->clipboard_selection;
407 options->dnd_default_action = c_options->dnd_default_action;
409 options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
410 options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
411 options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
412 options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
413 options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
414 options->metadata.confirm_write = c_options->metadata.confirm_write;
415 options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
416 options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
417 options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
418 options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
419 options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
420 options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
421 options->metadata.write_orientation = c_options->metadata.write_orientation;
422 options->metadata.check_spelling = c_options->metadata.check_spelling;
423 options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
424 (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
425 (c_options->stereo.tmp.flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
426 (c_options->stereo.tmp.mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
427 (c_options->stereo.tmp.flip_left ? PR_STEREO_FLIP_LEFT : 0) |
428 (c_options->stereo.tmp.swap ? PR_STEREO_SWAP : 0) |
429 (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
430 options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
431 (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
432 (c_options->stereo.tmp.fs_flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
433 (c_options->stereo.tmp.fs_mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
434 (c_options->stereo.tmp.fs_flip_left ? PR_STEREO_FLIP_LEFT : 0) |
435 (c_options->stereo.tmp.fs_swap ? PR_STEREO_SWAP : 0) |
436 (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
437 options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
438 options->stereo.fixed_w = c_options->stereo.fixed_w;
439 options->stereo.fixed_h = c_options->stereo.fixed_h;
440 options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
441 options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
442 options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
443 options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
445 options->info_keywords.height = c_options->info_keywords.height;
446 options->info_title.height = c_options->info_title.height;
447 options->info_comment.height = c_options->info_comment.height;
448 options->info_rating.height = c_options->info_rating.height;
450 options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
451 options->expand_menu_toolbar = c_options->expand_menu_toolbar;
453 options->marks_save = c_options->marks_save;
454 options->with_rename = c_options->with_rename;
455 options->collections_on_top = c_options->collections_on_top;
456 options->hide_window_in_fullscreen = c_options->hide_window_in_fullscreen;
457 config_entry_to_option(help_search_engine_entry, &options->help_search_engine, NULL);
459 options->external_preview.enable = c_options->external_preview.enable;
460 config_entry_to_option(external_preview_select_entry, &options->external_preview.select, NULL);
461 config_entry_to_option(external_preview_extract_entry, &options->external_preview.extract, NULL);
463 options->read_metadata_in_idle = c_options->read_metadata_in_idle;
465 options->star_rating.star = c_options->star_rating.star;
466 options->star_rating.rejected = c_options->star_rating.rejected;
468 options->threads.duplicates = c_options->threads.duplicates > 0 ? c_options->threads.duplicates : -1;
471 set_debug_level(debug_c);
475 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
477 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
478 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
480 config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
481 options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
482 if (options->color_profile.render_intent != c_options->color_profile.render_intent)
484 options->color_profile.render_intent = c_options->color_profile.render_intent;
489 options->mouse_button_8 = c_options->mouse_button_8;
490 options->mouse_button_9 = c_options->mouse_button_9;
492 options->override_disable_gpu = c_options->override_disable_gpu;
494 config_tab_keywords_save();
496 image_options_sync();
501 layout_refresh(NULL);
504 if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, NULL);
506 toolbar_apply(TOOLBAR_MAIN);
507 toolbar_apply(TOOLBAR_STATUS);
511 *-----------------------------------------------------------------------------
512 * config window main button callbacks (private)
513 *-----------------------------------------------------------------------------
516 static void config_window_close_cb(GtkWidget *UNUSED(widget), gpointer UNUSED(data))
518 gtk_widget_destroy(configwindow);
523 static void config_window_help_cb(GtkWidget *UNUSED(widget), gpointer data)
525 GtkWidget *notebook = static_cast<GtkWidget *>(data);
528 static const gchar *html_section[] =
530 "GuideOptionsGeneral.html",
531 "GuideOptionsImage.html",
532 "GuideOptionsOSD.html",
533 "GuideOptionsWindow.html",
534 "GuideOptionsKeyboard.html",
535 "GuideOptionsFiltering.html",
536 "GuideOptionsMetadata.html",
537 "GuideOptionsKeywords.html",
538 "GuideOptionsColor.html",
539 "GuideOptionsStereo.html",
540 "GuideOptionsBehavior.html",
541 "GuideOptionsToolbar.html",
542 "GuideOptionsToolbar.html",
543 "GuideOptionsAdvanced.html"
546 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
547 help_window_show(html_section[i]);
550 static gboolean config_window_delete(GtkWidget *UNUSED(widget), GdkEventAny *UNUSED(event), gpointer UNUSED(data))
552 config_window_close_cb(NULL, NULL);
556 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
559 GtkNotebook *notebook = static_cast<GtkNotebook *>(data);
567 lw = static_cast<LayoutWindow *>(layout_window_list->data);
569 window = gtk_widget_get_window(widget);
570 gdk_window_get_root_origin(window, &x, &y);
571 w = gdk_window_get_width(window);
572 h = gdk_window_get_height(window);
573 page_number = gtk_notebook_get_current_page(notebook);
575 lw->options.preferences_window.x = x;
576 lw->options.preferences_window.y = y;
577 lw->options.preferences_window.w = w;
578 lw->options.preferences_window.h = h;
579 lw->options.preferences_window.page_number = page_number;
581 config_window_apply();
582 layout_util_sync(lw);
583 save_options(options);
584 config_window_close_cb(NULL, NULL);
588 *-----------------------------------------------------------------------------
589 * config window setup (private)
590 *-----------------------------------------------------------------------------
593 static void quality_menu_cb(GtkWidget *combo, gpointer data)
595 gint *option = static_cast<gint *>(data);
597 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
601 *option = GDK_INTERP_NEAREST;
604 *option = GDK_INTERP_TILES;
607 *option = GDK_INTERP_BILINEAR;
612 static void dnd_default_action_selection_menu_cb(GtkWidget *combo, gpointer data)
614 gint *option = static_cast<gint *>(data);
616 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
620 *option = DND_ACTION_ASK;
623 *option = DND_ACTION_COPY;
626 *option = DND_ACTION_MOVE;
630 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
632 gint *option = static_cast<gint *>(data);
634 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
637 *option = CLIPBOARD_PRIMARY;
640 *option = CLIPBOARD_CLIPBOARD;
643 *option = CLIPBOARD_BOTH;
646 *option = CLIPBOARD_BOTH;
650 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
651 guint option, guint *option_c)
658 pref_table_label(table, column, row, text, 0.0);
660 combo = gtk_combo_box_text_new();
662 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
663 if (option == GDK_INTERP_NEAREST) current = 0;
664 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
665 if (option == GDK_INTERP_TILES) current = 1;
666 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear (best, but slowest)"));
667 if (option == GDK_INTERP_BILINEAR) current = 2;
669 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
671 g_signal_connect(G_OBJECT(combo), "changed",
672 G_CALLBACK(quality_menu_cb), option_c);
674 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
675 gtk_widget_show(combo);
678 static void add_dnd_default_action_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, DnDAction option, DnDAction *option_c)
685 pref_table_label(table, column, row, text, 0.0);
687 combo = gtk_combo_box_text_new();
689 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Ask"));
690 if (option == DND_ACTION_ASK) current = 0;
691 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Copy"));
692 if (option == DND_ACTION_COPY) current = 1;
693 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Move"));
694 if (option == DND_ACTION_MOVE) current = 2;
696 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
698 g_signal_connect(G_OBJECT(combo), "changed",
699 G_CALLBACK(dnd_default_action_selection_menu_cb), option_c);
701 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
702 gtk_widget_show(combo);
705 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
706 gint option, gint *option_c)
713 pref_table_label(table, column, row, text, 0.0);
715 combo = gtk_combo_box_text_new();
717 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Primary"));
718 if (option == CLIPBOARD_PRIMARY) current = 0;
719 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Clipboard"));
720 if (option == CLIPBOARD_CLIPBOARD) current = 1;
721 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Both"));
722 if (option == CLIPBOARD_BOTH) current = 2;
724 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
726 g_signal_connect(G_OBJECT(combo), "changed",
727 G_CALLBACK(clipboard_selection_menu_cb), option_c);
729 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
730 gtk_widget_show(combo);
733 static void zoom_style_selection_menu_cb(GtkWidget *combo, gpointer data)
735 gint *option = static_cast<gint *>(data);
737 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
740 *option = ZOOM_GEOMETRIC;
743 *option = ZOOM_ARITHMETIC;
746 *option = ZOOM_GEOMETRIC;
750 static void add_zoom_style_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, ZoomStyle option, ZoomStyle *option_c)
757 pref_table_label(table, column, row, text, 0.0);
759 combo = gtk_combo_box_text_new();
761 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Geometric"));
762 if (option == ZOOM_GEOMETRIC) current = 0;
763 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Arithmetic"));
764 if (option == ZOOM_ARITHMETIC) current = 1;
766 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
768 g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(zoom_style_selection_menu_cb), option_c);
770 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
771 gtk_widget_show(combo);
774 typedef struct _UseableMouseItems UseableMouseItems;
775 struct _UseableMouseItems
777 const gchar *name; /* GtkActionEntry terminology */
779 const gchar *stock_id;
782 static const UseableMouseItems useable_mouse_items[] = {
784 {"FirstImage", N_("First Image"), GTK_STOCK_GOTO_TOP},
785 {"PrevImage", N_("Previous Image"), GTK_STOCK_GO_UP},
786 {"NextImage", N_("Next Image"), GTK_STOCK_GO_DOWN},
787 {"LastImage", N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
788 {"Back", N_("Back"), GTK_STOCK_GO_BACK},
789 {"Forward", N_("Forward"), GTK_STOCK_GO_FORWARD},
790 {"Home", N_("Home"), GTK_STOCK_HOME},
791 {"Up", N_("Up"), GTK_STOCK_GO_UP},
792 {"FirstPage", N_("First page"), GTK_STOCK_MEDIA_PREVIOUS},
793 {"LastPage", N_("Last Page"), GTK_STOCK_MEDIA_NEXT},
794 {"NextPage", N_("Next page"), GTK_STOCK_MEDIA_FORWARD},
795 {"PrevPage", N_("Previous Page"), GTK_STOCK_MEDIA_REWIND},
796 {"NewWindow", N_("New _window"), GTK_STOCK_NEW},
797 {"NewCollection", N_("New collection"), GTK_STOCK_INDEX},
798 {"OpenCollection", N_("Open collection"), GTK_STOCK_OPEN},
799 {"Search", N_("Search"), GTK_STOCK_FIND},
800 {"FindDupes", N_("Find duplicates"), GTK_STOCK_FIND},
801 {"NewFolder", N_("New folder"),GTK_STOCK_DIRECTORY},
802 {"Copy", N_("Copy"), GTK_STOCK_COPY},
803 {"Move", N_("Move"), PIXBUF_INLINE_ICON_MOVE},
804 {"Rename", N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
805 {"Delete", N_("Delete"), GTK_STOCK_DELETE},
806 {"CloseWindow", N_("Close Window"), GTK_STOCK_CLOSE},
807 {"PanView", N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
808 {"SelectAll", N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
809 {"SelectNone", N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
810 {"SelectInvert", N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
811 {"ShowFileFilter", N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
812 {"RectangularSelection", N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
813 {"Print", N_("Print"), GTK_STOCK_PRINT},
814 {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
815 {"LayoutConfig", N_("Configure this window"), GTK_STOCK_PREFERENCES},
816 {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
817 {"RotateCW", N_("Rotate clockwise 90°"), PIXBUF_INLINE_ICON_CW},
818 {"RotateCCW", N_("Rotate counterclockwise 90°"), PIXBUF_INLINE_ICON_CCW},
819 {"Rotate180", N_("Rotate 180°"), PIXBUF_INLINE_ICON_180},
820 {"Mirror", N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
821 {"Flip", N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
822 {"AlterNone", N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
823 {"ZoomIn", N_("Zoom in"), GTK_STOCK_ZOOM_IN},
824 {"ZoomOut", N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
825 {"Zoom100", N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
826 {"ZoomFit", N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
827 {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
828 {"ZoomFillVert", N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
829 {"Zoom200", N_("Zoom 2:1"), GTK_STOCK_FILE},
830 {"Zoom300", N_("Zoom 3:1"), GTK_STOCK_FILE},
831 {"Zoom400", N_("Zoom 4:1"), GTK_STOCK_FILE},
832 {"Zoom50", N_("Zoom 1:2"), GTK_STOCK_FILE},
833 {"Zoom33", N_("Zoom1:3"), GTK_STOCK_FILE},
834 {"Zoom25", N_("Zoom 1:4"), GTK_STOCK_FILE},
835 {"ConnectZoomIn", N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
836 {"SplitPaneSync", N_("Split Pane Sync"), PIXBUF_INLINE_SPLIT_PANE_SYNC},
837 {"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
838 {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
839 {"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
840 {"SlideShowPause", N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
841 {"SlideShowFaster", N_("Slideshow Faster"), GTK_STOCK_FILE},
842 {"SlideShowSlower", N_("Slideshow Slower"), GTK_STOCK_FILE},
843 {"Refresh", N_("Refresh"), GTK_STOCK_REFRESH},
844 {"HelpContents", N_("Help"), GTK_STOCK_HELP},
845 {"ExifWin", N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
846 {"Thumbnails", N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
847 {"ShowMarks", N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
848 {"DrawRectangle", N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
849 {"FloatTools", N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
850 {"SBar", N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
851 {"SBarSort", N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
852 {"Quit", N_("Quit"), GTK_STOCK_QUIT},
856 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
858 gchar **option = static_cast<gchar **>(data);
861 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
863 const UseableMouseItems *list = useable_mouse_items;
867 if (g_strcmp0(list->label, label) == 0)
875 *option = g_strdup(list->name);
879 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
880 gchar *option, gchar **option_c)
888 pref_table_label(table, column, row, text, 0.0);
890 combo = gtk_combo_box_text_new();
892 const UseableMouseItems *list = useable_mouse_items;
896 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
897 if (g_strcmp0(list->name, option) == 0)
905 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
907 g_signal_connect(G_OBJECT(combo), "changed",
908 G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
910 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
911 gtk_widget_show(combo);
914 static void thumb_size_menu_cb(GtkWidget *combo, gpointer UNUSED(data))
918 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
921 if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
923 c_options->thumbnails.max_width = thumb_size_list[n].w;
924 c_options->thumbnails.max_height = thumb_size_list[n].h;
928 c_options->thumbnails.max_width = options->thumbnails.max_width;
929 c_options->thumbnails.max_height = options->thumbnails.max_height;
933 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
939 c_options->thumbnails.max_width = options->thumbnails.max_width;
940 c_options->thumbnails.max_height = options->thumbnails.max_height;
942 pref_table_label(table, column, row, text, 0.0);
944 combo = gtk_combo_box_text_new();
947 for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
952 w = thumb_size_list[i].w;
953 h = thumb_size_list[i].h;
955 buf = g_strdup_printf("%d x %d", w, h);
956 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
959 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
966 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
967 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
973 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
974 g_signal_connect(G_OBJECT(combo), "changed",
975 G_CALLBACK(thumb_size_menu_cb), NULL);
977 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
978 gtk_widget_show(combo);
981 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
983 gint *option = static_cast<gint *>(data);
985 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
989 *option = PR_STEREO_NONE;
992 *option = PR_STEREO_ANAGLYPH_RC;
995 *option = PR_STEREO_ANAGLYPH_GM;
998 *option = PR_STEREO_ANAGLYPH_YB;
1001 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
1004 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
1007 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
1010 *option = PR_STEREO_ANAGLYPH_DB_RC;
1013 *option = PR_STEREO_ANAGLYPH_DB_GM;
1016 *option = PR_STEREO_ANAGLYPH_DB_YB;
1019 *option = PR_STEREO_HORIZ;
1022 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
1025 *option = PR_STEREO_VERT;
1028 *option = PR_STEREO_VERT | PR_STEREO_HALF;
1031 *option = PR_STEREO_FIXED;
1036 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1037 gint option, gint *option_c, gboolean add_fixed)
1044 pref_table_label(table, column, row, text, 0.0);
1046 combo = gtk_combo_box_text_new();
1048 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
1050 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
1051 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
1052 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
1053 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
1054 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
1055 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
1056 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
1057 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
1058 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
1059 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
1060 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
1061 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
1062 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
1063 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
1064 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
1065 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
1066 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
1067 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
1069 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
1070 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
1071 if (option & PR_STEREO_HORIZ)
1074 if (option & PR_STEREO_HALF) current = 11;
1077 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
1078 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
1079 if (option & PR_STEREO_VERT)
1082 if (option & PR_STEREO_HALF) current = 13;
1087 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
1088 if (option & PR_STEREO_FIXED) current = 14;
1091 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1093 g_signal_connect(G_OBJECT(combo), "changed",
1094 G_CALLBACK(stereo_mode_menu_cb), option_c);
1096 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
1097 gtk_widget_show(combo);
1100 static void video_menu_cb(GtkWidget *combo, gpointer data)
1102 gchar **option = static_cast<gchar **>(data);
1104 EditorDescription *ed = static_cast<EditorDescription *>(g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo))));
1108 static void video_menu_populate(gpointer data, gpointer user_data)
1110 GtkWidget *combo = static_cast<GtkWidget *>(user_data);
1111 EditorDescription *ed = static_cast<EditorDescription *>(data);
1113 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1116 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1117 gchar *option, gchar **option_c)
1121 /* use lists since they are sorted */
1122 GList *eds = editor_list_get();
1126 pref_table_label(table, column, row, text, 0.0);
1128 combo = gtk_combo_box_text_new();
1129 g_list_foreach(eds,video_menu_populate,(gpointer)combo);
1130 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1132 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1134 g_signal_connect(G_OBJECT(combo), "changed",
1135 G_CALLBACK(video_menu_cb), option_c);
1137 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
1138 gtk_widget_show(combo);
1141 static void filter_store_populate(void)
1145 if (!filter_store) return;
1147 gtk_list_store_clear(filter_store);
1149 work = filter_get_list();
1155 fe = static_cast<FilterEntry *>(work->data);
1158 gtk_list_store_append(filter_store, &iter);
1159 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1163 static void filter_store_ext_edit_cb(GtkCellRendererText *UNUSED(cell), gchar *path_str,
1164 gchar *new_text, gpointer data)
1166 GtkWidget *model = static_cast<GtkWidget *>(data);
1167 FilterEntry *fe = static_cast<FilterEntry *>(data);
1171 if (!new_text || strlen(new_text) < 1) return;
1173 tpath = gtk_tree_path_new_from_string(path_str);
1174 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1175 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1177 g_free(fe->extensions);
1178 fe->extensions = g_strdup(new_text);
1180 gtk_tree_path_free(tpath);
1184 static void filter_store_class_edit_cb(GtkCellRendererText *UNUSED(cell), gchar *path_str,
1185 gchar *new_text, gpointer data)
1187 GtkWidget *model = static_cast<GtkWidget *>(data);
1188 FilterEntry *fe = static_cast<FilterEntry *>(data);
1193 if (!new_text || !new_text[0]) return;
1195 tpath = gtk_tree_path_new_from_string(path_str);
1196 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1197 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1199 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1201 if (strcmp(new_text, _(format_class_list[i])) == 0)
1203 fe->file_class = static_cast<FileFormatClass>(i);
1208 gtk_tree_path_free(tpath);
1212 static void filter_store_desc_edit_cb(GtkCellRendererText *UNUSED(cell), gchar *path_str,
1213 gchar *new_text, gpointer data)
1215 GtkWidget *model = static_cast<GtkWidget *>(data);
1220 if (!new_text || !new_text[0]) return;
1222 tpath = gtk_tree_path_new_from_string(path_str);
1223 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1224 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1226 g_free(fe->description);
1227 fe->description = g_strdup(new_text);
1229 gtk_tree_path_free(tpath);
1232 static void filter_store_enable_cb(GtkCellRendererToggle *UNUSED(renderer),
1233 gchar *path_str, gpointer data)
1235 GtkWidget *model = static_cast<GtkWidget *>(data);
1240 tpath = gtk_tree_path_new_from_string(path_str);
1241 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1242 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1244 fe->enabled = !fe->enabled;
1246 gtk_tree_path_free(tpath);
1250 static void filter_store_writable_cb(GtkCellRendererToggle *UNUSED(renderer),
1251 gchar *path_str, gpointer data)
1253 GtkWidget *model = static_cast<GtkWidget *>(data);
1258 tpath = gtk_tree_path_new_from_string(path_str);
1259 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1260 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1262 fe->writable = !fe->writable;
1263 if (fe->writable) fe->allow_sidecar = FALSE;
1265 gtk_tree_path_free(tpath);
1269 static void filter_store_sidecar_cb(GtkCellRendererToggle *UNUSED(renderer),
1270 gchar *path_str, gpointer data)
1272 GtkWidget *model = static_cast<GtkWidget *>(data);
1277 tpath = gtk_tree_path_new_from_string(path_str);
1278 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1279 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1281 fe->allow_sidecar = !fe->allow_sidecar;
1282 if (fe->allow_sidecar) fe->writable = FALSE;
1284 gtk_tree_path_free(tpath);
1288 static void filter_set_func(GtkTreeViewColumn *UNUSED(tree_column), GtkCellRenderer *cell,
1289 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1293 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1295 switch (GPOINTER_TO_INT(data))
1298 g_object_set(GTK_CELL_RENDERER(cell),
1299 "active", fe->enabled, NULL);
1302 g_object_set(GTK_CELL_RENDERER(cell),
1303 "text", fe->extensions, NULL);
1305 case FE_DESCRIPTION:
1306 g_object_set(GTK_CELL_RENDERER(cell),
1307 "text", fe->description, NULL);
1310 g_object_set(GTK_CELL_RENDERER(cell),
1311 "text", _(format_class_list[fe->file_class]), NULL);
1314 g_object_set(GTK_CELL_RENDERER(cell),
1315 "active", fe->writable, NULL);
1317 case FE_ALLOW_SIDECAR:
1318 g_object_set(GTK_CELL_RENDERER(cell),
1319 "active", fe->allow_sidecar, NULL);
1324 static gboolean filter_add_scroll(gpointer data)
1328 GtkCellRenderer *cell;
1329 GtkTreeViewColumn *column;
1332 GtkTreeModel *store;
1334 FilterEntry *filter;
1336 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1337 path = gtk_tree_path_new_from_indices(rows-1, -1);
1339 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1341 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1342 cell = static_cast<GtkCellRenderer *>(g_list_last(list_cells)->data);
1344 store = gtk_tree_view_get_model(GTK_TREE_VIEW(data));
1345 valid = gtk_tree_model_get_iter_first(store, &iter);
1349 gtk_tree_model_get(store, &iter, 0, &filter, -1);
1351 if (g_strcmp0(filter->extensions, ".new") == 0)
1353 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
1357 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1360 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1361 path, column, FALSE, 0.0, 0.0 );
1362 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1363 path, column, cell, TRUE);
1365 gtk_tree_path_free(path);
1366 g_list_free(list_cells);
1371 static void filter_add_cb(GtkWidget *UNUSED(widget), gpointer data)
1373 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1374 filter_store_populate();
1376 g_idle_add((GSourceFunc)filter_add_scroll, data);
1379 static void filter_remove_cb(GtkWidget *UNUSED(widget), gpointer data)
1381 GtkWidget *filter_view = static_cast<GtkWidget *>(data);
1382 GtkTreeSelection *selection;
1386 if (!filter_store) return;
1387 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1388 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1389 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1392 filter_remove_entry(fe);
1394 filter_store_populate();
1397 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1401 GtkTreeViewColumn *column;
1403 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1404 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1405 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1407 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1411 gtk_tree_path_free(path);
1416 static void filter_default_ok_cb(GenericDialog *gd, gpointer UNUSED(data))
1419 filter_add_defaults();
1421 filter_store_populate();
1423 g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1426 static void dummy_cancel_cb(GenericDialog *UNUSED(gd), gpointer UNUSED(data))
1428 /* no op, only so cancel button appears */
1431 static void filter_default_cb(GtkWidget *widget, gpointer data)
1435 gd = generic_dialog_new(_("Reset filters"),
1436 "reset_filter", widget, TRUE,
1437 dummy_cancel_cb, data);
1438 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1439 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1440 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1441 gtk_widget_show(gd->dialog);
1444 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1446 GtkWidget *frame = static_cast<GtkWidget *>(data);
1448 gtk_widget_set_sensitive(frame,
1449 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1452 static void safe_delete_view_cb(GtkWidget *UNUSED(widget), gpointer UNUSED(data))
1454 layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1457 static void safe_delete_clear_ok_cb(GenericDialog *UNUSED(gd), gpointer UNUSED(data))
1459 file_util_trash_clear();
1462 static void safe_delete_clear_cb(GtkWidget *widget, gpointer UNUSED(data))
1466 gd = generic_dialog_new(_("Clear trash"),
1467 "clear_trash", widget, TRUE,
1468 dummy_cancel_cb, NULL);
1469 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1470 _("This will remove the trash contents."), FALSE);
1471 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1472 entry = gtk_entry_new();
1473 gtk_widget_set_can_focus(entry, FALSE);
1474 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1475 if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1476 gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1477 gtk_widget_show(entry);
1478 gtk_widget_show(gd->dialog);
1481 static void image_overlay_template_view_changed_cb(GtkWidget *UNUSED(widget), gpointer data)
1483 GtkWidget *pTextView;
1484 GtkTextBuffer *pTextBuffer;
1488 pTextView = GTK_WIDGET(data);
1490 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1491 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1492 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1494 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1495 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1498 static void image_overlay_default_template_ok_cb(GenericDialog *UNUSED(gd), gpointer data)
1500 GtkTextView *text_view = static_cast<GtkTextView *>(data);
1501 GtkTextBuffer *buffer;
1503 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1504 if (!configwindow) return;
1506 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1507 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1510 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1514 gd = generic_dialog_new(_("Reset image overlay template string"),
1515 "reset_image_overlay_template_string", widget, TRUE,
1516 dummy_cancel_cb, data);
1517 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1518 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1519 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1520 gtk_widget_show(gd->dialog);
1523 static void image_overlay_help_cb(GtkWidget *UNUSED(widget), gpointer UNUSED(data))
1525 help_window_show("GuideOptionsOSD.html");
1528 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer UNUSED(data))
1532 PangoFontDescription *font_desc;
1534 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1535 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1537 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1539 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1540 font = pango_font_description_to_string(font_desc);
1541 g_free(c_options->image_overlay.font);
1542 c_options->image_overlay.font = g_strdup(font);
1546 gtk_widget_destroy(dialog);
1549 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer UNUSED(data))
1554 dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1555 colour.red = options->image_overlay.text_red;
1556 colour.green = options->image_overlay.text_green;
1557 colour.blue = options->image_overlay.text_blue;
1558 colour.alpha = options->image_overlay.text_alpha;
1559 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1560 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1562 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1564 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1565 c_options->image_overlay.text_red = colour.red*255;
1566 c_options->image_overlay.text_green = colour.green*255;
1567 c_options->image_overlay.text_blue = colour.blue*255;
1568 c_options->image_overlay.text_alpha = colour.alpha*255;
1570 gtk_widget_destroy(dialog);
1574 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer UNUSED(data))
1579 dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1580 colour.red = options->image_overlay.background_red;
1581 colour.green = options->image_overlay.background_green;
1582 colour.blue = options->image_overlay.background_blue;
1583 colour.alpha = options->image_overlay.background_alpha;
1584 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1585 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1587 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1589 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1590 c_options->image_overlay.background_red = colour.red*255;
1591 c_options->image_overlay.background_green = colour.green*255;
1592 c_options->image_overlay.background_blue = colour.blue*255;
1593 c_options->image_overlay.background_alpha = colour.alpha*255;
1595 gtk_widget_destroy(dialog);
1598 static void accel_store_populate(void)
1601 GList *groups, *actions;
1603 const gchar *accel_path;
1607 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1609 gtk_tree_store_clear(accel_store);
1610 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 */
1612 g_assert(lw && lw->ui_manager);
1613 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1616 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1619 action = GTK_ACTION(actions->data);
1620 accel_path = gtk_action_get_accel_path(action);
1621 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1623 gchar *label, *label2, *tooltip, *accel;
1624 g_object_get(action,
1625 "tooltip", &tooltip,
1629 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1635 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1639 gtk_tree_store_append(accel_store, &iter, NULL);
1640 gtk_tree_store_set(accel_store, &iter,
1643 AE_TOOLTIP, tooltip ? tooltip : "",
1644 AE_ACCEL, accel_path,
1652 actions = actions->next;
1655 groups = groups->next;
1659 static void accel_store_cleared_cb(GtkCellRendererAccel *UNUSED(accel), gchar *UNUSED(path_string), gpointer UNUSED(user_data))
1664 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *UNUSED(path), GtkTreeIter *iter, gpointer data)
1666 gchar *accel1 = static_cast<gchar *>(data);
1671 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1673 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1674 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1676 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1678 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1679 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1688 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))
1690 GtkTreeModel *model = (GtkTreeModel *)accel_store;
1694 GtkAccelKey old_key, key;
1695 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1697 gtk_tree_model_get_iter(model, &iter, path);
1698 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1700 /* test if the accelerator can be stored without conflicts*/
1701 gtk_accel_map_lookup_entry(accel_path, &old_key);
1703 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1704 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1705 gtk_accel_map_lookup_entry(accel_path, &key);
1707 /* restore the original for now, the key will be really changed when the changes are confirmed */
1708 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1710 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1711 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1713 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1714 gtk_tree_path_free(path);
1718 static gboolean accel_default_scroll(GtkTreeView *data)
1722 GtkTreeViewColumn *column;
1724 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1725 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1726 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1728 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1732 gtk_tree_path_free(path);
1737 static void accel_default_cb(GtkWidget *UNUSED(widget), gpointer data)
1739 accel_store_populate();
1741 g_idle_add((GSourceFunc)accel_default_scroll, data);
1744 //void accel_remove_selection(GtkTreeModel *UNUSED(model), GtkTreePath *UNUSED(path), GtkTreeIter *iter, gpointer UNUSED(data))
1746 //gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1749 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *UNUSED(path), GtkTreeIter *iter, gpointer UNUSED(data))
1752 gchar *accel_path, *accel;
1754 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1755 gtk_accel_map_lookup_entry(accel_path, &key);
1756 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1758 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1760 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1765 static void accel_reset_cb(GtkWidget *UNUSED(widget), gpointer data)
1767 GtkTreeSelection *selection;
1769 if (!accel_store) return;
1770 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1771 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1776 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1780 GtkWidget *scrolled;
1781 GtkWidget *viewport;
1783 scrolled = gtk_scrolled_window_new(NULL, NULL);
1784 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1785 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1786 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1787 label = gtk_label_new(title);
1788 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1789 gtk_widget_show(scrolled);
1791 viewport = gtk_viewport_new(NULL, NULL);
1792 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1793 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1794 gtk_widget_show(viewport);
1796 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
1797 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1798 gtk_widget_show(vbox);
1803 static void cache_standard_cb(GtkWidget *widget, gpointer UNUSED(data))
1805 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1807 c_options->thumbnails.spec_standard =TRUE;
1808 c_options->thumbnails.cache_into_dirs = FALSE;
1812 static void cache_geeqie_cb(GtkWidget *widget, gpointer UNUSED(data))
1814 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1816 c_options->thumbnails.spec_standard =FALSE;
1817 c_options->thumbnails.cache_into_dirs = FALSE;
1821 static void cache_local_cb(GtkWidget *widget, gpointer UNUSED(data))
1823 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1825 c_options->thumbnails.cache_into_dirs = TRUE;
1826 c_options->thumbnails.spec_standard =FALSE;
1830 static void help_search_engine_entry_icon_cb(GtkEntry *UNUSED(entry), GtkEntryIconPosition pos,
1831 GdkEvent *UNUSED(event), gpointer userdata)
1833 if (pos == GTK_ENTRY_ICON_PRIMARY)
1835 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1839 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1843 static void star_rating_star_icon_cb(GtkEntry *UNUSED(entry), GtkEntryIconPosition pos,
1844 GdkEvent *UNUSED(event), gpointer userdata)
1846 gchar *rating_symbol;
1848 if (pos == GTK_ENTRY_ICON_PRIMARY)
1850 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1851 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1852 g_free(rating_symbol);
1856 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1857 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1858 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1862 static void star_rating_rejected_icon_cb(GtkEntry *UNUSED(entry), GtkEntryIconPosition pos,
1863 GdkEvent *UNUSED(event), gpointer userdata)
1865 gchar *rating_symbol;
1867 if (pos == GTK_ENTRY_ICON_PRIMARY)
1869 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1870 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1871 g_free(rating_symbol);
1875 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1876 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1877 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1881 static guint star_rating_symbol_test(GtkWidget *UNUSED(widget), gpointer data)
1883 GtkContainer *hbox = static_cast<GtkContainer *>(data);
1884 GString *str = g_string_new(NULL);
1885 GtkEntry *hex_code_entry;
1886 gchar *hex_code_full;
1889 guint64 hex_value = 0;
1891 list = gtk_container_get_children(hbox);
1893 hex_code_entry = static_cast<GtkEntry *>(g_list_nth_data(list, 2));
1894 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1896 hex_code = g_strsplit(hex_code_full, "+", 2);
1897 if (hex_code[0] && hex_code[1])
1899 hex_value = strtoull(hex_code[1], NULL, 16);
1901 if (!hex_value || hex_value > 0x10FFFF)
1903 hex_value = 0x003F; // Unicode 'Question Mark'
1905 str = g_string_append_unichar(str, (gunichar)hex_value);
1906 gtk_label_set_text(static_cast<GtkLabel *>(g_list_nth_data(list, 1)), str->str);
1908 g_strfreev(hex_code);
1909 g_string_free(str, TRUE);
1910 g_free(hex_code_full);
1915 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1917 guint64 star_symbol;
1919 star_symbol = star_rating_symbol_test(widget, data);
1920 c_options->star_rating.star = star_symbol;
1923 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1925 guint64 rejected_symbol;
1927 rejected_symbol = star_rating_symbol_test(widget, data);
1928 c_options->star_rating.rejected = rejected_symbol;
1931 /* general options tab */
1932 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1933 typedef struct _TZData TZData;
1937 GCancellable *cancellable;
1939 GtkWidget *progress;
1941 GFile *timezone_database_gq;
1942 gchar *timezone_database_user;
1945 static void config_tab_general(GtkWidget *notebook)
1950 GtkWidget *group_frame;
1951 GtkWidget *subgroup;
1953 GtkWidget *ct_button;
1956 gint hours, minutes, remainder;
1958 GtkWidget *star_rating_entry;
1960 gchar *rating_symbol;
1963 gchar *download_locn;
1964 GNetworkMonitor *net_mon;
1965 GSocketConnectable *tz_org;
1966 gboolean internet_available = FALSE;
1969 vbox = scrolled_notebook_page(notebook, _("General"));
1971 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1973 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1974 add_thumb_size_menu(table, 0, 0, _("Size:"));
1975 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1977 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1978 pref_label_new(hbox, _("Custom size: "));
1979 pref_spin_new_int(hbox, _("Width:"), NULL, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
1980 pref_spin_new_int(hbox, _("Height:"), NULL, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
1982 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
1983 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1985 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1986 pref_checkbox_link_sensitivity(ct_button, subgroup);
1988 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
1989 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
1990 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
1991 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1992 button = pref_radiobutton_new(group_frame, NULL, get_thumbnails_cache_dir(),
1993 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1994 G_CALLBACK(cache_geeqie_cb), NULL);
1996 group_frame = pref_frame_new(subgroup, TRUE,
1997 _("Store thumbnails local to image folder (non-standard)"),
1998 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1999 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
2000 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
2001 G_CALLBACK(cache_local_cb), NULL);
2003 group_frame = pref_frame_new(subgroup, TRUE,
2004 _("Use standard thumbnail style and cache, shared with other applications"),
2005 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2006 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
2007 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2008 G_CALLBACK(cache_standard_cb), NULL);
2010 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
2011 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
2013 pref_checkbox_new_int(group, _("Thumbnail color management"),
2014 options->thumbnails.use_color_management, &c_options->thumbnails.use_color_management);
2016 spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
2018 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
2019 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
2021 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
2022 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
2023 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
2025 // pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
2026 // options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
2029 pref_spacer(group, PREF_PAD_GROUP);
2031 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
2033 c_options->star_rating.star = options->star_rating.star;
2034 c_options->star_rating.rejected = options->star_rating.rejected;
2036 str = g_string_new(NULL);
2037 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2038 pref_label_new(hbox, _("Star character: "));
2039 str = g_string_append_unichar(str, options->star_rating.star);
2040 pref_label_new(hbox, g_strdup(str->str));
2041 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
2042 star_rating_entry = gtk_entry_new();
2043 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2044 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2045 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2046 gtk_widget_show(star_rating_entry);
2047 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2048 G_CALLBACK(star_rating_star_test_cb), hbox);
2049 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2050 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2051 gtk_widget_show(button);
2052 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."));
2053 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2054 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2055 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2056 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2057 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2058 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2059 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2060 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2061 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2062 G_CALLBACK(star_rating_star_icon_cb),
2065 g_string_free(str, TRUE);
2066 g_free(rating_symbol);
2068 str = g_string_new(NULL);
2069 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2070 pref_label_new(hbox, _("Rejected character: "));
2071 str = g_string_append_unichar(str, options->star_rating.rejected);
2072 pref_label_new(hbox, g_strdup(str->str));
2073 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2074 star_rating_entry = gtk_entry_new();
2075 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2076 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2077 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2078 gtk_widget_show(star_rating_entry);
2079 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2080 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2081 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2082 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2083 gtk_widget_show(button);
2084 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."));
2085 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2086 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2087 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2088 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2089 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2090 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2091 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2092 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2093 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2094 G_CALLBACK(star_rating_rejected_icon_cb),
2097 g_string_free(str, TRUE);
2098 g_free(rating_symbol);
2100 pref_spacer(group, PREF_PAD_GROUP);
2102 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2104 c_options->slideshow.delay = options->slideshow.delay;
2105 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2106 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2107 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2108 seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2109 SLIDESHOW_SUBSECOND_PRECISION;
2111 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2113 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2115 options->slideshow.delay ? hours : 0.0,
2116 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2117 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2118 spin = pref_spin_new(hbox, ":" , NULL,
2120 options->slideshow.delay ? minutes: 0.0,
2121 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2122 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2123 spin = pref_spin_new(hbox, ":", NULL,
2124 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2125 options->slideshow.delay ? seconds : 10.0,
2126 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2127 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2129 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2130 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2132 pref_spacer(group, PREF_PAD_GROUP);
2134 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2136 pref_spin_new_int(group, _("Decoded image cache size (MiB):"), NULL,
2137 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2138 pref_checkbox_new_int(group, _("Preload next image"),
2139 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2141 pref_checkbox_new_int(group, _("Refresh on file change"),
2142 options->update_on_time_change, &c_options->update_on_time_change);
2145 pref_spacer(group, PREF_PAD_GROUP);
2147 group = pref_group_new(vbox, FALSE, _("Expand menu and toolbar"), GTK_ORIENTATION_VERTICAL);
2149 pref_checkbox_new_int(group, _("Expand menu and toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2150 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2151 gtk_widget_set_tooltip_text(group, _("Expand the menu and toolbar to the full width of the window"));
2153 pref_spacer(group, PREF_PAD_GROUP);
2155 if (g_getenv("APPDIR") && strstr(g_getenv("APPDIR"), "/tmp/.mount_Geeqie"))
2157 group = pref_group_new(vbox, FALSE, _("AppImage updates notifications"), GTK_ORIENTATION_VERTICAL);
2158 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2159 pref_checkbox_new_int(group, _("Enable"), options->appimage_notifications, &c_options->appimage_notifications);
2160 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"));
2162 pref_spacer(group, PREF_PAD_GROUP);
2166 net_mon = g_network_monitor_get_default();
2167 tz_org = g_network_address_parse_uri(TIMEZONE_DATABASE_WEB, 80, NULL);
2170 internet_available = g_network_monitor_can_reach(net_mon, tz_org, NULL, NULL);
2171 g_object_unref(tz_org);
2174 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2175 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2177 if (!internet_available)
2179 gtk_widget_set_sensitive(group, FALSE);
2182 tz = g_new0(TZData, 1);
2184 path = path_from_utf8(TIMEZONE_DATABASE_WEB);
2185 basename = g_path_get_basename(path);
2186 tz->timezone_database_user = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
2190 if (isfile(tz->timezone_database_user))
2192 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2196 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2199 download_locn = g_strconcat(_("Download database from: "), TIMEZONE_DATABASE_WEB, NULL);
2200 pref_label_new(GTK_WIDGET(hbox), download_locn);
2201 g_free(download_locn);
2203 if (!internet_available)
2205 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"));
2209 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"));
2211 gtk_widget_show(button);
2213 pref_spacer(group, PREF_PAD_GROUP);
2215 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2217 help_search_engine_entry = gtk_entry_new();
2218 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2219 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2220 gtk_widget_show(help_search_engine_entry);
2222 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"));
2224 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2225 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2226 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2227 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2228 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2229 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2230 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2231 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2232 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2233 G_CALLBACK(help_search_engine_entry_icon_cb),
2234 help_search_engine_entry);
2238 static void config_tab_image(GtkWidget *notebook)
2243 GtkWidget *ct_button;
2244 GtkWidget *enlargement_button;
2247 //~ #ifdef HAVE_CLUTTER
2248 //~ GtkWidget *gpu_accel;
2251 vbox = scrolled_notebook_page(notebook, _("Image"));
2253 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2255 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2256 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2257 //~ if (options->image.use_clutter_renderer && !options->disable_gpu)
2259 //~ gtk_widget_set_sensitive(table, FALSE);
2262 //~ #ifdef HAVE_CLUTTER
2263 //~ gpu_accel = pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library (Requires restart)"),
2264 //~ options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2265 //~ if (options->disable_gpu && !options->override_disable_gpu)
2267 //~ gtk_widget_set_sensitive(gpu_accel, FALSE);
2271 pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2272 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2273 //~ if (options->image.use_clutter_renderer && !options->disable_gpu)
2275 //~ gtk_widget_set_sensitive(two_pass, FALSE);
2278 c_options->image.zoom_increment = options->image.zoom_increment;
2279 spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2280 0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2281 G_CALLBACK(zoom_increment_cb), NULL);
2282 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2284 c_options->image.zoom_style = options->image.zoom_style;
2285 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2286 add_zoom_style_selection_menu(table, 0, 0, _("Zoom style:"), options->image.zoom_style, &c_options->image.zoom_style);
2288 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2290 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2291 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2292 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2293 spin = pref_spin_new_int(hbox, NULL, NULL,
2295 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2296 pref_checkbox_link_sensitivity(enlargement_button, spin);
2297 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."));
2299 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2300 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2301 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2302 spin = pref_spin_new_int(hbox, NULL, NULL,
2304 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2305 pref_checkbox_link_sensitivity(ct_button, spin);
2306 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."));
2308 group = pref_group_new(vbox, FALSE, _("Tile size"), GTK_ORIENTATION_VERTICAL);
2309 //~ gtk_widget_set_sensitive(group, !options->image.use_clutter_renderer);
2311 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2312 spin = pref_spin_new_int(hbox, _("Pixels"), _("(Requires restart)"),
2314 options->image.tile_size, &c_options->image.tile_size);
2315 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."));
2317 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2319 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2320 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2322 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2323 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2325 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2326 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2328 c_options->image.border_color = options->image.border_color;
2330 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2331 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2333 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2334 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2336 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2337 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2342 static void save_default_window_layout_cb(GtkWidget *UNUSED(widget), gpointer UNUSED(data))
2344 LayoutWindow *lw = NULL;
2345 gchar *default_path;
2348 /* Get current lw */
2351 tmp_id = lw->options.id;
2352 lw->options.id = g_strdup("lw_default");
2354 default_path = g_build_filename(get_rc_dir(), DEFAULT_WINDOW_LAYOUT, NULL);
2355 save_default_layout_options_to_file(default_path, options, lw);
2356 g_free(lw->options.id);
2357 lw->options.id = tmp_id;
2358 g_free(default_path);
2361 static gboolean popover_cb(gpointer data)
2363 GtkPopover *popover = static_cast<GtkPopover *>(data);
2365 gtk_popover_popdown(popover);
2370 static void default_layout_changed_cb(GtkWidget *UNUSED(button), GtkPopover *popover)
2372 gtk_popover_popup(popover);
2374 g_timeout_add(2000, popover_cb, popover);
2377 static GtkWidget *create_popover(GtkWidget *parent, GtkWidget *child, GtkPositionType pos)
2381 popover = gtk_popover_new(parent);
2382 gtk_popover_set_position(GTK_POPOVER (popover), pos);
2383 gtk_container_add (GTK_CONTAINER(popover), child);
2384 gtk_container_set_border_width(GTK_CONTAINER (popover), 6);
2385 gtk_widget_show (child);
2390 static void config_tab_windows(GtkWidget *notebook)
2395 GtkWidget *subgroup;
2397 GtkWidget *ct_button;
2400 vbox = scrolled_notebook_page(notebook, _("Windows"));
2402 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2404 ct_button = pref_checkbox_new_int(group, _("Remember session"),
2405 options->save_window_positions, &c_options->save_window_positions);
2407 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2408 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2409 pref_checkbox_link_sensitivity(ct_button, button);
2411 button = pref_checkbox_new_int(group, _("Remember window workspace"),
2412 options->save_window_workspace, &c_options->save_window_workspace);
2413 pref_checkbox_link_sensitivity(ct_button, button);
2415 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2416 options->tools_restore_state, &c_options->tools_restore_state);
2418 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2419 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2421 pref_checkbox_new_int(group, _("Show window IDs"),
2422 options->show_window_ids, &c_options->show_window_ids);
2424 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2425 pref_label_new(subgroup, _("Use current layout for default: "));
2426 button = pref_button_new(subgroup, NULL, _("Set"), FALSE, G_CALLBACK(save_default_window_layout_cb), NULL);
2430 popover = create_popover(button, gtk_label_new(_("Current window layout\nhas been set as default")), GTK_POS_TOP);
2431 gtk_popover_set_modal(GTK_POPOVER (popover), FALSE);
2432 g_signal_connect(button, "clicked", G_CALLBACK(default_layout_changed_cb), popover);
2434 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2436 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2437 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2439 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2440 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2441 options->image.limit_window_size, &c_options->image.limit_window_size);
2442 spin = pref_spin_new_int(hbox, NULL, NULL,
2444 options->image.max_window_size, &c_options->image.max_window_size);
2445 pref_checkbox_link_sensitivity(ct_button, spin);
2447 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2449 c_options->fullscreen.screen = options->fullscreen.screen;
2450 c_options->fullscreen.above = options->fullscreen.above;
2451 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2452 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2453 gtk_widget_show(hbox);
2455 pref_checkbox_new_int(group, _("Smooth image flip"),
2456 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2457 pref_checkbox_new_int(group, _("Disable screen saver"),
2458 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2461 #define PRE_FORMATTED_COLUMNS 5
2462 static void config_tab_osd(GtkWidget *notebook)
2468 GtkWidget *image_overlay_template_view;
2469 GtkWidget *scrolled;
2470 GtkWidget *scrolled_pre_formatted;
2471 GtkTextBuffer *buffer;
2473 GtkWidget *subgroup;
2475 vbox = scrolled_notebook_page(notebook, _("OSD"));
2477 image_overlay_template_view = gtk_text_view_new();
2479 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2481 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2483 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2484 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2485 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2486 gtk_widget_show(scrolled_pre_formatted);
2487 gtk_widget_show(subgroup);
2489 pref_line(group, PREF_PAD_GAP);
2491 pref_label_new(group, _("Image overlay template"));
2493 scrolled = gtk_scrolled_window_new(NULL, NULL);
2494 gtk_widget_set_size_request(scrolled, 200, 150);
2495 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2496 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2497 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2498 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2499 gtk_widget_show(scrolled);
2501 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2502 _("Extensive formatting options are shown in the Help file"));
2504 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2505 gtk_widget_show(image_overlay_template_view);
2507 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2509 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2510 G_CALLBACK(image_overlay_set_font_cb), notebook);
2512 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2513 gtk_widget_show(button);
2515 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2516 G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2517 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2518 gtk_widget_show(button);
2520 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2521 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2522 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2523 gtk_widget_show(button);
2524 image_overlay_set_text_colours();
2526 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2527 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2528 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2529 gtk_widget_show(button);
2531 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2532 G_CALLBACK(image_overlay_help_cb), NULL);
2533 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2534 gtk_widget_show(button);
2536 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2537 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2538 g_signal_connect(G_OBJECT(buffer), "changed",
2539 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2541 pref_line(group, PREF_PAD_GAP);
2543 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2544 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2545 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2546 gtk_widget_show(hbox);
2547 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2548 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2549 gtk_widget_show(label);
2550 pref_spacer(group,TRUE);
2552 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2553 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2554 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2555 gtk_widget_show(hbox);
2556 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2557 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2558 gtk_widget_show(label);
2559 pref_spacer(group,TRUE);
2561 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2562 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2563 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2564 gtk_widget_show(hbox);
2565 label = gtk_label_new(_("%path:39%"));
2566 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2567 gtk_widget_show(label);
2568 pref_spacer(group,TRUE);
2570 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2571 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2572 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2573 gtk_widget_show(hbox);
2574 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%"));
2575 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2576 gtk_widget_show(label);
2577 pref_spacer(group,TRUE);
2579 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2580 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
2581 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2582 gtk_widget_show(hbox);
2583 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2584 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2585 gtk_widget_show(label);
2588 static GtkTreeModel *create_class_model(void)
2590 GtkListStore *model;
2594 /* create list store */
2595 model = gtk_list_store_new(1, G_TYPE_STRING);
2596 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2598 gtk_list_store_append(model, &iter);
2599 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2601 return GTK_TREE_MODEL (model);
2606 static gint filter_table_sort_cb(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data)
2608 gint n = GPOINTER_TO_INT(data);
2610 FilterEntry *filter_a;
2611 FilterEntry *filter_b;
2613 gtk_tree_model_get(model, a, 0, &filter_a, -1);
2614 gtk_tree_model_get(model, b, 0, &filter_b, -1);
2618 case FILETYPES_COLUMN_ENABLED:
2620 ret = filter_a->enabled - filter_b->enabled;
2623 case FILETYPES_COLUMN_FILTER:
2625 ret = g_utf8_collate(filter_a->extensions, filter_b->extensions);
2628 case FILETYPES_COLUMN_DESCRIPTION:
2630 ret = g_utf8_collate(filter_a->description, filter_b->description);
2633 case FILETYPES_COLUMN_CLASS:
2635 ret = g_strcmp0(format_class_list[filter_a->file_class], format_class_list[filter_b->file_class]);
2638 case FILETYPES_COLUMN_WRITABLE:
2640 ret = filter_a->writable - filter_b->writable;
2643 case FILETYPES_COLUMN_SIDECAR:
2645 ret = filter_a->allow_sidecar - filter_b->allow_sidecar;
2649 g_return_val_if_reached(0);
2655 static gboolean search_function_cb(GtkTreeModel *model, gint UNUSED(column), const gchar *key, GtkTreeIter *iter, gpointer UNUSED(search_data))
2658 gboolean ret = TRUE;
2660 gtk_tree_model_get(model, iter, 0, &fe, -1);
2662 if (g_strstr_len(fe->extensions, -1, key))
2670 static void config_tab_files(GtkWidget *notebook)
2677 GtkWidget *ct_button;
2678 GtkWidget *scrolled;
2679 GtkWidget *filter_view;
2680 GtkCellRenderer *renderer;
2681 GtkTreeSelection *selection;
2682 GtkTreeViewColumn *column;
2684 vbox = scrolled_notebook_page(notebook, _("File Filters"));
2686 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2688 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2689 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2690 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2691 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2692 pref_checkbox_new_int(group, _("Case sensitive sort"),
2693 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2694 pref_checkbox_new_int(group, _("Natural sort order - Requires restart"),
2695 options->file_sort.natural, &c_options->file_sort.natural);
2696 pref_checkbox_new_int(group, _("Disable file extension checks"),
2697 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2699 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2700 options->file_filter.disable, &c_options->file_filter.disable);
2703 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2705 sidecar_ext_entry = gtk_entry_new();
2706 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2707 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2708 gtk_widget_show(sidecar_ext_entry);
2710 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2712 frame = pref_group_parent(group);
2713 g_signal_connect(G_OBJECT(ct_button), "toggled",
2714 G_CALLBACK(filter_disable_cb), frame);
2715 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2717 scrolled = gtk_scrolled_window_new(NULL, NULL);
2718 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2719 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2720 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2721 gtk_widget_show(scrolled);
2723 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2724 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2725 g_object_unref(filter_store);
2726 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2727 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2729 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2731 column = gtk_tree_view_column_new();
2732 gtk_tree_view_column_set_title(column, _("Enabled"));
2733 gtk_tree_view_column_set_resizable(column, TRUE);
2735 renderer = gtk_cell_renderer_toggle_new();
2736 g_signal_connect(G_OBJECT(renderer), "toggled",
2737 G_CALLBACK(filter_store_enable_cb), filter_store);
2738 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2739 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2740 GINT_TO_POINTER(FE_ENABLE), NULL);
2741 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);
2742 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_ENABLED);
2743 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2745 column = gtk_tree_view_column_new();
2746 gtk_tree_view_column_set_title(column, _("Filter"));
2747 gtk_tree_view_column_set_resizable(column, TRUE);
2748 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);
2749 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_FILTER);
2751 renderer = gtk_cell_renderer_text_new();
2752 g_signal_connect(G_OBJECT(renderer), "edited",
2753 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2754 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2755 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2756 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2757 GINT_TO_POINTER(FE_EXTENSION), NULL);
2758 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2760 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), TRUE);
2761 gtk_tree_view_set_search_column(GTK_TREE_VIEW(filter_view), FILETYPES_COLUMN_FILTER);
2762 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(filter_view), search_function_cb, NULL, NULL);
2764 column = gtk_tree_view_column_new();
2765 gtk_tree_view_column_set_title(column, _("Description"));
2766 gtk_tree_view_column_set_resizable(column, TRUE);
2767 gtk_tree_view_column_set_fixed_width(column, 200);
2768 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2770 renderer = gtk_cell_renderer_text_new();
2771 g_signal_connect(G_OBJECT(renderer), "edited",
2772 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2773 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2774 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2775 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2776 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2777 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2778 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);
2779 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_DESCRIPTION);
2781 column = gtk_tree_view_column_new();
2782 gtk_tree_view_column_set_title(column, _("Class"));
2783 gtk_tree_view_column_set_resizable(column, TRUE);
2784 renderer = gtk_cell_renderer_combo_new();
2785 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2786 "model", create_class_model(),
2791 g_signal_connect(G_OBJECT(renderer), "edited",
2792 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2793 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2794 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2795 GINT_TO_POINTER(FE_CLASS), NULL);
2796 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2797 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);
2798 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_CLASS);
2800 column = gtk_tree_view_column_new();
2801 gtk_tree_view_column_set_title(column, _("Writable"));
2802 gtk_tree_view_column_set_resizable(column, FALSE);
2803 renderer = gtk_cell_renderer_toggle_new();
2804 g_signal_connect(G_OBJECT(renderer), "toggled",
2805 G_CALLBACK(filter_store_writable_cb), filter_store);
2806 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2807 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2808 GINT_TO_POINTER(FE_WRITABLE), NULL);
2809 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2810 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);
2811 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_WRITABLE);
2813 column = gtk_tree_view_column_new();
2814 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2815 gtk_tree_view_column_set_resizable(column, FALSE);
2816 renderer = gtk_cell_renderer_toggle_new();
2817 g_signal_connect(G_OBJECT(renderer), "toggled",
2818 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2819 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2820 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2821 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2822 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2823 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);
2824 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_SIDECAR);
2826 filter_store_populate();
2827 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2828 gtk_widget_show(filter_view);
2830 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2832 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2833 G_CALLBACK(filter_default_cb), filter_view);
2834 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2835 gtk_widget_show(button);
2837 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2838 G_CALLBACK(filter_remove_cb), filter_view);
2839 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2840 gtk_widget_show(button);
2842 button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2843 G_CALLBACK(filter_add_cb), filter_view);
2844 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2845 gtk_widget_show(button);
2849 static void config_tab_metadata(GtkWidget *notebook)
2854 GtkWidget *ct_button;
2856 GtkWidget *tmp_widget;
2858 GtkWidget *text_label;
2860 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2863 group = pref_group_new(vbox, FALSE, _("Metadata writing sequence"), GTK_ORIENTATION_VERTICAL);
2865 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2867 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."));
2868 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2869 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2871 gtk_widget_set_tooltip_text(label, _("A flowchart of the sequence is shown in the Help file"));
2873 ct_button = pref_checkbox_new_int(group, "", options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2874 text_label = gtk_bin_get_child(GTK_BIN(ct_button));
2875 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"));
2876 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2878 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)"));
2879 gtk_widget_set_tooltip_markup(ct_button, markup);
2883 gtk_widget_set_sensitive(ct_button, FALSE);
2886 tmp_widget = pref_checkbox_new_int(group, "", options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2887 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2888 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)"));
2889 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2892 label = pref_label_new(group, "");
2893 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(), "/");
2894 gtk_label_set_markup (GTK_LABEL(label), markup);
2897 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2898 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2899 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2900 pref_spacer(group, PREF_PAD_GROUP);
2902 group = pref_group_new(vbox, FALSE, _("Step 1 Options:"), GTK_ORIENTATION_VERTICAL);
2904 gtk_widget_set_sensitive(group, FALSE);
2907 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2908 pref_checkbox_link_sensitivity(ct_button, hbox);
2910 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);
2911 gtk_widget_set_tooltip_text(tmp_widget, _("A simplified conversion list is in the Help file"));
2913 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);
2915 pref_checkbox_new_int(hbox, _("Ask before writing to image files"), options->metadata.confirm_write, &c_options->metadata.confirm_write);
2917 tmp_widget= pref_checkbox_new_int(hbox, "", options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2918 gtk_widget_set_tooltip_text(tmp_widget, _("This file naming convention is used by Darktable"));
2919 text_label = gtk_bin_get_child(GTK_BIN(tmp_widget));
2920 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", ")");
2921 gtk_label_set_markup (GTK_LABEL(text_label), markup);
2924 pref_spacer(group, PREF_PAD_GROUP);
2926 group = pref_group_new(vbox, FALSE, _("Steps 2 and 3 Option:"), GTK_ORIENTATION_VERTICAL);
2928 gtk_widget_set_sensitive(group, FALSE);
2931 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);
2933 pref_spacer(group, PREF_PAD_GROUP);
2935 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2936 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);
2937 gtk_widget_set_tooltip_text(tmp_widget, _("See the Help file for a list of the tags used"));
2939 tmp_widget = pref_checkbox_new_int(group, _("Permit Keywords to be case-sensitive"), options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2940 gtk_widget_set_tooltip_text(tmp_widget, _("When selected, \"Place\" and \"place\" are two different keywords"));
2942 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"), options->metadata.write_orientation, &c_options->metadata.write_orientation);
2943 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"));
2946 gtk_widget_set_sensitive(ct_button, FALSE);
2949 pref_spacer(group, PREF_PAD_GROUP);
2951 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2953 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"), options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2955 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2956 pref_checkbox_link_sensitivity(ct_button, hbox);
2958 pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1, options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2960 pref_checkbox_new_int(group, _("Write metadata on image change"), options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2962 pref_checkbox_new_int(group, _("Write metadata on directory change"), options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2964 pref_spacer(group, PREF_PAD_GROUP);
2967 group = pref_group_new(vbox, FALSE, _("Spelling checks"), GTK_ORIENTATION_VERTICAL);
2969 ct_button = pref_checkbox_new_int(group, _("Check spelling - Requires restart"), options->metadata.check_spelling, &c_options->metadata.check_spelling);
2970 gtk_widget_set_tooltip_text(ct_button, _("Spelling checks are performed on info sidebar panes Comment, Headline and Title"));
2973 pref_spacer(group, PREF_PAD_GROUP);
2975 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2977 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"), options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2978 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");
2983 typedef struct _KeywordFindData KeywordFindData;
2984 struct _KeywordFindData
2991 GtkWidget *button_close;
2992 GtkWidget *button_stop;
2993 GtkWidget *button_start;
2994 GtkWidget *progress;
3002 guint idle_id; /* event source id */
3005 #define KEYWORD_DIALOG_WIDTH 400
3007 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
3009 GList *list_d = NULL;
3010 GList *list_f = NULL;
3014 filelist_read(dir_fd, &list_f, &list_d);
3018 filelist_read(dir_fd, &list_f, NULL);
3021 list_f = filelist_filter(list_f, FALSE);
3022 list_d = filelist_filter(list_d, TRUE);
3024 kfd->list = g_list_concat(list_f, kfd->list);
3025 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
3028 static void keywords_find_reset(KeywordFindData *kfd)
3030 filelist_free(kfd->list);
3033 filelist_free(kfd->list_dir);
3034 kfd->list_dir = NULL;
3037 static void keywords_find_close_cb(GenericDialog *UNUSED(fd), gpointer data)
3039 KeywordFindData *kfd = static_cast<KeywordFindData *>(data);
3041 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
3043 keywords_find_reset(kfd);
3044 generic_dialog_close(kfd->gd);
3048 static void keywords_find_finish(KeywordFindData *kfd)
3050 keywords_find_reset(kfd);
3052 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
3053 spinner_set_interval(kfd->spinner, -1);
3055 gtk_widget_set_sensitive(kfd->group, TRUE);
3056 gtk_widget_set_sensitive(kfd->button_start, TRUE);
3057 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3058 gtk_widget_set_sensitive(kfd->button_close, TRUE);
3061 static void keywords_find_stop_cb(GenericDialog *UNUSED(fd), gpointer data)
3063 KeywordFindData *kfd = static_cast<KeywordFindData *>(data);
3065 g_idle_remove_by_data(kfd);
3067 keywords_find_finish(kfd);
3070 static gboolean keywords_find_file(gpointer data)
3072 KeywordFindData *kfd = static_cast<KeywordFindData *>(data);
3074 GtkTextBuffer *buffer;
3082 fd = static_cast<FileData *>(kfd->list->data);
3083 kfd->list = g_list_remove(kfd->list, fd);
3085 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
3086 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3090 gtk_text_buffer_get_end_iter(buffer, &iter);
3091 tmp = g_strconcat(static_cast<const gchar *>(keywords->data), "\n", NULL);
3092 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3094 keywords = keywords->next;
3097 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
3098 file_data_unref(fd);
3099 string_list_free(keywords);
3103 else if (kfd->list_dir)
3107 fd = static_cast<FileData *>(kfd->list_dir->data);
3108 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
3110 keywords_find_folder(kfd, fd);
3112 file_data_unref(fd);
3117 keywords_find_finish(kfd);
3122 static void keywords_find_start_cb(GenericDialog *UNUSED(fd), gpointer data)
3124 KeywordFindData *kfd = static_cast<KeywordFindData *>(data);
3127 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
3129 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
3130 parse_out_relatives(path);
3134 warning_dialog(_("Invalid folder"),
3135 _("The specified folder can not be found."),
3136 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
3142 gtk_widget_set_sensitive(kfd->group, FALSE);
3143 gtk_widget_set_sensitive(kfd->button_start, FALSE);
3144 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
3145 gtk_widget_set_sensitive(kfd->button_close, FALSE);
3146 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
3148 dir_fd = file_data_new_dir(path);
3149 keywords_find_folder(kfd, dir_fd);
3150 file_data_unref(dir_fd);
3151 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
3157 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
3159 KeywordFindData *kfd;
3163 kfd = g_new0(KeywordFindData, 1);
3165 kfd->gd = generic_dialog_new(_("Search for keywords"),
3166 "search_for_keywords",
3169 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
3170 kfd->gd->cancel_cb = keywords_find_close_cb;
3171 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
3172 keywords_find_close_cb, FALSE);
3173 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
3174 keywords_find_start_cb, FALSE);
3175 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
3176 keywords_find_stop_cb, FALSE);
3177 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3179 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
3181 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
3182 pref_spacer(hbox, PREF_PAD_INDENT);
3183 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
3185 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3186 pref_label_new(hbox, _("Folder:"));
3188 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
3189 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
3190 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
3191 gtk_widget_show(label);
3193 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
3195 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
3196 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3198 kfd->progress = gtk_entry_new();
3199 gtk_widget_set_can_focus(kfd->progress, FALSE);
3200 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
3201 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
3202 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
3203 gtk_widget_show(kfd->progress);
3205 kfd->spinner = spinner_new(NULL, -1);
3206 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
3207 gtk_widget_show(kfd->spinner);
3211 gtk_widget_show(kfd->gd->dialog);
3214 static void keywords_find_cb(GtkWidget *widget, gpointer UNUSED(data))
3216 const gchar *path = layout_get_path(NULL);
3218 if (!path || !*path) path = homedir();
3219 keywords_find_dialog(widget, path);
3222 static void config_tab_keywords_save()
3224 GtkTextIter start, end;
3225 GtkTextBuffer *buffer;
3226 GList *kw_list = NULL;
3232 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3233 gtk_text_buffer_get_bounds(buffer, &start, &end);
3235 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3237 kw_split = strtok(buffer_text, "\n");
3238 while (kw_split != NULL)
3244 if (g_strcmp0(static_cast<const gchar *>(work->data), kw_split) == 0)
3253 kw_list = g_list_append(kw_list, g_strdup(kw_split));
3255 kw_split = strtok(NULL, "\n");
3258 keyword_list_set(kw_list);
3260 string_list_free(kw_list);
3261 g_free(buffer_text);
3264 static void config_tab_keywords(GtkWidget *notebook)
3270 GtkWidget *scrolled;
3272 GtkTextBuffer *buffer;
3275 GspellTextView *gspell_view;
3278 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3280 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3282 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3284 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
3285 G_CALLBACK(keywords_find_cb), keyword_text);
3286 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
3289 keyword_text = gtk_text_view_new();
3290 gtk_widget_set_size_request(keyword_text, 20, 20);
3291 scrolled = gtk_scrolled_window_new(NULL, NULL);
3292 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3293 gtk_widget_show(scrolled);
3296 if (options->metadata.check_spelling)
3298 gspell_view = gspell_text_view_get_from_gtk_text_view(GTK_TEXT_VIEW(keyword_text));
3299 gspell_text_view_basic_setup(gspell_view);
3303 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
3304 gtk_widget_show(keyword_text);
3306 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3308 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3309 gtk_text_buffer_create_tag(buffer, "monospace",
3310 "family", "monospace", NULL);
3312 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3313 gtk_text_buffer_get_start_iter(buffer, &iter);
3314 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3317 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3319 GList *kwl = keyword_list_get();
3320 kwl = g_list_first(kwl);
3323 gtk_text_buffer_get_end_iter (buffer, &iter);
3324 tmp = g_strconcat(static_cast<const gchar *>(kwl->data), "\n", NULL);
3325 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3330 gtk_text_buffer_set_modified(buffer, FALSE);
3337 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3339 gint *option = static_cast<gint *>(data);
3341 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3345 *option = INTENT_PERCEPTUAL;
3348 *option = INTENT_RELATIVE_COLORIMETRIC;
3351 *option = INTENT_SATURATION;
3354 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3359 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3360 gint option, gint *option_c)
3367 pref_table_label(table, column, row, text, 0.0);
3369 combo = gtk_combo_box_text_new();
3371 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3372 if (option == INTENT_PERCEPTUAL) current = 0;
3373 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3374 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3375 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3376 if (option == INTENT_SATURATION) current = 2;
3377 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3378 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3380 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3382 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3384 g_signal_connect(G_OBJECT(combo), "changed",
3385 G_CALLBACK(intent_menu_cb), option_c);
3387 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, static_cast<GtkAttachOptions>(0), 0, 0);
3388 gtk_widget_show(combo);
3392 static void config_tab_color(GtkWidget *notebook)
3401 vbox = scrolled_notebook_page(notebook, _("Color management"));
3403 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3405 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3408 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3409 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3411 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3412 pref_label_bold(label, TRUE, FALSE);
3414 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3415 pref_label_bold(label, TRUE, FALSE);
3417 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3418 pref_label_bold(label, TRUE, FALSE);
3420 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3425 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3426 pref_table_label(table, 0, i + 1, buf, 1.0);
3429 entry = gtk_entry_new();
3430 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3431 if (options->color_profile.input_name[i])
3433 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3435 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3436 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), static_cast<GtkAttachOptions>(0), 0, 0);
3437 gtk_widget_show(entry);
3438 color_profile_input_name_entry[i] = entry;
3440 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3441 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3442 gtk_widget_set_size_request(entry, 160, -1);
3443 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3444 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), static_cast<GtkAttachOptions>(0), 0, 0);
3445 gtk_widget_show(tabcomp);
3446 color_profile_input_file_entry[i] = entry;
3449 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3451 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3453 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3454 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3456 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3458 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3459 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3460 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3461 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3462 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3464 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3466 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3468 static_cast<GtkAttachOptions>(GTK_FILL | GTK_EXPAND), static_cast<GtkAttachOptions>(0), 0, 0);
3470 gtk_widget_show(tabcomp);
3473 /* advanced entry tab */
3474 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer UNUSED(data))
3476 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3478 c_options->file_ops.use_system_trash = FALSE;
3479 c_options->file_ops.no_trash = FALSE;
3483 static void use_system_trash_cb(GtkWidget *widget, gpointer UNUSED(data))
3485 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3487 c_options->file_ops.use_system_trash = TRUE;
3488 c_options->file_ops.no_trash = FALSE;
3492 static void use_no_cache_cb(GtkWidget *widget, gpointer UNUSED(data))
3494 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3496 c_options->file_ops.no_trash = TRUE;
3500 static void config_tab_behavior(GtkWidget *notebook)
3507 GtkWidget *ct_button;
3511 GtkWidget *with_rename;
3512 GtkWidget *collections_on_top;
3513 GtkWidget *hide_window_in_fullscreen;
3514 GtkWidget *checkbox;
3517 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3519 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3521 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3522 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3523 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3524 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3525 pref_checkbox_new_int(group, _("Enable Delete key"),
3526 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3528 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3529 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3531 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3532 pref_checkbox_link_sensitivity(ct_button, hbox);
3534 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3535 pref_label_new(hbox, _("Folder:"));
3537 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3538 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3539 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3540 gtk_widget_show(tabcomp);
3542 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3543 pref_checkbox_link_sensitivity(ct_button, hbox);
3545 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3546 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MiB"),
3547 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3548 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3549 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3550 G_CALLBACK(safe_delete_view_cb), NULL);
3551 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3552 gtk_widget_show(button);
3554 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3555 G_CALLBACK(safe_delete_clear_cb), NULL);
3556 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3558 c_options->file_ops.no_trash = options->file_ops.no_trash;
3559 c_options->file_ops.use_system_trash = options->file_ops.use_system_trash;
3561 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3562 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3564 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3565 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3567 gtk_widget_show(button);
3569 pref_spacer(group, PREF_PAD_GROUP);
3572 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3574 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3575 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3577 pref_checkbox_new_int(group, _("In place renaming"),
3578 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3580 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3581 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3583 tmp = pref_checkbox_new_int(group, _("Circular selection lists"),
3584 options->circular_selection_lists, &c_options->circular_selection_lists);
3585 gtk_widget_set_tooltip_text(tmp, _("Traverse selection lists in a circular manner"));
3587 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3588 options->marks_save, &c_options->marks_save);
3589 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3591 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3592 options->with_rename, &c_options->with_rename);
3593 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3595 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3596 options->collections_on_top, &c_options->collections_on_top);
3597 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3599 hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3600 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3601 gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice");
3603 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3604 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3606 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);
3607 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."));
3609 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3610 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3612 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3613 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3615 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3616 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3618 pref_spacer(group, PREF_PAD_GROUP);
3620 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3622 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3623 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3624 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3625 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3626 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3627 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3628 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3629 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3630 pref_checkbox_new_int(group, _("Open archive by left click on image"),
3631 options->image_l_click_archive, &c_options->image_l_click_archive);
3632 pref_checkbox_new_int(group, _("Play video by left click on image"),
3633 options->image_l_click_video, &c_options->image_l_click_video);
3634 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3635 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3637 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3638 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3639 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3640 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3641 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3643 pref_spacer(group, PREF_PAD_GROUP);
3645 group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3647 checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3648 options->override_disable_gpu, &c_options->override_disable_gpu);
3649 gtk_widget_set_tooltip_text(checkbox, "Contact the developers for usage");
3652 pref_spacer(group, PREF_PAD_GROUP);
3654 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3656 pref_spin_new_int(group, _("Debug level:"), NULL,
3657 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3659 pref_checkbox_new_int(group, _("Timer data"),
3660 options->log_window.timer_data, &c_options->log_window.timer_data);
3662 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3663 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3667 /* accelerators tab */
3668 static void config_tab_accelerators(GtkWidget *notebook)
3674 GtkWidget *scrolled;
3675 GtkWidget *accel_view;
3676 GtkCellRenderer *renderer;
3677 GtkTreeSelection *selection;
3678 GtkTreeViewColumn *column;
3680 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3682 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3684 scrolled = gtk_scrolled_window_new(NULL, NULL);
3685 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3686 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3687 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3688 gtk_widget_show(scrolled);
3690 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3692 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3693 g_object_unref(accel_store);
3694 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3695 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3697 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3699 renderer = gtk_cell_renderer_text_new();
3701 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3706 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3707 gtk_tree_view_column_set_resizable(column, TRUE);
3708 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3711 renderer = gtk_cell_renderer_accel_new();
3712 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3713 G_CALLBACK(accel_store_cleared_cb), accel_store);
3714 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3715 G_CALLBACK(accel_store_edited_cb), accel_store);
3718 g_object_set (renderer,
3720 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3723 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3728 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3729 gtk_tree_view_column_set_resizable(column, TRUE);
3730 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3732 renderer = gtk_cell_renderer_text_new();
3734 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3739 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
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("Accel",
3750 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3751 gtk_tree_view_column_set_resizable(column, TRUE);
3752 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3754 accel_store_populate();
3755 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3756 gtk_widget_show(accel_view);
3758 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3760 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3761 G_CALLBACK(accel_default_cb), accel_view);
3762 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3763 gtk_widget_show(button);
3765 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3766 G_CALLBACK(accel_reset_cb), accel_view);
3767 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3768 gtk_widget_show(button);
3771 /* toolbar main tab */
3772 static void config_tab_toolbar_main(GtkWidget *notebook)
3775 GtkWidget *toolbardata;
3778 lw = static_cast<LayoutWindow *>(layout_window_list->data);
3780 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3782 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3783 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3784 gtk_widget_show(vbox);
3787 /* toolbar status tab */
3788 static void config_tab_toolbar_status(GtkWidget *notebook)
3791 GtkWidget *toolbardata;
3794 lw = static_cast<LayoutWindow *>(layout_window_list->data);
3796 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3798 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3799 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3800 gtk_widget_show(vbox);
3804 static gint extension_sort_cb(gconstpointer a, gconstpointer b)
3806 return g_strcmp0((gchar *)a, (gchar *)b);
3809 static void config_tab_advanced(GtkWidget *notebook)
3813 GSList *formats_list;
3814 GList *extensions_list = NULL;
3817 GdkPixbufFormat *fm;
3819 GString *types_string = g_string_new(NULL);
3820 GtkWidget *types_string_label;
3821 GtkWidget *threads_string_label;
3822 GtkWidget *dupes_threads_spin;
3824 vbox = scrolled_notebook_page(notebook, _("Advanced"));
3825 group = pref_group_new(vbox, FALSE, _("External preview extraction"), GTK_ORIENTATION_VERTICAL);
3827 pref_checkbox_new_int(group, _("Use external preview extraction - Requires restart"), options->external_preview.enable, &c_options->external_preview.enable);
3829 pref_spacer(group, PREF_PAD_GROUP);
3831 formats_list = gdk_pixbuf_get_formats();
3833 while (formats_list)
3835 fm = static_cast<GdkPixbufFormat *>(formats_list->data);
3836 extensions = gdk_pixbuf_format_get_extensions(fm);
3839 while (extensions[i])
3841 extensions_list = g_list_insert_sorted(extensions_list, g_strdup(extensions[i]), extension_sort_cb);
3845 g_strfreev(extensions);
3846 formats_list = formats_list->next;
3849 while (extensions_list)
3851 if (types_string->len == 0)
3853 types_string = g_string_append(types_string, static_cast<const gchar *>(extensions_list->data));
3857 types_string = g_string_append(types_string, ", ");
3858 types_string = g_string_append(types_string, static_cast<const gchar *>(extensions_list->data));
3861 extensions_list = extensions_list->next;
3864 types_string = g_string_prepend(types_string, _("Usable file types:\n"));
3865 types_string_label = pref_label_new(group, types_string->str);
3866 gtk_label_set_line_wrap(GTK_LABEL(types_string_label), TRUE);
3868 pref_spacer(group, PREF_PAD_GROUP);
3870 group = pref_group_new(vbox, FALSE, _("File identification tool"), GTK_ORIENTATION_VERTICAL);
3871 external_preview_select_entry = gtk_entry_new();
3872 tabcomp = tab_completion_new(&external_preview_select_entry, options->external_preview.select, NULL, NULL, NULL, NULL);
3873 tab_completion_add_select_button(external_preview_select_entry, _("Select file identification tool"), FALSE);
3874 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3875 gtk_widget_show(tabcomp);
3877 group = pref_group_new(vbox, FALSE, _("Preview extraction tool"), GTK_ORIENTATION_VERTICAL);
3878 external_preview_extract_entry = gtk_entry_new();
3879 tabcomp = tab_completion_new(&external_preview_extract_entry, options->external_preview.extract, NULL, NULL, NULL, NULL);
3880 tab_completion_add_select_button(external_preview_extract_entry, _("Select preview extraction tool"), FALSE);
3881 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3882 gtk_widget_show(tabcomp);
3884 gtk_widget_show(vbox);
3886 g_slist_free(formats_list);
3887 string_list_free(extensions_list);
3888 g_string_free(types_string, TRUE);
3890 pref_spacer(group, PREF_PAD_GROUP);
3892 pref_line(vbox, PREF_PAD_SPACE);
3893 group = pref_group_new(vbox, FALSE, _("Thread pool limits"), GTK_ORIENTATION_VERTICAL);
3895 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.");
3896 gtk_label_set_line_wrap(GTK_LABEL(threads_string_label), TRUE);
3898 pref_spacer(vbox, PREF_PAD_GROUP);
3900 dupes_threads_spin = pref_spin_new_int(vbox, _("Duplicate check:"), _("max. threads"), 0, get_cpu_cores(), 1, options->threads.duplicates, &c_options->threads.duplicates);
3901 gtk_widget_set_tooltip_markup(dupes_threads_spin, _("Set to 0 for unlimited"));
3905 static void config_tab_stereo(GtkWidget *notebook)
3913 GtkWidget *fs_button;
3914 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3916 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3918 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3919 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3921 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3922 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3923 pref_checkbox_new_int(box, _("Mirror left image"),
3924 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3925 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3926 pref_checkbox_new_int(box, _("Flip left image"),
3927 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3928 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3929 pref_checkbox_new_int(box, _("Mirror right image"),
3930 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3931 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3932 pref_checkbox_new_int(box, _("Flip right image"),
3933 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3934 pref_checkbox_new_int(group, _("Swap left and right images"),
3935 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3936 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3937 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3939 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3940 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3941 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3942 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3943 pref_checkbox_link_sensitivity(fs_button, box2);
3944 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3945 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3946 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3947 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3948 pref_checkbox_new_int(box, _("Mirror left image"),
3949 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3950 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3951 pref_checkbox_new_int(box, _("Flip left image"),
3952 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3953 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3954 pref_checkbox_new_int(box, _("Mirror right image"),
3955 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3956 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3957 pref_checkbox_new_int(box, _("Flip right image"),
3958 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3959 pref_checkbox_new_int(box2, _("Swap left and right images"),
3960 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3961 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3962 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3964 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3965 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3966 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3967 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3968 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
3969 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3970 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
3971 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3972 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
3973 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3974 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
3975 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3976 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
3977 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3981 /* Main preferences window */
3982 static void config_window_create(LayoutWindow *lw)
3984 GtkWidget *win_vbox;
3986 GtkWidget *notebook;
3988 GtkWidget *ct_button;
3990 if (!c_options) c_options = init_options(NULL);
3992 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3993 DEBUG_NAME(configwindow);
3994 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3995 g_signal_connect(G_OBJECT(configwindow), "delete_event",
3996 G_CALLBACK(config_window_delete), NULL);
3997 if (options->save_dialog_window_positions)
3999 gtk_window_resize(GTK_WINDOW(configwindow), lw->options.preferences_window.w, lw->options.preferences_window.h);
4000 gtk_window_move(GTK_WINDOW(configwindow), lw->options.preferences_window.x, lw->options.preferences_window.y);
4004 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
4006 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
4007 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
4009 win_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
4010 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
4011 gtk_widget_show(win_vbox);
4013 notebook = gtk_notebook_new();
4014 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
4015 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
4016 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
4018 config_tab_general(notebook);
4019 config_tab_image(notebook);
4020 config_tab_osd(notebook);
4021 config_tab_windows(notebook);
4022 config_tab_accelerators(notebook);
4023 config_tab_files(notebook);
4024 config_tab_metadata(notebook);
4025 config_tab_keywords(notebook);
4026 config_tab_color(notebook);
4027 config_tab_stereo(notebook);
4028 config_tab_behavior(notebook);
4029 config_tab_toolbar_main(notebook);
4030 config_tab_toolbar_status(notebook);
4031 config_tab_advanced(notebook);
4033 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), lw->options.preferences_window.page_number);
4035 hbox = gtk_hbutton_box_new();
4036 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
4037 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
4038 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
4039 gtk_widget_show(hbox);
4041 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
4042 G_CALLBACK(config_window_help_cb), notebook);
4043 gtk_container_add(GTK_CONTAINER(hbox), button);
4044 gtk_widget_set_can_default(button, TRUE);
4045 gtk_widget_show(button);
4047 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
4048 G_CALLBACK(config_window_ok_cb), notebook);
4049 gtk_container_add(GTK_CONTAINER(hbox), button);
4050 gtk_widget_set_can_default(button, TRUE);
4051 gtk_widget_grab_default(button);
4052 gtk_widget_show(button);
4056 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
4057 G_CALLBACK(config_window_close_cb), NULL);
4058 gtk_container_add(GTK_CONTAINER(hbox), button);
4059 gtk_widget_set_can_default(button, TRUE);
4060 gtk_widget_show(button);
4062 if (!generic_dialog_get_alternative_button_order(configwindow))
4064 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
4067 gtk_widget_show(notebook);
4069 gtk_widget_show(configwindow);
4073 *-----------------------------------------------------------------------------
4074 * config window show (public)
4075 *-----------------------------------------------------------------------------
4078 void show_config_window(LayoutWindow *lw)
4082 gtk_window_present(GTK_WINDOW(configwindow));
4086 config_window_create(lw);
4095 void show_about_window(LayoutWindow *lw)
4097 GDataInputStream *data_stream;
4098 GInputStream *in_stream_authors;
4099 GInputStream *in_stream_translators;
4100 GResource *credits_resource;
4102 GdkPixbuf *pixbuf_icon;
4103 GdkPixbuf *pixbuf_logo;
4106 gchar *authors[1000];
4107 gchar *authors_path;
4109 gchar *timezone_path;
4111 gchar *translators_path;
4119 copyright = g_string_new(NULL);
4120 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");
4122 timezone_path = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
4123 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
4125 cd = ZDOpenDatabase(timezone_path);
4128 copyright = g_string_append(copyright, ZDGetNotice(cd));
4132 log_printf("Error: Init of timezone database %s failed\n", timezone_path);
4134 ZDCloseDatabase(cd);
4136 g_free(timezone_path);
4138 credits_resource = credits_get_resource();
4140 authors_path = g_build_filename(GQ_RESOURCE_PATH_CREDITS, "authors", NULL);
4142 in_stream_authors = g_resource_open_stream(credits_resource, authors_path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
4144 data_stream = g_data_input_stream_new(in_stream_authors);
4147 while ((author_line = g_data_input_stream_read_line(G_DATA_INPUT_STREAM(data_stream), &length, NULL, NULL)))
4149 authors[i_authors] = g_strdup(author_line);
4151 g_free(author_line);
4153 authors[i_authors] = NULL;
4155 g_input_stream_close(in_stream_authors, NULL, NULL);
4157 translators_path = g_build_filename(GQ_RESOURCE_PATH_CREDITS, "translators", NULL);
4159 g_resource_get_info(credits_resource, translators_path, G_RESOURCE_LOOKUP_FLAGS_NONE, &size, &flags, NULL);
4161 in_stream_translators = g_resource_open_stream(credits_resource, translators_path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
4162 translators = static_cast<gchar *>(g_malloc0(size));
4163 g_input_stream_read_all(in_stream_translators, translators, size, &bytes_read, NULL, NULL);
4164 g_input_stream_close(in_stream_translators, NULL, NULL);
4166 comment = g_strconcat("Project created by John Ellis\nGQview 1998\nGeeqie 2007\n\n\nDevelopment and bug reports:\n", GQ_EMAIL_ADDRESS, "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
4168 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
4169 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
4170 gtk_show_about_dialog(GTK_WINDOW(lw->window),
4171 "title", _("About Geeqie"),
4173 "program-name", GQ_APPNAME,
4175 "logo", pixbuf_logo,
4176 "icon", pixbuf_icon,
4177 "website", GQ_WEBSITE,
4178 "website-label", "Website",
4179 "comments", comment,
4181 "translator-credits", translators,
4182 "wrap-license", TRUE,
4183 "license", copyright->str,
4186 g_string_free(copyright, TRUE);
4188 while(n < i_authors)
4194 g_free(authors_path);
4196 g_free(translators);
4197 g_free(translators_path);
4198 g_object_unref(data_stream);
4199 g_object_unref(in_stream_authors);
4200 g_object_unref(in_stream_translators);
4205 static void image_overlay_set_text_colours()
4207 c_options->image_overlay.text_red = options->image_overlay.text_red;
4208 c_options->image_overlay.text_green = options->image_overlay.text_green;
4209 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
4210 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
4211 c_options->image_overlay.background_red = options->image_overlay.background_red;
4212 c_options->image_overlay.background_green = options->image_overlay.background_green;
4213 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
4214 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
4218 *-----------------------------------------------------------------------------
4219 * timezone database routines
4220 *-----------------------------------------------------------------------------
4223 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
4225 GError *error = NULL;
4226 TZData *tz = static_cast<TZData *>(data);
4227 gchar *tmp_filename;
4228 gchar *timezone_bin;
4229 gchar *tmp_dir = NULL;
4232 if (!g_cancellable_is_cancelled(tz->cancellable))
4234 generic_dialog_close(tz->gd);
4238 if (g_file_copy_finish(G_FILE(source_object), res, &error))
4240 tmp_filename = g_file_get_path(tz->tmp_g_file);
4241 fd = file_data_new_simple(tmp_filename);
4242 tmp_dir = open_archive(fd);
4246 timezone_bin = g_build_filename(tmp_dir, TIMEZONE_DATABASE_VERSION, TIMEZONE_DATABASE_FILE, NULL);
4247 if (isfile(timezone_bin))
4249 move_file(timezone_bin, tz->timezone_database_user);
4253 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GTK_STOCK_DIALOG_WARNING, NULL);
4256 g_free(timezone_bin);
4257 g_free(tmp_dir); // The folder in /tmp is deleted in exit_program_final()
4261 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GTK_STOCK_DIALOG_WARNING, NULL);
4263 g_free(tmp_filename);
4264 file_data_unref(fd);
4268 file_util_warning_dialog(_("Error: Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4271 g_file_delete(tz->tmp_g_file, NULL, &error);
4272 g_object_unref(tz->tmp_g_file);
4273 tz->tmp_g_file = NULL;
4274 g_object_unref(tz->cancellable);
4275 g_object_unref(tz->timezone_database_gq);
4278 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
4280 TZData *tz = static_cast<TZData *>(data);
4282 if (!g_cancellable_is_cancelled(tz->cancellable))
4284 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
4288 static void timezone_cancel_button_cb(GenericDialog *UNUSED(gd), gpointer data)
4290 TZData *tz = static_cast<TZData *>(data);
4292 g_cancellable_cancel(tz->cancellable);
4295 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
4297 TZData *tz = static_cast<TZData *>(data);
4298 GError *error = NULL;
4299 GFileIOStream *io_stream;
4306 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
4310 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4311 log_printf("Error: Download timezone database failed:\n%s", error->message);
4312 g_error_free(error);
4313 g_object_unref(tz->tmp_g_file);
4317 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE_WEB);
4319 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
4321 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
4323 tz->progress = gtk_progress_bar_new();
4324 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
4325 gtk_widget_show(tz->progress);
4327 gtk_widget_show(tz->gd->dialog);
4328 tz->cancellable = g_cancellable_new();
4329 g_file_copy_async(tz->timezone_database_gq, tz->tmp_g_file, G_FILE_COPY_OVERWRITE, G_PRIORITY_LOW, tz->cancellable, timezone_progress_cb, tz, timezone_async_ready_cb, tz);
4331 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
4334 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */