2 * Copyright (C) 2006 John Ellis
3 * Copyright (C) 2008 - 2016 The Geeqie Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "preferences.h"
26 #include "bar_keywords.h"
28 #include "cache_maint.h"
33 #include "filefilter.h"
34 #include "fullscreen.h"
36 #include "image-overlay.h"
37 #include "color-man.h"
39 #include "layout_config.h"
40 #include "layout_util.h"
44 #include "pixbuf_util.h"
46 #include "slideshow.h"
50 #include "ui_fileops.h"
52 #include "ui_spinner.h"
53 #include "ui_tabcomp.h"
54 #include "ui_utildlg.h"
56 #include "zonedetect.h"
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_FILTER = 0,
117 FILETYPES_COLUMN_DESCRIPTION,
118 FILETYPES_COLUMN_CLASS,
119 FILETYPES_COLUMN_WRITABLE,
120 FILETYPES_COLUMN_SIDECAR,
121 FILETYPES_COLUMN_COUNT
124 gchar *format_class_list[] = {
135 /* config memory values */
136 static ConfOptions *c_options = NULL;
143 static GtkWidget *configwindow = NULL;
144 static GtkListStore *filter_store = NULL;
145 static GtkTreeStore *accel_store = NULL;
147 static GtkWidget *safe_delete_path_entry;
149 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
150 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
151 static GtkWidget *color_profile_screen_file_entry;
152 static GtkWidget *external_preview_select_entry;
153 static GtkWidget *external_preview_extract_entry;
155 static GtkWidget *sidecar_ext_entry;
156 static GtkWidget *help_search_engine_entry;
159 #define CONFIG_WINDOW_DEF_WIDTH 700
160 #define CONFIG_WINDOW_DEF_HEIGHT 600
163 *-----------------------------------------------------------------------------
164 * option widget callbacks (private)
165 *-----------------------------------------------------------------------------
168 static void zoom_increment_cb(GtkWidget *spin, gpointer data)
170 c_options->image.zoom_increment = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
173 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer data)
175 gint mins_secs_tenths, delay;
177 mins_secs_tenths = c_options->slideshow.delay %
178 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
180 delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
181 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
184 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
185 SLIDESHOW_SUBSECOND_PRECISION;
188 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer data)
190 gint hours, secs_tenths, delay;
192 hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
193 secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
195 delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
196 (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
197 (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
199 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
200 SLIDESHOW_SUBSECOND_PRECISION;
203 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer data)
205 gint hours_mins, delay;
207 hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
209 delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
210 (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
211 (gdouble)(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
213 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
214 SLIDESHOW_SUBSECOND_PRECISION;
218 *-----------------------------------------------------------------------------
219 * sync program to config window routine (private)
220 *-----------------------------------------------------------------------------
223 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
229 buf = gtk_entry_get_text(GTK_ENTRY(entry));
230 if (buf && strlen(buf) > 0)
235 *option = g_strdup(buf);
240 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
242 gchar *accel_path, *accel;
244 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
246 if (accel_path && accel_path[0])
249 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
250 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
260 static void config_window_apply(void)
262 gboolean refresh = FALSE;
267 config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
269 if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
270 if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
271 if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
272 if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
273 if (options->file_sort.natural != c_options->file_sort.natural) refresh = TRUE;
274 if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
275 if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
277 options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
278 options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
279 options->file_ops.confirm_move_to_trash = c_options->file_ops.confirm_move_to_trash;
280 options->file_ops.use_system_trash = c_options->file_ops.use_system_trash;
281 options->file_ops.no_trash = c_options->file_ops.no_trash;
282 options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
283 options->tools_restore_state = c_options->tools_restore_state;
284 options->save_window_positions = c_options->save_window_positions;
285 options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
286 options->save_window_workspace = c_options->save_window_workspace;
287 options->save_dialog_window_positions = c_options->save_dialog_window_positions;
288 options->show_window_ids = c_options->show_window_ids;
289 options->image.scroll_reset_method = c_options->image.scroll_reset_method;
290 options->image.zoom_2pass = c_options->image.zoom_2pass;
291 options->image.fit_window_to_image = c_options->image.fit_window_to_image;
292 options->image.limit_window_size = c_options->image.limit_window_size;
293 options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
294 options->image.max_window_size = c_options->image.max_window_size;
295 options->image.limit_autofit_size = c_options->image.limit_autofit_size;
296 options->image.max_autofit_size = c_options->image.max_autofit_size;
297 options->image.max_enlargement_size = c_options->image.max_enlargement_size;
298 options->image.use_clutter_renderer = c_options->image.use_clutter_renderer;
299 options->image.tile_size = c_options->image.tile_size;
300 options->progressive_key_scrolling = c_options->progressive_key_scrolling;
301 options->keyboard_scroll_step = c_options->keyboard_scroll_step;
303 if (options->thumbnails.max_width != c_options->thumbnails.max_width
304 || options->thumbnails.max_height != c_options->thumbnails.max_height
305 || options->thumbnails.quality != c_options->thumbnails.quality)
307 thumb_format_changed = TRUE;
309 options->thumbnails.max_width = c_options->thumbnails.max_width;
310 options->thumbnails.max_height = c_options->thumbnails.max_height;
311 options->thumbnails.quality = c_options->thumbnails.quality;
313 options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
314 options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
315 options->thumbnails.use_exif = c_options->thumbnails.use_exif;
316 options->thumbnails.use_color_management = c_options->thumbnails.use_color_management;
317 options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
318 options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
319 // options->thumbnails.use_ft_metadata_small = c_options->thumbnails.use_ft_metadata_small;
320 options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
321 options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
322 options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
323 options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
324 options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
325 options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
327 options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
328 options->file_sort.natural = c_options->file_sort.natural;
329 options->file_filter.disable = c_options->file_filter.disable;
331 config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, NULL);
332 sidecar_ext_parse(options->sidecar.ext);
334 options->slideshow.random = c_options->slideshow.random;
335 options->slideshow.repeat = c_options->slideshow.repeat;
336 options->slideshow.delay = c_options->slideshow.delay;
338 options->mousewheel_scrolls = c_options->mousewheel_scrolls;
339 options->image_lm_click_nav = c_options->image_lm_click_nav;
340 options->image_l_click_archive = c_options->image_l_click_archive;
341 options->image_l_click_video = c_options->image_l_click_video;
342 options->image_l_click_video_editor = c_options->image_l_click_video_editor;
344 options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
346 options->image.tile_cache_max = c_options->image.tile_cache_max;
347 options->image.image_cache_max = c_options->image.image_cache_max;
349 options->image.zoom_quality = c_options->image.zoom_quality;
351 options->image.zoom_increment = c_options->image.zoom_increment;
353 options->image.zoom_style = c_options->image.zoom_style;
355 options->image.enable_read_ahead = c_options->image.enable_read_ahead;
358 if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
359 || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
360 || !gdk_color_equal(&options->image.border_color, &c_options->image.border_color))
362 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
363 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
364 options->image.border_color = c_options->image.border_color;
365 layout_colors_update();
366 view_window_colors_update();
369 options->image.alpha_color_1 = c_options->image.alpha_color_1;
370 options->image.alpha_color_2 = c_options->image.alpha_color_2;
372 options->fullscreen.screen = c_options->fullscreen.screen;
373 options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
374 options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
375 options->fullscreen.above = c_options->fullscreen.above;
376 if (c_options->image_overlay.template_string)
377 set_image_overlay_template_string(&options->image_overlay.template_string,
378 c_options->image_overlay.template_string);
379 if (c_options->image_overlay.font)
380 set_image_overlay_font_string(&options->image_overlay.font,
381 c_options->image_overlay.font);
382 options->image_overlay.text_red = c_options->image_overlay.text_red;
383 options->image_overlay.text_green = c_options->image_overlay.text_green;
384 options->image_overlay.text_blue = c_options->image_overlay.text_blue;
385 options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
386 options->image_overlay.background_red = c_options->image_overlay.background_red;
387 options->image_overlay.background_green = c_options->image_overlay.background_green;
388 options->image_overlay.background_blue = c_options->image_overlay.background_blue;
389 options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
390 options->update_on_time_change = c_options->update_on_time_change;
392 options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
393 options->rot_invariant_sim = c_options->rot_invariant_sim;
395 options->tree_descend_subdirs = c_options->tree_descend_subdirs;
397 options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
398 options->circular_selection_lists = c_options->circular_selection_lists;
400 options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
401 options->dnd_icon_size = c_options->dnd_icon_size;
402 options->clipboard_selection = c_options->clipboard_selection;
403 options->dnd_default_action = c_options->dnd_default_action;
405 options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
406 options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
407 options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
408 options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
409 options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
410 options->metadata.confirm_write = c_options->metadata.confirm_write;
411 options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
412 options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
413 options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
414 options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
415 options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
416 options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
417 options->metadata.write_orientation = c_options->metadata.write_orientation;
418 options->metadata.check_spelling = c_options->metadata.check_spelling;
419 options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
420 (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
421 (c_options->stereo.tmp.flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
422 (c_options->stereo.tmp.mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
423 (c_options->stereo.tmp.flip_left ? PR_STEREO_FLIP_LEFT : 0) |
424 (c_options->stereo.tmp.swap ? PR_STEREO_SWAP : 0) |
425 (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
426 options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
427 (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
428 (c_options->stereo.tmp.fs_flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
429 (c_options->stereo.tmp.fs_mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
430 (c_options->stereo.tmp.fs_flip_left ? PR_STEREO_FLIP_LEFT : 0) |
431 (c_options->stereo.tmp.fs_swap ? PR_STEREO_SWAP : 0) |
432 (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
433 options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
434 options->stereo.fixed_w = c_options->stereo.fixed_w;
435 options->stereo.fixed_h = c_options->stereo.fixed_h;
436 options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
437 options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
438 options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
439 options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
441 options->info_keywords.height = c_options->info_keywords.height;
442 options->info_title.height = c_options->info_title.height;
443 options->info_comment.height = c_options->info_comment.height;
444 options->info_rating.height = c_options->info_rating.height;
446 options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
447 options->expand_menu_toolbar = c_options->expand_menu_toolbar;
449 options->marks_save = c_options->marks_save;
450 options->with_rename = c_options->with_rename;
451 options->collections_on_top = c_options->collections_on_top;
452 options->hide_window_in_fullscreen = c_options->hide_window_in_fullscreen;
453 config_entry_to_option(help_search_engine_entry, &options->help_search_engine, NULL);
455 options->external_preview.enable = c_options->external_preview.enable;
456 config_entry_to_option(external_preview_select_entry, &options->external_preview.select, NULL);
457 config_entry_to_option(external_preview_extract_entry, &options->external_preview.extract, NULL);
459 options->read_metadata_in_idle = c_options->read_metadata_in_idle;
461 options->star_rating.star = c_options->star_rating.star;
462 options->star_rating.rejected = c_options->star_rating.rejected;
464 options->threads.duplicates = c_options->threads.duplicates > 0 ? c_options->threads.duplicates : -1;
467 set_debug_level(debug_c);
471 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
473 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
474 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
476 config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
477 options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
478 if (options->color_profile.render_intent != c_options->color_profile.render_intent)
480 options->color_profile.render_intent = c_options->color_profile.render_intent;
485 options->mouse_button_8 = c_options->mouse_button_8;
486 options->mouse_button_9 = c_options->mouse_button_9;
488 options->override_disable_gpu = c_options->override_disable_gpu;
490 config_tab_keywords_save();
492 image_options_sync();
497 layout_refresh(NULL);
500 if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, NULL);
502 toolbar_apply(TOOLBAR_MAIN);
503 toolbar_apply(TOOLBAR_STATUS);
507 *-----------------------------------------------------------------------------
508 * config window main button callbacks (private)
509 *-----------------------------------------------------------------------------
512 static void config_window_close_cb(GtkWidget *widget, gpointer data)
514 gtk_widget_destroy(configwindow);
519 static void config_window_help_cb(GtkWidget *widget, gpointer data)
521 GtkWidget *notebook = data;
524 static gchar *html_section[] =
526 "GuideOptionsGeneral.html",
527 "GuideOptionsImage.html",
528 "GuideOptionsOSD.html",
529 "GuideOptionsWindow.html",
530 "GuideOptionsKeyboard.html",
531 "GuideOptionsFiltering.html",
532 "GuideOptionsMetadata.html",
533 "GuideOptionsKeywords.html",
534 "GuideOptionsColor.html",
535 "GuideOptionsStereo.html",
536 "GuideOptionsBehavior.html",
537 "GuideOptionsToolbar.html",
538 "GuideOptionsToolbar.html",
539 "GuideOptionsAdvanced.html"
542 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
543 help_window_show(html_section[i]);
546 static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpointer data)
548 config_window_close_cb(NULL, NULL);
552 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
555 GtkNotebook *notebook = data;
563 lw = layout_window_list->data;
565 window = gtk_widget_get_window(widget);
566 gdk_window_get_root_origin(window, &x, &y);
567 w = gdk_window_get_width(window);
568 h = gdk_window_get_height(window);
569 page_number = gtk_notebook_get_current_page(notebook);
571 lw->options.preferences_window.x = x;
572 lw->options.preferences_window.y = y;
573 lw->options.preferences_window.w = w;
574 lw->options.preferences_window.h = h;
575 lw->options.preferences_window.page_number = page_number;
577 config_window_apply();
578 layout_util_sync(lw);
579 save_options(options);
580 config_window_close_cb(NULL, NULL);
584 *-----------------------------------------------------------------------------
585 * config window setup (private)
586 *-----------------------------------------------------------------------------
589 static void quality_menu_cb(GtkWidget *combo, gpointer data)
593 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
597 *option = GDK_INTERP_NEAREST;
600 *option = GDK_INTERP_TILES;
603 *option = GDK_INTERP_BILINEAR;
608 static void dnd_default_action_selection_menu_cb(GtkWidget *combo, gpointer data)
612 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
616 *option = DND_ACTION_ASK;
619 *option = DND_ACTION_COPY;
622 *option = DND_ACTION_MOVE;
626 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
630 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
633 *option = CLIPBOARD_PRIMARY;
636 *option = CLIPBOARD_CLIPBOARD;
639 *option = CLIPBOARD_BOTH;
642 *option = CLIPBOARD_BOTH;
646 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
647 guint option, guint *option_c)
654 pref_table_label(table, column, row, text, 0.0);
656 combo = gtk_combo_box_text_new();
658 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
659 if (option == GDK_INTERP_NEAREST) current = 0;
660 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
661 if (option == GDK_INTERP_TILES) current = 1;
662 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear (best, but slowest)"));
663 if (option == GDK_INTERP_BILINEAR) current = 2;
665 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
667 g_signal_connect(G_OBJECT(combo), "changed",
668 G_CALLBACK(quality_menu_cb), option_c);
670 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
671 gtk_widget_show(combo);
674 static void add_dnd_default_action_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, DnDAction option, DnDAction *option_c)
681 pref_table_label(table, column, row, text, 0.0);
683 combo = gtk_combo_box_text_new();
685 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Ask"));
686 if (option == DND_ACTION_ASK) current = 0;
687 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Copy"));
688 if (option == DND_ACTION_COPY) current = 1;
689 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Move"));
690 if (option == DND_ACTION_MOVE) current = 2;
692 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
694 g_signal_connect(G_OBJECT(combo), "changed",
695 G_CALLBACK(dnd_default_action_selection_menu_cb), option_c);
697 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
698 gtk_widget_show(combo);
701 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
702 gint option, gint *option_c)
709 pref_table_label(table, column, row, text, 0.0);
711 combo = gtk_combo_box_text_new();
713 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Primary"));
714 if (option == CLIPBOARD_PRIMARY) current = 0;
715 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Clipboard"));
716 if (option == CLIPBOARD_CLIPBOARD) current = 1;
717 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Both"));
718 if (option == CLIPBOARD_BOTH) current = 2;
720 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
722 g_signal_connect(G_OBJECT(combo), "changed",
723 G_CALLBACK(clipboard_selection_menu_cb), option_c);
725 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
726 gtk_widget_show(combo);
729 static void zoom_style_selection_menu_cb(GtkWidget *combo, gpointer data)
733 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
736 *option = ZOOM_GEOMETRIC;
739 *option = ZOOM_ARITHMETIC;
742 *option = ZOOM_GEOMETRIC;
746 static void add_zoom_style_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, ZoomStyle option, ZoomStyle *option_c)
753 pref_table_label(table, column, row, text, 0.0);
755 combo = gtk_combo_box_text_new();
757 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Geometric"));
758 if (option == ZOOM_GEOMETRIC) current = 0;
759 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Arithmetic"));
760 if (option == ZOOM_ARITHMETIC) current = 1;
762 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
764 g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(zoom_style_selection_menu_cb), option_c);
766 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
767 gtk_widget_show(combo);
770 typedef struct _UseableMouseItems UseableMouseItems;
771 struct _UseableMouseItems
773 gchar *name; /* GtkActionEntry terminology */
778 static const UseableMouseItems useable_mouse_items[] = {
780 {"FirstImage", N_("First Image"), GTK_STOCK_GOTO_TOP},
781 {"PrevImage", N_("Previous Image"), GTK_STOCK_GO_UP},
782 {"NextImage", N_("Next Image"), GTK_STOCK_GO_DOWN},
783 {"LastImage", N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
784 {"Back", N_("Back"), GTK_STOCK_GO_BACK},
785 {"Forward", N_("Forward"), GTK_STOCK_GO_FORWARD},
786 {"Home", N_("Home"), GTK_STOCK_HOME},
787 {"Up", N_("Up"), GTK_STOCK_GO_UP},
788 {"FirstPage", N_("First page"), GTK_STOCK_MEDIA_PREVIOUS},
789 {"LastPage", N_("Last Page"), GTK_STOCK_MEDIA_NEXT},
790 {"NextPage", N_("Next page"), GTK_STOCK_MEDIA_FORWARD},
791 {"PrevPage", N_("Previous Page"), GTK_STOCK_MEDIA_REWIND},
792 {"NewWindow", N_("New _window"), GTK_STOCK_NEW},
793 {"NewCollection", N_("New collection"), GTK_STOCK_INDEX},
794 {"OpenCollection", N_("Open collection"), GTK_STOCK_OPEN},
795 {"Search", N_("Search"), GTK_STOCK_FIND},
796 {"FindDupes", N_("Find duplicates"), GTK_STOCK_FIND},
797 {"NewFolder", N_("New folder"),GTK_STOCK_DIRECTORY},
798 {"Copy", N_("Copy"), GTK_STOCK_COPY},
799 {"Move", N_("Move"), PIXBUF_INLINE_ICON_MOVE},
800 {"Rename", N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
801 {"Delete", N_("Delete"), GTK_STOCK_DELETE},
802 {"CloseWindow", N_("Close Window"), GTK_STOCK_CLOSE},
803 {"PanView", N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
804 {"SelectAll", N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
805 {"SelectNone", N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
806 {"SelectInvert", N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
807 {"ShowFileFilter", N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
808 {"RectangularSelection", N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
809 {"Print", N_("Print"), GTK_STOCK_PRINT},
810 {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
811 {"LayoutConfig", N_("Configure this window"), GTK_STOCK_PREFERENCES},
812 {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
813 {"RotateCW", N_("Rotate clockwise 90°"), PIXBUF_INLINE_ICON_CW},
814 {"RotateCCW", N_("Rotate counterclockwise 90°"), PIXBUF_INLINE_ICON_CCW},
815 {"Rotate180", N_("Rotate 180°"), PIXBUF_INLINE_ICON_180},
816 {"Mirror", N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
817 {"Flip", N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
818 {"AlterNone", N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
819 {"ZoomIn", N_("Zoom in"), GTK_STOCK_ZOOM_IN},
820 {"ZoomOut", N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
821 {"Zoom100", N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
822 {"ZoomFit", N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
823 {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
824 {"ZoomFillVert", N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
825 {"Zoom200", N_("Zoom 2:1"), GTK_STOCK_FILE},
826 {"Zoom300", N_("Zoom 3:1"), GTK_STOCK_FILE},
827 {"Zoom400", N_("Zoom 4:1"), GTK_STOCK_FILE},
828 {"Zoom50", N_("Zoom 1:2"), GTK_STOCK_FILE},
829 {"Zoom33", N_("Zoom1:3"), GTK_STOCK_FILE},
830 {"Zoom25", N_("Zoom 1:4"), GTK_STOCK_FILE},
831 {"ConnectZoomIn", N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
832 {"SplitPaneSync", N_("Split Pane Sync"), PIXBUF_INLINE_SPLIT_PANE_SYNC},
833 {"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
834 {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
835 {"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
836 {"SlideShowPause", N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
837 {"SlideShowFaster", N_("Slideshow Faster"), GTK_STOCK_FILE},
838 {"SlideShowSlower", N_("Slideshow Slower"), GTK_STOCK_FILE},
839 {"Refresh", N_("Refresh"), GTK_STOCK_REFRESH},
840 {"HelpContents", N_("Help"), GTK_STOCK_HELP},
841 {"ExifWin", N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
842 {"Thumbnails", N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
843 {"ShowMarks", N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
844 {"DrawRectangle", N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
845 {"FloatTools", N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
846 {"SBar", N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
847 {"SBarSort", N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
848 {"Quit", N_("Quit"), GTK_STOCK_QUIT},
852 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
854 gchar **option = data;
857 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
859 const UseableMouseItems *list = useable_mouse_items;
863 if (g_strcmp0(list->label, label) == 0)
871 *option = g_strdup(list->name);
875 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
876 gchar *option, gchar **option_c)
884 pref_table_label(table, column, row, text, 0.0);
886 combo = gtk_combo_box_text_new();
888 const UseableMouseItems *list = useable_mouse_items;
892 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
893 if (g_strcmp0(list->name, option) == 0)
901 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
903 g_signal_connect(G_OBJECT(combo), "changed",
904 G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
906 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
907 gtk_widget_show(combo);
910 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
914 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
917 if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
919 c_options->thumbnails.max_width = thumb_size_list[n].w;
920 c_options->thumbnails.max_height = thumb_size_list[n].h;
924 c_options->thumbnails.max_width = options->thumbnails.max_width;
925 c_options->thumbnails.max_height = options->thumbnails.max_height;
929 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
935 c_options->thumbnails.max_width = options->thumbnails.max_width;
936 c_options->thumbnails.max_height = options->thumbnails.max_height;
938 pref_table_label(table, column, row, text, 0.0);
940 combo = gtk_combo_box_text_new();
943 for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
948 w = thumb_size_list[i].w;
949 h = thumb_size_list[i].h;
951 buf = g_strdup_printf("%d x %d", w, h);
952 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
955 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
962 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
963 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
969 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
970 g_signal_connect(G_OBJECT(combo), "changed",
971 G_CALLBACK(thumb_size_menu_cb), NULL);
973 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
974 gtk_widget_show(combo);
977 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
981 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
985 *option = PR_STEREO_NONE;
988 *option = PR_STEREO_ANAGLYPH_RC;
991 *option = PR_STEREO_ANAGLYPH_GM;
994 *option = PR_STEREO_ANAGLYPH_YB;
997 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
1000 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
1003 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
1006 *option = PR_STEREO_ANAGLYPH_DB_RC;
1009 *option = PR_STEREO_ANAGLYPH_DB_GM;
1012 *option = PR_STEREO_ANAGLYPH_DB_YB;
1015 *option = PR_STEREO_HORIZ;
1018 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
1021 *option = PR_STEREO_VERT;
1024 *option = PR_STEREO_VERT | PR_STEREO_HALF;
1027 *option = PR_STEREO_FIXED;
1032 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1033 gint option, gint *option_c, gboolean add_fixed)
1040 pref_table_label(table, column, row, text, 0.0);
1042 combo = gtk_combo_box_text_new();
1044 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
1046 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
1047 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
1048 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
1049 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
1050 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
1051 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
1052 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
1053 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
1054 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
1055 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
1056 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
1057 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
1058 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
1059 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
1060 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
1061 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
1062 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
1063 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
1065 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
1066 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
1067 if (option & PR_STEREO_HORIZ)
1070 if (option & PR_STEREO_HALF) current = 11;
1073 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
1074 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
1075 if (option & PR_STEREO_VERT)
1078 if (option & PR_STEREO_HALF) current = 13;
1083 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
1084 if (option & PR_STEREO_FIXED) current = 14;
1087 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1089 g_signal_connect(G_OBJECT(combo), "changed",
1090 G_CALLBACK(stereo_mode_menu_cb), option_c);
1092 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1093 gtk_widget_show(combo);
1096 static void video_menu_cb(GtkWidget *combo, gpointer data)
1098 gchar **option = data;
1100 EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
1104 static void video_menu_populate(gpointer data, gpointer user_data)
1106 GtkWidget *combo = user_data;
1107 EditorDescription *ed = data;
1109 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1112 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1113 gchar *option, gchar **option_c)
1117 /* use lists since they are sorted */
1118 GList *eds = editor_list_get();
1122 pref_table_label(table, column, row, text, 0.0);
1124 combo = gtk_combo_box_text_new();
1125 g_list_foreach(eds,video_menu_populate,(gpointer)combo);
1126 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1128 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1130 g_signal_connect(G_OBJECT(combo), "changed",
1131 G_CALLBACK(video_menu_cb), option_c);
1133 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1134 gtk_widget_show(combo);
1137 static void filter_store_populate(void)
1141 if (!filter_store) return;
1143 gtk_list_store_clear(filter_store);
1145 work = filter_get_list();
1154 gtk_list_store_append(filter_store, &iter);
1155 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1159 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1160 gchar *new_text, gpointer data)
1162 GtkWidget *model = data;
1163 FilterEntry *fe = data;
1167 if (!new_text || strlen(new_text) < 1) return;
1169 tpath = gtk_tree_path_new_from_string(path_str);
1170 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1171 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1173 g_free(fe->extensions);
1174 fe->extensions = g_strdup(new_text);
1176 gtk_tree_path_free(tpath);
1180 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1181 gchar *new_text, gpointer data)
1183 GtkWidget *model = data;
1184 FilterEntry *fe = data;
1189 if (!new_text || !new_text[0]) return;
1191 tpath = gtk_tree_path_new_from_string(path_str);
1192 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1193 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1195 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1197 if (strcmp(new_text, _(format_class_list[i])) == 0)
1204 gtk_tree_path_free(tpath);
1208 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1209 gchar *new_text, gpointer data)
1211 GtkWidget *model = data;
1216 if (!new_text || !new_text[0]) return;
1218 tpath = gtk_tree_path_new_from_string(path_str);
1219 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1220 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1222 g_free(fe->description);
1223 fe->description = g_strdup(new_text);
1225 gtk_tree_path_free(tpath);
1228 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
1229 gchar *path_str, gpointer data)
1231 GtkWidget *model = data;
1236 tpath = gtk_tree_path_new_from_string(path_str);
1237 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1238 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1240 fe->enabled = !fe->enabled;
1242 gtk_tree_path_free(tpath);
1246 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
1247 gchar *path_str, gpointer data)
1249 GtkWidget *model = data;
1254 tpath = gtk_tree_path_new_from_string(path_str);
1255 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1256 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1258 fe->writable = !fe->writable;
1259 if (fe->writable) fe->allow_sidecar = FALSE;
1261 gtk_tree_path_free(tpath);
1265 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
1266 gchar *path_str, gpointer data)
1268 GtkWidget *model = data;
1273 tpath = gtk_tree_path_new_from_string(path_str);
1274 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1275 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1277 fe->allow_sidecar = !fe->allow_sidecar;
1278 if (fe->allow_sidecar) fe->writable = FALSE;
1280 gtk_tree_path_free(tpath);
1284 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1285 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1289 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1291 switch (GPOINTER_TO_INT(data))
1294 g_object_set(GTK_CELL_RENDERER(cell),
1295 "active", fe->enabled, NULL);
1298 g_object_set(GTK_CELL_RENDERER(cell),
1299 "text", fe->extensions, NULL);
1301 case FE_DESCRIPTION:
1302 g_object_set(GTK_CELL_RENDERER(cell),
1303 "text", fe->description, NULL);
1306 g_object_set(GTK_CELL_RENDERER(cell),
1307 "text", _(format_class_list[fe->file_class]), NULL);
1310 g_object_set(GTK_CELL_RENDERER(cell),
1311 "active", fe->writable, NULL);
1313 case FE_ALLOW_SIDECAR:
1314 g_object_set(GTK_CELL_RENDERER(cell),
1315 "active", fe->allow_sidecar, NULL);
1320 static gboolean filter_add_scroll(gpointer data)
1324 GtkCellRenderer *cell;
1325 GtkTreeViewColumn *column;
1328 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1329 path = gtk_tree_path_new_from_indices(rows-1, -1);
1331 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1333 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1334 cell = g_list_last(list_cells)->data;
1336 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1337 path, column, FALSE, 0.0, 0.0 );
1338 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1339 path, column, cell, TRUE);
1341 gtk_tree_path_free(path);
1342 g_list_free(list_cells);
1347 static void filter_add_cb(GtkWidget *widget, gpointer data)
1349 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1350 filter_store_populate();
1352 g_idle_add((GSourceFunc)filter_add_scroll, data);
1355 static void filter_remove_cb(GtkWidget *widget, gpointer data)
1357 GtkWidget *filter_view = data;
1358 GtkTreeSelection *selection;
1362 if (!filter_store) return;
1363 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1364 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1365 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1368 filter_remove_entry(fe);
1370 filter_store_populate();
1373 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1377 GtkTreeViewColumn *column;
1379 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1380 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1381 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1383 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1387 gtk_tree_path_free(path);
1392 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
1395 filter_add_defaults();
1397 filter_store_populate();
1399 g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1402 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1404 /* no op, only so cancel button appears */
1407 static void filter_default_cb(GtkWidget *widget, gpointer data)
1411 gd = generic_dialog_new(_("Reset filters"),
1412 "reset_filter", widget, TRUE,
1413 dummy_cancel_cb, data);
1414 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1415 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1416 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1417 gtk_widget_show(gd->dialog);
1420 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1422 GtkWidget *frame = data;
1424 gtk_widget_set_sensitive(frame,
1425 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1428 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
1430 layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1433 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
1435 file_util_trash_clear();
1438 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
1442 gd = generic_dialog_new(_("Clear trash"),
1443 "clear_trash", widget, TRUE,
1444 dummy_cancel_cb, NULL);
1445 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1446 _("This will remove the trash contents."), FALSE);
1447 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1448 entry = gtk_entry_new();
1449 gtk_widget_set_can_focus(entry, FALSE);
1450 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1451 if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1452 gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1453 gtk_widget_show(entry);
1454 gtk_widget_show(gd->dialog);
1457 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
1459 GtkWidget *pTextView;
1460 GtkTextBuffer *pTextBuffer;
1464 pTextView = GTK_WIDGET(data);
1466 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1467 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1468 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1470 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1471 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1474 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
1476 GtkTextView *text_view = data;
1477 GtkTextBuffer *buffer;
1479 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1480 if (!configwindow) return;
1482 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1483 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1486 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1490 gd = generic_dialog_new(_("Reset image overlay template string"),
1491 "reset_image_overlay_template_string", widget, TRUE,
1492 dummy_cancel_cb, data);
1493 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1494 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1495 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1496 gtk_widget_show(gd->dialog);
1499 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
1501 help_window_show("GuideOptionsOSD.html");
1504 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer data)
1506 #if GTK_CHECK_VERSION(3,4,0)
1509 PangoFontDescription *font_desc;
1511 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1512 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1514 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1516 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1517 font = pango_font_description_to_string(font_desc);
1518 g_free(c_options->image_overlay.font);
1519 c_options->image_overlay.font = g_strdup(font);
1523 gtk_widget_destroy(dialog);
1527 font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
1528 c_options->image_overlay.font = g_strdup(font);
1532 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer data)
1535 #if GTK_CHECK_VERSION(3,4,0)
1538 dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1539 colour.red = options->image_overlay.text_red;
1540 colour.green = options->image_overlay.text_green;
1541 colour.blue = options->image_overlay.text_blue;
1542 colour.alpha = options->image_overlay.text_alpha;
1543 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1544 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1546 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1548 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1549 c_options->image_overlay.text_red = colour.red*255;
1550 c_options->image_overlay.text_green = colour.green*255;
1551 c_options->image_overlay.text_blue = colour.blue*255;
1552 c_options->image_overlay.text_alpha = colour.alpha*255;
1554 gtk_widget_destroy(dialog);
1557 GtkColorSelection *colorsel;
1559 dialog = gtk_color_selection_dialog_new("Image Overlay Text Colour");
1560 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1561 colour.red = options->image_overlay.text_red*257;
1562 colour.green = options->image_overlay.text_green*257;
1563 colour.blue = options->image_overlay.text_blue*257;
1564 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1565 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1566 gtk_color_selection_set_current_color(colorsel, &colour);
1567 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.text_alpha*257);
1569 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1571 gtk_color_selection_get_current_color(colorsel, &colour);
1572 c_options->image_overlay.text_red = colour.red/257;
1573 c_options->image_overlay.text_green = colour.green/257;
1574 c_options->image_overlay.text_blue = colour.blue/257;
1575 c_options->image_overlay.text_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1577 gtk_widget_destroy (dialog);
1582 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer data)
1585 #if GTK_CHECK_VERSION(3,4,0)
1588 dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1589 colour.red = options->image_overlay.background_red;
1590 colour.green = options->image_overlay.background_green;
1591 colour.blue = options->image_overlay.background_blue;
1592 colour.alpha = options->image_overlay.background_alpha;
1593 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1594 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1596 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1598 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1599 c_options->image_overlay.background_red = colour.red*255;
1600 c_options->image_overlay.background_green = colour.green*255;
1601 c_options->image_overlay.background_blue = colour.blue*255;
1602 c_options->image_overlay.background_alpha = colour.alpha*255;
1604 gtk_widget_destroy(dialog);
1607 GtkColorSelection *colorsel;
1609 dialog = gtk_color_selection_dialog_new("Image Overlay Background Colour");
1610 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1611 colour.red = options->image_overlay.background_red*257;
1612 colour.green = options->image_overlay.background_green*257;
1613 colour.blue = options->image_overlay.background_blue*257;
1614 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1615 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1616 gtk_color_selection_set_current_color(colorsel, &colour);
1617 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.background_alpha*257);
1619 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1621 gtk_color_selection_get_current_color(colorsel, &colour);
1622 c_options->image_overlay.background_red = colour.red/257;
1623 c_options->image_overlay.background_green = colour.green/257;
1624 c_options->image_overlay.background_blue = colour.blue/257;
1625 c_options->image_overlay.background_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1627 gtk_widget_destroy(dialog);
1631 static void accel_store_populate(void)
1634 GList *groups, *actions;
1636 const gchar *accel_path;
1640 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1642 gtk_tree_store_clear(accel_store);
1643 lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
1645 g_assert(lw && lw->ui_manager);
1646 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1649 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1652 action = GTK_ACTION(actions->data);
1653 accel_path = gtk_action_get_accel_path(action);
1654 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1656 gchar *label, *label2, *tooltip, *accel;
1657 g_object_get(action,
1658 "tooltip", &tooltip,
1662 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1668 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1672 gtk_tree_store_append(accel_store, &iter, NULL);
1673 gtk_tree_store_set(accel_store, &iter,
1676 AE_TOOLTIP, tooltip ? tooltip : "",
1677 AE_ACCEL, accel_path,
1685 actions = actions->next;
1688 groups = groups->next;
1692 static void accel_store_cleared_cb(GtkCellRendererAccel *accel, gchar *path_string, gpointer user_data)
1697 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1699 gchar *accel1 = data;
1704 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1706 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1707 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1709 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1711 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1712 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1721 static void accel_store_edited_cb(GtkCellRendererAccel *accel, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode, gpointer user_data)
1723 GtkTreeModel *model = (GtkTreeModel *)accel_store;
1727 GtkAccelKey old_key, key;
1728 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1730 gtk_tree_model_get_iter(model, &iter, path);
1731 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1733 /* test if the accelerator can be stored without conflicts*/
1734 gtk_accel_map_lookup_entry(accel_path, &old_key);
1736 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1737 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1738 gtk_accel_map_lookup_entry(accel_path, &key);
1740 /* restore the original for now, the key will be really changed when the changes are confirmed */
1741 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1743 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1744 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1746 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1747 gtk_tree_path_free(path);
1751 static gboolean accel_default_scroll(GtkTreeView *data)
1755 GtkTreeViewColumn *column;
1757 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1758 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1759 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1761 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1765 gtk_tree_path_free(path);
1770 static void accel_default_cb(GtkWidget *widget, gpointer data)
1772 accel_store_populate();
1774 g_idle_add((GSourceFunc)accel_default_scroll, data);
1777 void accel_remove_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1779 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1782 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1785 gchar *accel_path, *accel;
1787 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1788 gtk_accel_map_lookup_entry(accel_path, &key);
1789 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1791 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1793 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1798 static void accel_reset_cb(GtkWidget *widget, gpointer data)
1800 GtkTreeSelection *selection;
1802 if (!accel_store) return;
1803 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1804 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1809 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1813 GtkWidget *scrolled;
1814 GtkWidget *viewport;
1816 scrolled = gtk_scrolled_window_new(NULL, NULL);
1817 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1818 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1819 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1820 label = gtk_label_new(title);
1821 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1822 gtk_widget_show(scrolled);
1824 viewport = gtk_viewport_new(NULL, NULL);
1825 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1826 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1827 gtk_widget_show(viewport);
1829 vbox = gtk_vbox_new(FALSE, 0);
1830 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1831 gtk_widget_show(vbox);
1836 static void cache_standard_cb(GtkWidget *widget, gpointer data)
1838 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1840 c_options->thumbnails.spec_standard =TRUE;
1841 c_options->thumbnails.cache_into_dirs = FALSE;
1845 static void cache_geeqie_cb(GtkWidget *widget, gpointer data)
1847 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1849 c_options->thumbnails.spec_standard =FALSE;
1850 c_options->thumbnails.cache_into_dirs = FALSE;
1854 static void cache_local_cb(GtkWidget *widget, gpointer data)
1856 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1858 c_options->thumbnails.cache_into_dirs = TRUE;
1859 c_options->thumbnails.spec_standard =FALSE;
1863 static void help_search_engine_entry_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1864 GdkEvent *event, gpointer userdata)
1866 if (pos == GTK_ENTRY_ICON_PRIMARY)
1868 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1872 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1876 static void star_rating_star_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1877 GdkEvent *event, gpointer userdata)
1879 gchar *rating_symbol;
1881 if (pos == GTK_ENTRY_ICON_PRIMARY)
1883 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1884 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1885 g_free(rating_symbol);
1889 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1890 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1891 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1895 static void star_rating_rejected_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1896 GdkEvent *event, gpointer userdata)
1898 gchar *rating_symbol;
1900 if (pos == GTK_ENTRY_ICON_PRIMARY)
1902 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1903 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1904 g_free(rating_symbol);
1908 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1909 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1910 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1914 static guint star_rating_symbol_test(GtkWidget *widget, gpointer data)
1916 GtkContainer *hbox = data;
1917 GString *str = g_string_new(NULL);
1918 GtkEntry *hex_code_entry;
1919 gchar *hex_code_full;
1922 guint64 hex_value = 0;
1924 list = gtk_container_get_children(hbox);
1926 hex_code_entry = g_list_nth_data(list, 2);
1927 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1929 hex_code = g_strsplit(hex_code_full, "+", 2);
1930 if (hex_code[0] && hex_code[1])
1932 hex_value = strtoull(hex_code[1], NULL, 16);
1934 if (!hex_value || hex_value > 0x10FFFF)
1936 hex_value = 0x003F; // Unicode 'Question Mark'
1938 str = g_string_append_unichar(str, (gunichar)hex_value);
1939 gtk_label_set_text(g_list_nth_data(list, 1), str->str);
1941 g_strfreev(hex_code);
1942 g_string_free(str, TRUE);
1943 g_free(hex_code_full);
1948 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1950 guint64 star_symbol;
1952 star_symbol = star_rating_symbol_test(widget, data);
1953 c_options->star_rating.star = star_symbol;
1956 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1958 guint64 rejected_symbol;
1960 rejected_symbol = star_rating_symbol_test(widget, data);
1961 c_options->star_rating.rejected = rejected_symbol;
1964 /* general options tab */
1965 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1966 typedef struct _TZData TZData;
1970 GCancellable *cancellable;
1972 GtkWidget *progress;
1974 GFile *timezone_database_gq;
1975 gchar *timezone_database_user;
1978 static void config_tab_general(GtkWidget *notebook)
1983 GtkWidget *group_frame;
1984 GtkWidget *subgroup;
1986 GtkWidget *ct_button;
1989 gint hours, minutes, remainder;
1991 GtkWidget *star_rating_entry;
1993 gchar *rating_symbol;
1996 gchar *download_locn;
1997 GNetworkMonitor *net_mon;
1998 GSocketConnectable *tz_org;
1999 gboolean internet_available = FALSE;
2002 vbox = scrolled_notebook_page(notebook, _("General"));
2004 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
2006 table = pref_table_new(group, 2, 2, FALSE, FALSE);
2007 add_thumb_size_menu(table, 0, 0, _("Size:"));
2008 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
2010 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2011 pref_label_new(hbox, _("Custom size: "));
2012 pref_spin_new_int(hbox, _("Width:"), NULL, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
2013 pref_spin_new_int(hbox, _("Height:"), NULL, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
2015 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
2016 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
2018 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2019 pref_checkbox_link_sensitivity(ct_button, subgroup);
2021 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
2022 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
2023 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
2024 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2025 button = pref_radiobutton_new(group_frame, NULL, get_thumbnails_cache_dir(),
2026 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2027 G_CALLBACK(cache_geeqie_cb), NULL);
2029 group_frame = pref_frame_new(subgroup, TRUE,
2030 _("Store thumbnails local to image folder (non-standard)"),
2031 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2032 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
2033 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
2034 G_CALLBACK(cache_local_cb), NULL);
2036 group_frame = pref_frame_new(subgroup, TRUE,
2037 _("Use standard thumbnail style and cache, shared with other applications"),
2038 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2039 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
2040 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2041 G_CALLBACK(cache_standard_cb), NULL);
2043 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
2044 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
2046 pref_checkbox_new_int(group, _("Thumbnail color management"),
2047 options->thumbnails.use_color_management, &c_options->thumbnails.use_color_management);
2049 spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
2051 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
2052 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
2054 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
2055 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
2056 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
2058 // pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
2059 // options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
2062 pref_spacer(group, PREF_PAD_GROUP);
2064 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
2066 c_options->star_rating.star = options->star_rating.star;
2067 c_options->star_rating.rejected = options->star_rating.rejected;
2069 str = g_string_new(NULL);
2070 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2071 pref_label_new(hbox, _("Star character: "));
2072 str = g_string_append_unichar(str, options->star_rating.star);
2073 pref_label_new(hbox, g_strdup(str->str));
2074 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
2075 star_rating_entry = gtk_entry_new();
2076 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2077 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2078 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2079 gtk_widget_show(star_rating_entry);
2080 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2081 G_CALLBACK(star_rating_star_test_cb), hbox);
2082 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2083 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2084 gtk_widget_show(button);
2085 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."));
2086 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2087 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2088 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2089 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2090 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2091 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2092 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2093 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2094 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2095 G_CALLBACK(star_rating_star_icon_cb),
2098 g_string_free(str, TRUE);
2099 g_free(rating_symbol);
2101 str = g_string_new(NULL);
2102 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2103 pref_label_new(hbox, _("Rejected character: "));
2104 str = g_string_append_unichar(str, options->star_rating.rejected);
2105 pref_label_new(hbox, g_strdup(str->str));
2106 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2107 star_rating_entry = gtk_entry_new();
2108 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2109 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2110 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2111 gtk_widget_show(star_rating_entry);
2112 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2113 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2114 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2115 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2116 gtk_widget_show(button);
2117 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."));
2118 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2119 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2120 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2121 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2122 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2123 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2124 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2125 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2126 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2127 G_CALLBACK(star_rating_rejected_icon_cb),
2130 g_string_free(str, TRUE);
2131 g_free(rating_symbol);
2133 pref_spacer(group, PREF_PAD_GROUP);
2135 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2137 c_options->slideshow.delay = options->slideshow.delay;
2138 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2139 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2140 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2141 seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2142 SLIDESHOW_SUBSECOND_PRECISION;
2144 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2146 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2148 options->slideshow.delay ? hours : 0.0,
2149 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2150 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2151 spin = pref_spin_new(hbox, ":" , NULL,
2153 options->slideshow.delay ? minutes: 0.0,
2154 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2155 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2156 spin = pref_spin_new(hbox, ":", NULL,
2157 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2158 options->slideshow.delay ? seconds : 10.0,
2159 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2160 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2162 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2163 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2165 pref_spacer(group, PREF_PAD_GROUP);
2167 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2169 pref_spin_new_int(group, _("Decoded image cache size (MiB):"), NULL,
2170 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2171 pref_checkbox_new_int(group, _("Preload next image"),
2172 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2174 pref_checkbox_new_int(group, _("Refresh on file change"),
2175 options->update_on_time_change, &c_options->update_on_time_change);
2178 pref_spacer(group, PREF_PAD_GROUP);
2180 group = pref_group_new(vbox, FALSE, _("Expand menu and toolbar"), GTK_ORIENTATION_VERTICAL);
2182 pref_checkbox_new_int(group, _("Expand menu and toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2183 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2184 gtk_widget_set_tooltip_text(group, _("Expand the menu and toolbar to the full width of the window"));
2186 pref_spacer(group, PREF_PAD_GROUP);
2188 net_mon = g_network_monitor_get_default();
2189 tz_org = g_network_address_parse_uri(TIMEZONE_DATABASE_WEB, 80, NULL);
2192 internet_available = g_network_monitor_can_reach(net_mon, tz_org, NULL, NULL);
2193 g_object_unref(tz_org);
2196 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2197 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2199 if (!internet_available)
2201 gtk_widget_set_sensitive(group, FALSE);
2204 tz = g_new0(TZData, 1);
2206 path = path_from_utf8(TIMEZONE_DATABASE_WEB);
2207 basename = g_path_get_basename(path);
2208 tz->timezone_database_user = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
2212 if (isfile(tz->timezone_database_user))
2214 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2218 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2221 download_locn = g_strconcat(_("Download database from: "), TIMEZONE_DATABASE_WEB, NULL);
2222 pref_label_new(GTK_WIDGET(hbox), download_locn);
2223 g_free(download_locn);
2225 if (!internet_available)
2227 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"));
2231 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"));
2233 gtk_widget_show(button);
2235 pref_spacer(group, PREF_PAD_GROUP);
2237 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2239 help_search_engine_entry = gtk_entry_new();
2240 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2241 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2242 gtk_widget_show(help_search_engine_entry);
2244 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"));
2246 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2247 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2248 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2249 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2250 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2251 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2252 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2253 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2254 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2255 G_CALLBACK(help_search_engine_entry_icon_cb),
2256 help_search_engine_entry);
2260 static void config_tab_image(GtkWidget *notebook)
2265 GtkWidget *ct_button;
2266 GtkWidget *enlargement_button;
2269 GtkWidget *two_pass;
2271 GtkWidget *gpu_accel;
2274 vbox = scrolled_notebook_page(notebook, _("Image"));
2276 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2278 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2279 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2280 if (options->image.use_clutter_renderer && !options->disable_gpu)
2282 gtk_widget_set_sensitive(table, FALSE);
2286 gpu_accel = pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library (Requires restart)"),
2287 options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2288 if (options->disable_gpu && !options->override_disable_gpu)
2290 gtk_widget_set_sensitive(gpu_accel, FALSE);
2294 two_pass = pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2295 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2296 if (options->image.use_clutter_renderer && !options->disable_gpu)
2298 gtk_widget_set_sensitive(two_pass, FALSE);
2301 c_options->image.zoom_increment = options->image.zoom_increment;
2302 spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2303 0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2304 G_CALLBACK(zoom_increment_cb), NULL);
2305 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2307 c_options->image.zoom_style = options->image.zoom_style;
2308 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2309 add_zoom_style_selection_menu(table, 0, 0, _("Zoom style:"), options->image.zoom_style, &c_options->image.zoom_style);
2311 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2313 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2314 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2315 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2316 spin = pref_spin_new_int(hbox, NULL, NULL,
2318 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2319 pref_checkbox_link_sensitivity(enlargement_button, spin);
2320 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."));
2322 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2323 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2324 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2325 spin = pref_spin_new_int(hbox, NULL, NULL,
2327 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2328 pref_checkbox_link_sensitivity(ct_button, spin);
2329 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."));
2331 group = pref_group_new(vbox, FALSE, _("Tile size"), GTK_ORIENTATION_VERTICAL);
2332 gtk_widget_set_sensitive(group, !options->image.use_clutter_renderer);
2334 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2335 spin = pref_spin_new_int(hbox, _("Pixels"), _("(Requires restart)"),
2337 options->image.tile_size, &c_options->image.tile_size);
2338 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."));
2340 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2342 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2343 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2345 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2346 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2348 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2349 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2351 c_options->image.border_color = options->image.border_color;
2353 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2354 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2356 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2357 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2359 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2360 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2365 static void save_default_window_layout_cb(GtkWidget *widget, gpointer data)
2367 LayoutWindow *lw = NULL;
2368 gchar *default_path;
2371 /* Get current lw */
2374 tmp_id = lw->options.id;
2375 lw->options.id = g_strdup("lw_default");
2377 default_path = g_build_filename(get_rc_dir(), DEFAULT_WINDOW_LAYOUT, NULL);
2378 save_default_layout_options_to_file(default_path, options, lw);
2379 g_free(lw->options.id);
2380 lw->options.id = tmp_id;
2381 g_free(default_path);
2384 #if GTK_CHECK_VERSION(3,22,0)
2385 static gboolean popover_cb(gpointer data)
2387 GtkPopover *popover = data;
2389 gtk_popover_popdown(popover);
2394 static void default_layout_changed_cb(GtkWidget *button, GtkPopover *popover)
2396 gtk_popover_popup(popover);
2398 g_timeout_add(2000, popover_cb, popover);
2401 static GtkWidget *create_popover(GtkWidget *parent, GtkWidget *child, GtkPositionType pos)
2405 popover = gtk_popover_new(parent);
2406 gtk_popover_set_position(GTK_POPOVER (popover), pos);
2407 gtk_container_add (GTK_CONTAINER(popover), child);
2408 gtk_container_set_border_width(GTK_CONTAINER (popover), 6);
2409 gtk_widget_show (child);
2415 static void config_tab_windows(GtkWidget *notebook)
2420 GtkWidget *subgroup;
2422 GtkWidget *ct_button;
2425 vbox = scrolled_notebook_page(notebook, _("Windows"));
2427 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2429 ct_button = pref_checkbox_new_int(group, _("Remember session"),
2430 options->save_window_positions, &c_options->save_window_positions);
2432 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2433 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2434 pref_checkbox_link_sensitivity(ct_button, button);
2436 button = pref_checkbox_new_int(group, _("Remember window workspace"),
2437 options->save_window_workspace, &c_options->save_window_workspace);
2438 pref_checkbox_link_sensitivity(ct_button, button);
2440 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2441 options->tools_restore_state, &c_options->tools_restore_state);
2443 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2444 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2446 pref_checkbox_new_int(group, _("Show window IDs"),
2447 options->show_window_ids, &c_options->show_window_ids);
2449 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2450 pref_label_new(subgroup, _("Use current layout for default: "));
2451 button = pref_button_new(subgroup, NULL, _("Set"), FALSE, G_CALLBACK(save_default_window_layout_cb), NULL);
2453 #if GTK_CHECK_VERSION(3,22,0)
2456 popover = create_popover(button, gtk_label_new(_("Current window layout\nhas been set as default")), GTK_POS_TOP);
2457 gtk_popover_set_modal(GTK_POPOVER (popover), FALSE);
2458 g_signal_connect(button, "clicked", G_CALLBACK(default_layout_changed_cb), popover);
2461 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2463 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2464 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2466 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2467 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2468 options->image.limit_window_size, &c_options->image.limit_window_size);
2469 spin = pref_spin_new_int(hbox, NULL, NULL,
2471 options->image.max_window_size, &c_options->image.max_window_size);
2472 pref_checkbox_link_sensitivity(ct_button, spin);
2474 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2476 c_options->fullscreen.screen = options->fullscreen.screen;
2477 c_options->fullscreen.above = options->fullscreen.above;
2478 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2479 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2480 gtk_widget_show(hbox);
2482 pref_checkbox_new_int(group, _("Smooth image flip"),
2483 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2484 pref_checkbox_new_int(group, _("Disable screen saver"),
2485 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2488 #define PRE_FORMATTED_COLUMNS 5
2489 static void config_tab_osd(GtkWidget *notebook)
2495 GtkWidget *image_overlay_template_view;
2496 GtkWidget *scrolled;
2497 GtkWidget *scrolled_pre_formatted;
2498 GtkTextBuffer *buffer;
2500 GtkWidget *subgroup;
2502 vbox = scrolled_notebook_page(notebook, _("OSD"));
2504 image_overlay_template_view = gtk_text_view_new();
2506 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2508 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2510 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2511 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2512 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2513 gtk_widget_show(scrolled_pre_formatted);
2514 gtk_widget_show(subgroup);
2516 pref_line(group, PREF_PAD_GAP);
2518 pref_label_new(group, _("Image overlay template"));
2520 scrolled = gtk_scrolled_window_new(NULL, NULL);
2521 gtk_widget_set_size_request(scrolled, 200, 150);
2522 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2523 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2524 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2525 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2526 gtk_widget_show(scrolled);
2528 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2529 _("Extensive formatting options are shown in the Help file"));
2531 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2532 gtk_widget_show(image_overlay_template_view);
2534 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2536 #if GTK_CHECK_VERSION(3,4,0)
2537 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2538 G_CALLBACK(image_overlay_set_font_cb), notebook);
2540 button = gtk_font_button_new();
2541 gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
2542 gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
2543 g_signal_connect(G_OBJECT(button), "font-set",
2544 G_CALLBACK(image_overlay_set_font_cb),NULL);
2546 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2547 gtk_widget_show(button);
2549 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2550 G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2551 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2552 gtk_widget_show(button);
2554 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2555 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2556 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2557 gtk_widget_show(button);
2558 image_overlay_set_text_colours();
2560 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2561 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2562 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2563 gtk_widget_show(button);
2565 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2566 G_CALLBACK(image_overlay_help_cb), NULL);
2567 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2568 gtk_widget_show(button);
2570 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2571 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2572 g_signal_connect(G_OBJECT(buffer), "changed",
2573 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2575 pref_line(group, PREF_PAD_GAP);
2577 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2578 hbox = gtk_hbox_new(FALSE, 0);
2579 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2580 gtk_widget_show(hbox);
2581 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2582 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2583 gtk_widget_show(label);
2584 pref_spacer(group,TRUE);
2586 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2587 hbox = gtk_hbox_new(FALSE, 0);
2588 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2589 gtk_widget_show(hbox);
2590 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2591 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2592 gtk_widget_show(label);
2593 pref_spacer(group,TRUE);
2595 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2596 hbox = gtk_hbox_new(FALSE, 0);
2597 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2598 gtk_widget_show(hbox);
2599 label = gtk_label_new(_("%path:39%"));
2600 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2601 gtk_widget_show(label);
2602 pref_spacer(group,TRUE);
2604 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2605 hbox = gtk_hbox_new(FALSE, 0);
2606 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2607 gtk_widget_show(hbox);
2608 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%"));
2609 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2610 gtk_widget_show(label);
2611 pref_spacer(group,TRUE);
2613 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2614 hbox = gtk_hbox_new(FALSE, 0);
2615 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2616 gtk_widget_show(hbox);
2617 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2618 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2619 gtk_widget_show(label);
2622 static GtkTreeModel *create_class_model(void)
2624 GtkListStore *model;
2628 /* create list store */
2629 model = gtk_list_store_new(1, G_TYPE_STRING);
2630 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2632 gtk_list_store_append(model, &iter);
2633 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2635 return GTK_TREE_MODEL (model);
2640 static gint filter_table_sort_cb(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data)
2642 gint n = GPOINTER_TO_INT(data);
2644 FilterEntry *filter_a;
2645 FilterEntry *filter_b;
2647 gtk_tree_model_get(model, a, 0, &filter_a, -1);
2648 gtk_tree_model_get(model, b, 0, &filter_b, -1);
2652 case FILETYPES_COLUMN_DESCRIPTION:
2654 ret = g_utf8_collate(filter_a->description, filter_b->description);
2657 case FILETYPES_COLUMN_CLASS:
2659 ret = g_strcmp0(format_class_list[filter_a->file_class], format_class_list[filter_b->file_class]);
2662 case FILETYPES_COLUMN_WRITABLE:
2664 ret = filter_a->writable - filter_b->writable;
2667 case FILETYPES_COLUMN_SIDECAR:
2669 ret = filter_a->allow_sidecar - filter_b->allow_sidecar;
2673 g_return_val_if_reached(0);
2679 static gboolean search_function_cb(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer search_data)
2682 gboolean ret = TRUE;
2684 gtk_tree_model_get(model, iter, 0, &fe, -1);
2686 if (g_strstr_len(fe->extensions, -1, key))
2694 static void config_tab_files(GtkWidget *notebook)
2701 GtkWidget *ct_button;
2702 GtkWidget *scrolled;
2703 GtkWidget *filter_view;
2704 GtkCellRenderer *renderer;
2705 GtkTreeSelection *selection;
2706 GtkTreeViewColumn *column;
2708 vbox = scrolled_notebook_page(notebook, _("Files"));
2710 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2712 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2713 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2714 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2715 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2716 pref_checkbox_new_int(group, _("Case sensitive sort"),
2717 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2718 pref_checkbox_new_int(group, _("Natural sort order"),
2719 options->file_sort.natural, &c_options->file_sort.natural);
2720 pref_checkbox_new_int(group, _("Disable file extension checks"),
2721 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2723 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2724 options->file_filter.disable, &c_options->file_filter.disable);
2727 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2729 sidecar_ext_entry = gtk_entry_new();
2730 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2731 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2732 gtk_widget_show(sidecar_ext_entry);
2734 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2736 frame = pref_group_parent(group);
2737 g_signal_connect(G_OBJECT(ct_button), "toggled",
2738 G_CALLBACK(filter_disable_cb), frame);
2739 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2741 scrolled = gtk_scrolled_window_new(NULL, NULL);
2742 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2743 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2744 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2745 gtk_widget_show(scrolled);
2747 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2748 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2749 g_object_unref(filter_store);
2750 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2751 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2753 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2755 column = gtk_tree_view_column_new();
2756 gtk_tree_view_column_set_title(column, _("Filter"));
2757 gtk_tree_view_column_set_resizable(column, TRUE);
2759 renderer = gtk_cell_renderer_toggle_new();
2760 g_signal_connect(G_OBJECT(renderer), "toggled",
2761 G_CALLBACK(filter_store_enable_cb), filter_store);
2762 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2763 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2764 GINT_TO_POINTER(FE_ENABLE), NULL);
2766 renderer = gtk_cell_renderer_text_new();
2767 g_signal_connect(G_OBJECT(renderer), "edited",
2768 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2769 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2770 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2771 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2772 GINT_TO_POINTER(FE_EXTENSION), NULL);
2773 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2775 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), TRUE);
2776 gtk_tree_view_set_search_column(GTK_TREE_VIEW(filter_view), FILETYPES_COLUMN_FILTER);
2777 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(filter_view), search_function_cb, NULL, NULL);
2779 column = gtk_tree_view_column_new();
2780 gtk_tree_view_column_set_title(column, _("Description"));
2781 gtk_tree_view_column_set_resizable(column, TRUE);
2782 gtk_tree_view_column_set_fixed_width(column, 200);
2783 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2785 renderer = gtk_cell_renderer_text_new();
2786 g_signal_connect(G_OBJECT(renderer), "edited",
2787 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2788 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2789 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2790 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2791 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2792 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2793 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);
2794 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_DESCRIPTION);
2796 column = gtk_tree_view_column_new();
2797 gtk_tree_view_column_set_title(column, _("Class"));
2798 gtk_tree_view_column_set_resizable(column, TRUE);
2799 renderer = gtk_cell_renderer_combo_new();
2800 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2801 "model", create_class_model(),
2806 g_signal_connect(G_OBJECT(renderer), "edited",
2807 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2808 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2809 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2810 GINT_TO_POINTER(FE_CLASS), NULL);
2811 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2812 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_CLASS, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_CLASS), NULL);
2813 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_CLASS);
2815 column = gtk_tree_view_column_new();
2816 gtk_tree_view_column_set_title(column, _("Writable"));
2817 gtk_tree_view_column_set_resizable(column, FALSE);
2818 renderer = gtk_cell_renderer_toggle_new();
2819 g_signal_connect(G_OBJECT(renderer), "toggled",
2820 G_CALLBACK(filter_store_writable_cb), filter_store);
2821 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2822 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2823 GINT_TO_POINTER(FE_WRITABLE), NULL);
2824 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2825 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_WRITABLE, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_WRITABLE), NULL);
2826 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_WRITABLE);
2828 column = gtk_tree_view_column_new();
2829 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2830 gtk_tree_view_column_set_resizable(column, FALSE);
2831 renderer = gtk_cell_renderer_toggle_new();
2832 g_signal_connect(G_OBJECT(renderer), "toggled",
2833 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2834 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2835 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2836 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2837 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2838 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_SIDECAR, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_SIDECAR), NULL);
2839 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_SIDECAR);
2841 filter_store_populate();
2842 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2843 gtk_widget_show(filter_view);
2845 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2847 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2848 G_CALLBACK(filter_default_cb), filter_view);
2849 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2850 gtk_widget_show(button);
2852 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2853 G_CALLBACK(filter_remove_cb), filter_view);
2854 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2855 gtk_widget_show(button);
2857 button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2858 G_CALLBACK(filter_add_cb), filter_view);
2859 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2860 gtk_widget_show(button);
2864 static void config_tab_metadata(GtkWidget *notebook)
2869 GtkWidget *ct_button;
2873 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2876 group = pref_group_new(vbox, FALSE, _("Metadata writing process"), GTK_ORIENTATION_VERTICAL);
2878 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2880 label = pref_label_new(group, _("Metadata are written in the following order. The process ends after first success."));
2881 #if GTK_CHECK_VERSION(3,16,0)
2882 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2883 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2885 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2888 ct_button = pref_checkbox_new_int(group, _("1) Save metadata in image files, or sidecar files, according to the XMP standard"),
2889 options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2891 gtk_widget_set_sensitive(ct_button, FALSE);
2894 pref_checkbox_new_int(group, _("2) Save metadata in '.metadata' folder, local to image folder (non-standard)"),
2895 options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2897 text = g_strdup_printf(_("3) Save metadata in Geeqie private directory '%s'"), get_metadata_cache_dir());
2898 label = pref_label_new(group, text);
2899 #if GTK_CHECK_VERSION(3,16,0)
2900 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2901 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2903 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2905 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2908 group = pref_group_new(vbox, FALSE, _("Step 1: Write to image files"), GTK_ORIENTATION_VERTICAL);
2910 gtk_widget_set_sensitive(group, FALSE);
2913 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2914 pref_checkbox_link_sensitivity(ct_button, hbox);
2916 pref_checkbox_new_int(hbox, _("Store metadata also in legacy IPTC tags (converted according to IPTC4XMP standard)"),
2917 options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2919 pref_checkbox_new_int(hbox, _("Warn if the image files are unwritable"),
2920 options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2922 pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
2923 options->metadata.confirm_write, &c_options->metadata.confirm_write);
2925 pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
2926 options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2928 group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
2930 gtk_widget_set_sensitive(group, FALSE);
2933 pref_checkbox_new_int(group, _("Use GQview legacy metadata format (supports only keywords and comments) instead of XMP"),
2934 options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2937 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2938 pref_checkbox_new_int(group, _("Write the same description tags (keywords, comment, etc.) to all grouped sidecars"),
2939 options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2941 pref_checkbox_new_int(group, _("Allow keywords to differ only in case"),
2942 options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2944 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"),
2945 options->metadata.write_orientation, &c_options->metadata.write_orientation);
2947 gtk_widget_set_sensitive(ct_button, FALSE);
2950 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2952 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"),
2953 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,
2959 options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2961 pref_checkbox_new_int(group, _("Write metadata on image change"),
2962 options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2964 pref_checkbox_new_int(group, _("Write metadata on directory change"),
2965 options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2968 #if GTK_CHECK_VERSION(3,20,0)
2969 group = pref_group_new(vbox, FALSE, _("Spelling checks"), GTK_ORIENTATION_VERTICAL);
2971 ct_button = pref_checkbox_new_int(group, _("Check spelling -Requires restart"), options->metadata.check_spelling, &c_options->metadata.check_spelling);
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"),
2978 options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2979 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");
2984 typedef struct _KeywordFindData KeywordFindData;
2985 struct _KeywordFindData
2992 GtkWidget *button_close;
2993 GtkWidget *button_stop;
2994 GtkWidget *button_start;
2995 GtkWidget *progress;
3003 guint idle_id; /* event source id */
3006 #define KEYWORD_DIALOG_WIDTH 400
3008 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
3010 GList *list_d = NULL;
3011 GList *list_f = NULL;
3015 filelist_read(dir_fd, &list_f, &list_d);
3019 filelist_read(dir_fd, &list_f, NULL);
3022 list_f = filelist_filter(list_f, FALSE);
3023 list_d = filelist_filter(list_d, TRUE);
3025 kfd->list = g_list_concat(list_f, kfd->list);
3026 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
3029 static void keywords_find_reset(KeywordFindData *kfd)
3031 filelist_free(kfd->list);
3034 filelist_free(kfd->list_dir);
3035 kfd->list_dir = NULL;
3038 static void keywords_find_close_cb(GenericDialog *fd, gpointer data)
3040 KeywordFindData *kfd = data;
3042 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
3044 keywords_find_reset(kfd);
3045 generic_dialog_close(kfd->gd);
3049 static void keywords_find_finish(KeywordFindData *kfd)
3051 keywords_find_reset(kfd);
3053 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
3054 spinner_set_interval(kfd->spinner, -1);
3056 gtk_widget_set_sensitive(kfd->group, TRUE);
3057 gtk_widget_set_sensitive(kfd->button_start, TRUE);
3058 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3059 gtk_widget_set_sensitive(kfd->button_close, TRUE);
3062 static void keywords_find_stop_cb(GenericDialog *fd, gpointer data)
3064 KeywordFindData *kfd = data;
3066 g_idle_remove_by_data(kfd);
3068 keywords_find_finish(kfd);
3071 static gboolean keywords_find_file(gpointer data)
3073 KeywordFindData *kfd = data;
3075 GtkTextBuffer *buffer;
3083 fd = kfd->list->data;
3084 kfd->list = g_list_remove(kfd->list, fd);
3086 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
3087 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3091 gtk_text_buffer_get_end_iter(buffer, &iter);
3092 tmp = g_strconcat(keywords->data, "\n", NULL);
3093 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3095 keywords = keywords->next;
3098 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
3099 file_data_unref(fd);
3100 string_list_free(keywords);
3104 else if (kfd->list_dir)
3108 fd = kfd->list_dir->data;
3109 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
3111 keywords_find_folder(kfd, fd);
3113 file_data_unref(fd);
3118 keywords_find_finish(kfd);
3123 static void keywords_find_start_cb(GenericDialog *fd, gpointer data)
3125 KeywordFindData *kfd = data;
3128 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
3130 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
3131 parse_out_relatives(path);
3135 warning_dialog(_("Invalid folder"),
3136 _("The specified folder can not be found."),
3137 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
3143 gtk_widget_set_sensitive(kfd->group, FALSE);
3144 gtk_widget_set_sensitive(kfd->button_start, FALSE);
3145 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
3146 gtk_widget_set_sensitive(kfd->button_close, FALSE);
3147 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
3149 dir_fd = file_data_new_dir(path);
3150 keywords_find_folder(kfd, dir_fd);
3151 file_data_unref(dir_fd);
3152 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
3158 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
3160 KeywordFindData *kfd;
3164 kfd = g_new0(KeywordFindData, 1);
3166 kfd->gd = generic_dialog_new(_("Search for keywords"),
3167 "search_for_keywords",
3170 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
3171 kfd->gd->cancel_cb = keywords_find_close_cb;
3172 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
3173 keywords_find_close_cb, FALSE);
3174 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
3175 keywords_find_start_cb, FALSE);
3176 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
3177 keywords_find_stop_cb, FALSE);
3178 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3180 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
3182 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
3183 pref_spacer(hbox, PREF_PAD_INDENT);
3184 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
3186 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3187 pref_label_new(hbox, _("Folder:"));
3189 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
3190 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
3191 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
3192 gtk_widget_show(label);
3194 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
3196 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
3197 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3199 kfd->progress = gtk_entry_new();
3200 gtk_widget_set_can_focus(kfd->progress, FALSE);
3201 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
3202 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
3203 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
3204 gtk_widget_show(kfd->progress);
3206 kfd->spinner = spinner_new(NULL, -1);
3207 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
3208 gtk_widget_show(kfd->spinner);
3212 gtk_widget_show(kfd->gd->dialog);
3215 static void keywords_find_cb(GtkWidget *widget, gpointer data)
3217 const gchar *path = layout_get_path(NULL);
3219 if (!path || !*path) path = homedir();
3220 keywords_find_dialog(widget, path);
3223 static void config_tab_keywords_save()
3225 GtkTextIter start, end;
3226 GtkTextBuffer *buffer;
3227 GList *kw_list = NULL;
3233 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3234 gtk_text_buffer_get_bounds(buffer, &start, &end);
3236 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3238 kw_split = strtok(buffer_text, "\n");
3239 while (kw_split != NULL)
3245 if (g_strcmp0(work->data, kw_split) == 0)
3254 kw_list = g_list_append(kw_list, g_strdup(kw_split));
3256 kw_split = strtok(NULL, "\n");
3259 keyword_list_set(kw_list);
3261 string_list_free(kw_list);
3262 g_free(buffer_text);
3265 static void config_tab_keywords(GtkWidget *notebook)
3271 GtkWidget *scrolled;
3273 GtkTextBuffer *buffer;
3276 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3278 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3280 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3282 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
3283 G_CALLBACK(keywords_find_cb), keyword_text);
3284 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
3287 keyword_text = gtk_text_view_new();
3288 gtk_widget_set_size_request(keyword_text, 20, 20);
3289 scrolled = gtk_scrolled_window_new(NULL, NULL);
3290 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3291 gtk_widget_show(scrolled);
3293 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
3294 gtk_widget_show(keyword_text);
3296 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3298 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3299 gtk_text_buffer_create_tag(buffer, "monospace",
3300 "family", "monospace", NULL);
3302 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3303 gtk_text_buffer_get_start_iter(buffer, &iter);
3304 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3307 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3309 GList *kwl = keyword_list_get();
3310 kwl = g_list_first(kwl);
3313 gtk_text_buffer_get_end_iter (buffer, &iter);
3314 tmp = g_strconcat(kwl->data, "\n", NULL);
3315 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3320 gtk_text_buffer_set_modified(buffer, FALSE);
3327 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3329 gint *option = data;
3331 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3335 *option = INTENT_PERCEPTUAL;
3338 *option = INTENT_RELATIVE_COLORIMETRIC;
3341 *option = INTENT_SATURATION;
3344 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3349 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3350 gint option, gint *option_c)
3357 pref_table_label(table, column, row, text, 0.0);
3359 combo = gtk_combo_box_text_new();
3361 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3362 if (option == INTENT_PERCEPTUAL) current = 0;
3363 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3364 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3365 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3366 if (option == INTENT_SATURATION) current = 2;
3367 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3368 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3370 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3372 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3374 g_signal_connect(G_OBJECT(combo), "changed",
3375 G_CALLBACK(intent_menu_cb), option_c);
3377 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
3378 gtk_widget_show(combo);
3382 static void config_tab_color(GtkWidget *notebook)
3391 vbox = scrolled_notebook_page(notebook, _("Color management"));
3393 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3395 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3398 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3399 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3401 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3402 pref_label_bold(label, TRUE, FALSE);
3404 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3405 pref_label_bold(label, TRUE, FALSE);
3407 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3408 pref_label_bold(label, TRUE, FALSE);
3410 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3415 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3416 pref_table_label(table, 0, i + 1, buf, 1.0);
3419 entry = gtk_entry_new();
3420 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3421 if (options->color_profile.input_name[i])
3423 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3425 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3426 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3427 gtk_widget_show(entry);
3428 color_profile_input_name_entry[i] = entry;
3430 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3431 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3432 gtk_widget_set_size_request(entry, 160, -1);
3433 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3434 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3435 gtk_widget_show(tabcomp);
3436 color_profile_input_file_entry[i] = entry;
3439 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3441 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3443 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3444 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3446 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3448 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3449 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3450 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3451 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3452 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3454 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3456 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3458 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3460 gtk_widget_show(tabcomp);
3463 /* advanced entry tab */
3464 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer data)
3466 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3468 c_options->file_ops.use_system_trash = FALSE;
3469 c_options->file_ops.no_trash = FALSE;
3473 static void use_system_trash_cb(GtkWidget *widget, gpointer data)
3475 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3477 c_options->file_ops.use_system_trash = TRUE;
3478 c_options->file_ops.no_trash = FALSE;
3482 static void use_no_cache_cb(GtkWidget *widget, gpointer data)
3484 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3486 c_options->file_ops.no_trash = TRUE;
3490 static void config_tab_behavior(GtkWidget *notebook)
3497 GtkWidget *ct_button;
3501 GtkWidget *with_rename;
3502 GtkWidget *collections_on_top;
3503 GtkWidget *hide_window_in_fullscreen;
3504 GtkWidget *checkbox;
3507 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3509 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3511 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3512 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3513 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3514 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3515 pref_checkbox_new_int(group, _("Enable Delete key"),
3516 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3518 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3519 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3521 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3522 pref_checkbox_link_sensitivity(ct_button, hbox);
3524 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3525 pref_label_new(hbox, _("Folder:"));
3527 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3528 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3529 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3530 gtk_widget_show(tabcomp);
3532 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3533 pref_checkbox_link_sensitivity(ct_button, hbox);
3535 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3536 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MiB"),
3537 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3538 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3539 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3540 G_CALLBACK(safe_delete_view_cb), NULL);
3541 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3542 gtk_widget_show(button);
3544 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3545 G_CALLBACK(safe_delete_clear_cb), NULL);
3546 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3548 c_options->file_ops.no_trash = options->file_ops.no_trash;
3549 c_options->file_ops.use_system_trash = options->file_ops.use_system_trash;
3551 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3552 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3554 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3555 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3557 gtk_widget_show(button);
3559 pref_spacer(group, PREF_PAD_GROUP);
3562 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3564 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3565 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3567 pref_checkbox_new_int(group, _("In place renaming"),
3568 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3570 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3571 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3573 tmp = pref_checkbox_new_int(group, _("Circular selection lists"),
3574 options->circular_selection_lists, &c_options->circular_selection_lists);
3575 gtk_widget_set_tooltip_text(tmp, _("Traverse selection lists in a circular manner"));
3577 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3578 options->marks_save, &c_options->marks_save);
3579 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3581 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3582 options->with_rename, &c_options->with_rename);
3583 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3585 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3586 options->collections_on_top, &c_options->collections_on_top);
3587 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3589 hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3590 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3591 gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice");
3593 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3594 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3596 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3597 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3599 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3600 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3602 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3603 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3605 pref_spacer(group, PREF_PAD_GROUP);
3607 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3609 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3610 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3611 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3612 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3613 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3614 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3615 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3616 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3617 pref_checkbox_new_int(group, _("Open archive by left click on image"),
3618 options->image_l_click_archive, &c_options->image_l_click_archive);
3619 pref_checkbox_new_int(group, _("Play video by left click on image"),
3620 options->image_l_click_video, &c_options->image_l_click_video);
3621 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3622 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3624 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3625 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3626 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3627 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3628 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3630 pref_spacer(group, PREF_PAD_GROUP);
3632 group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3634 checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3635 options->override_disable_gpu, &c_options->override_disable_gpu);
3636 gtk_widget_set_tooltip_text(checkbox, "Contact the developers for usage");
3639 pref_spacer(group, PREF_PAD_GROUP);
3641 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3643 pref_spin_new_int(group, _("Debug level:"), NULL,
3644 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3646 pref_checkbox_new_int(group, _("Timer data"),
3647 options->log_window.timer_data, &c_options->log_window.timer_data);
3649 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3650 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3654 /* accelerators tab */
3655 static void config_tab_accelerators(GtkWidget *notebook)
3661 GtkWidget *scrolled;
3662 GtkWidget *accel_view;
3663 GtkCellRenderer *renderer;
3664 GtkTreeSelection *selection;
3665 GtkTreeViewColumn *column;
3667 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3669 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3671 scrolled = gtk_scrolled_window_new(NULL, NULL);
3672 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3673 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3674 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3675 gtk_widget_show(scrolled);
3677 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3679 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3680 g_object_unref(accel_store);
3681 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3682 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3684 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3686 renderer = gtk_cell_renderer_text_new();
3688 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3693 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3694 gtk_tree_view_column_set_resizable(column, TRUE);
3695 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3698 renderer = gtk_cell_renderer_accel_new();
3699 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3700 G_CALLBACK(accel_store_cleared_cb), accel_store);
3701 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3702 G_CALLBACK(accel_store_edited_cb), accel_store);
3705 g_object_set (renderer,
3707 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3710 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3715 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3716 gtk_tree_view_column_set_resizable(column, TRUE);
3717 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3719 renderer = gtk_cell_renderer_text_new();
3721 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3726 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3727 gtk_tree_view_column_set_resizable(column, TRUE);
3728 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3730 renderer = gtk_cell_renderer_text_new();
3732 column = gtk_tree_view_column_new_with_attributes("Accel",
3737 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3738 gtk_tree_view_column_set_resizable(column, TRUE);
3739 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3741 accel_store_populate();
3742 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3743 gtk_widget_show(accel_view);
3745 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3747 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3748 G_CALLBACK(accel_default_cb), accel_view);
3749 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3750 gtk_widget_show(button);
3752 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3753 G_CALLBACK(accel_reset_cb), accel_view);
3754 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3755 gtk_widget_show(button);
3758 /* toolbar main tab */
3759 static void config_tab_toolbar_main(GtkWidget *notebook)
3762 GtkWidget *toolbardata;
3765 lw = layout_window_list->data;
3767 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3769 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3770 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3771 gtk_widget_show(vbox);
3774 /* toolbar status tab */
3775 static void config_tab_toolbar_status(GtkWidget *notebook)
3778 GtkWidget *toolbardata;
3781 lw = layout_window_list->data;
3783 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3785 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3786 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3787 gtk_widget_show(vbox);
3791 static gint extension_sort_cb(gconstpointer a, gconstpointer b)
3793 return g_strcmp0((gchar *)a, (gchar *)b);
3796 static void config_tab_advanced(GtkWidget *notebook)
3800 GSList *formats_list;
3801 GList *extensions_list = NULL;
3804 GdkPixbufFormat *fm;
3806 GString *types_string = g_string_new(NULL);
3807 GtkWidget *types_string_label;
3808 GtkWidget *threads_string_label;
3809 GtkWidget *dupes_threads_spin;
3811 vbox = scrolled_notebook_page(notebook, _("Advanced"));
3812 group = pref_group_new(vbox, FALSE, _("External preview extraction"), GTK_ORIENTATION_VERTICAL);
3814 pref_checkbox_new_int(group, _("Use external preview extraction - Requires restart"), options->external_preview.enable, &c_options->external_preview.enable);
3816 pref_spacer(group, PREF_PAD_GROUP);
3818 formats_list = gdk_pixbuf_get_formats();
3820 while (formats_list)
3822 fm = formats_list->data;
3823 extensions = gdk_pixbuf_format_get_extensions(fm);
3826 while (extensions[i])
3828 extensions_list = g_list_insert_sorted(extensions_list, g_strdup(extensions[i]), extension_sort_cb);
3832 g_strfreev(extensions);
3833 formats_list = formats_list->next;
3836 while (extensions_list)
3838 if (types_string->len == 0)
3840 types_string = g_string_append(types_string, extensions_list->data);
3844 types_string = g_string_append(types_string, ", ");
3845 types_string = g_string_append(types_string, extensions_list->data);
3848 extensions_list = extensions_list->next;
3851 types_string = g_string_prepend(types_string, _("Usable file types:\n"));
3852 types_string_label = pref_label_new(group, types_string->str);
3853 gtk_label_set_line_wrap(GTK_LABEL(types_string_label), TRUE);
3855 pref_spacer(group, PREF_PAD_GROUP);
3857 group = pref_group_new(vbox, FALSE, _("File identification tool"), GTK_ORIENTATION_VERTICAL);
3858 external_preview_select_entry = gtk_entry_new();
3859 tabcomp = tab_completion_new(&external_preview_select_entry, options->external_preview.select, NULL, NULL, NULL, NULL);
3860 tab_completion_add_select_button(external_preview_select_entry, _("Select file identification tool"), FALSE);
3861 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3862 gtk_widget_show(tabcomp);
3864 group = pref_group_new(vbox, FALSE, _("Preview extraction tool"), GTK_ORIENTATION_VERTICAL);
3865 external_preview_extract_entry = gtk_entry_new();
3866 tabcomp = tab_completion_new(&external_preview_extract_entry, options->external_preview.extract, NULL, NULL, NULL, NULL);
3867 tab_completion_add_select_button(external_preview_extract_entry, _("Select preview extraction tool"), FALSE);
3868 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3869 gtk_widget_show(tabcomp);
3871 gtk_widget_show(vbox);
3873 g_slist_free(formats_list);
3874 string_list_free(extensions_list);
3875 g_string_free(types_string, TRUE);
3877 pref_spacer(group, PREF_PAD_GROUP);
3879 pref_line(vbox, PREF_PAD_SPACE);
3880 group = pref_group_new(vbox, FALSE, _("Thread pool limits"), GTK_ORIENTATION_VERTICAL);
3882 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.");
3883 gtk_label_set_line_wrap(GTK_LABEL(threads_string_label), TRUE);
3885 pref_spacer(vbox, PREF_PAD_GROUP);
3887 dupes_threads_spin = pref_spin_new_int(vbox, _("Duplicate check:"), _("max. threads"), 0, get_cpu_cores(), 1, options->threads.duplicates, &c_options->threads.duplicates);
3888 gtk_widget_set_tooltip_markup(dupes_threads_spin, _("Set to 0 for unlimited"));
3892 static void config_tab_stereo(GtkWidget *notebook)
3900 GtkWidget *fs_button;
3901 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3903 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3905 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3906 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3908 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3909 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3910 pref_checkbox_new_int(box, _("Mirror left image"),
3911 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3912 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3913 pref_checkbox_new_int(box, _("Flip left image"),
3914 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3915 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3916 pref_checkbox_new_int(box, _("Mirror right image"),
3917 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3918 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3919 pref_checkbox_new_int(box, _("Flip right image"),
3920 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3921 pref_checkbox_new_int(group, _("Swap left and right images"),
3922 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3923 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3924 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3926 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3927 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3928 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3929 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3930 pref_checkbox_link_sensitivity(fs_button, box2);
3931 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3932 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3933 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3934 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3935 pref_checkbox_new_int(box, _("Mirror left image"),
3936 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3937 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3938 pref_checkbox_new_int(box, _("Flip left image"),
3939 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3940 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3941 pref_checkbox_new_int(box, _("Mirror right image"),
3942 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3943 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3944 pref_checkbox_new_int(box, _("Flip right image"),
3945 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3946 pref_checkbox_new_int(box2, _("Swap left and right images"),
3947 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3948 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3949 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3951 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3952 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3953 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3954 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3955 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
3956 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3957 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
3958 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3959 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
3960 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3961 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
3962 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3963 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
3964 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3968 /* Main preferences window */
3969 static void config_window_create(LayoutWindow *lw)
3971 GtkWidget *win_vbox;
3973 GtkWidget *notebook;
3975 GtkWidget *ct_button;
3977 if (!c_options) c_options = init_options(NULL);
3979 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3980 DEBUG_NAME(configwindow);
3981 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3982 g_signal_connect(G_OBJECT(configwindow), "delete_event",
3983 G_CALLBACK(config_window_delete), NULL);
3984 if (options->save_dialog_window_positions)
3986 gtk_window_resize(GTK_WINDOW(configwindow), lw->options.preferences_window.w, lw->options.preferences_window.h);
3987 gtk_window_move(GTK_WINDOW(configwindow), lw->options.preferences_window.x, lw->options.preferences_window.y);
3991 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
3993 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
3994 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
3996 win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
3997 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
3998 gtk_widget_show(win_vbox);
4000 notebook = gtk_notebook_new();
4001 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
4002 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
4003 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
4005 config_tab_general(notebook);
4006 config_tab_image(notebook);
4007 config_tab_osd(notebook);
4008 config_tab_windows(notebook);
4009 config_tab_accelerators(notebook);
4010 config_tab_files(notebook);
4011 config_tab_metadata(notebook);
4012 config_tab_keywords(notebook);
4013 config_tab_color(notebook);
4014 config_tab_stereo(notebook);
4015 config_tab_behavior(notebook);
4016 config_tab_toolbar_main(notebook);
4017 config_tab_toolbar_status(notebook);
4018 config_tab_advanced(notebook);
4020 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), lw->options.preferences_window.page_number);
4022 hbox = gtk_hbutton_box_new();
4023 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
4024 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
4025 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
4026 gtk_widget_show(hbox);
4028 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
4029 G_CALLBACK(config_window_help_cb), notebook);
4030 gtk_container_add(GTK_CONTAINER(hbox), button);
4031 gtk_widget_set_can_default(button, TRUE);
4032 gtk_widget_show(button);
4034 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
4035 G_CALLBACK(config_window_ok_cb), notebook);
4036 gtk_container_add(GTK_CONTAINER(hbox), button);
4037 gtk_widget_set_can_default(button, TRUE);
4038 gtk_widget_grab_default(button);
4039 gtk_widget_show(button);
4043 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
4044 G_CALLBACK(config_window_close_cb), NULL);
4045 gtk_container_add(GTK_CONTAINER(hbox), button);
4046 gtk_widget_set_can_default(button, TRUE);
4047 gtk_widget_show(button);
4049 if (!generic_dialog_get_alternative_button_order(configwindow))
4051 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
4054 gtk_widget_show(notebook);
4056 gtk_widget_show(configwindow);
4060 *-----------------------------------------------------------------------------
4061 * config window show (public)
4062 *-----------------------------------------------------------------------------
4065 void show_config_window(LayoutWindow *lw)
4069 gtk_window_present(GTK_WINDOW(configwindow));
4073 config_window_create(lw);
4082 void show_about_window(LayoutWindow *lw)
4084 GdkPixbuf *pixbuf_logo;
4085 GdkPixbuf *pixbuf_icon;
4086 gchar *authors[1000];
4091 gchar *timezone_path;
4094 #define LINE_LENGTH 1000
4095 gchar line[LINE_LENGTH];
4097 copyright = g_string_new(NULL);
4098 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");
4100 timezone_path = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
4101 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
4103 cd = ZDOpenDatabase(timezone_path);
4106 copyright = g_string_append(copyright, ZDGetNotice(cd));
4110 log_printf("Error: Init of timezone database %s failed\n", timezone_path);
4112 ZDCloseDatabase(cd);
4114 g_free(timezone_path);
4117 path = g_build_filename(gq_helpdir, "AUTHORS", NULL);
4118 fp = fopen(path, "r");
4121 while(fgets(line, LINE_LENGTH, fp))
4123 /* get rid of ending \n from fgets */
4124 line[strlen(line) - 1] = '\0';
4125 authors[i_authors] = g_strdup(line);
4128 authors[i_authors] = NULL;
4133 comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
4134 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
4136 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
4137 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
4138 gtk_show_about_dialog(GTK_WINDOW(lw->window),
4139 "title", _("About Geeqie"),
4141 "program-name", GQ_APPNAME,
4143 "logo", pixbuf_logo,
4144 "icon", pixbuf_icon,
4145 "website", GQ_WEBSITE,
4146 "website-label", "Website",
4147 "comments", comment,
4149 "translator-credits", _("translator-credits"),
4150 "wrap-license", TRUE,
4151 "license", copyright->str,
4154 g_string_free(copyright, TRUE);
4157 while(n < i_authors)
4167 static void image_overlay_set_text_colours()
4169 c_options->image_overlay.text_red = options->image_overlay.text_red;
4170 c_options->image_overlay.text_green = options->image_overlay.text_green;
4171 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
4172 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
4173 c_options->image_overlay.background_red = options->image_overlay.background_red;
4174 c_options->image_overlay.background_green = options->image_overlay.background_green;
4175 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
4176 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
4180 *-----------------------------------------------------------------------------
4181 * timezone database routines
4182 *-----------------------------------------------------------------------------
4185 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
4187 GError *error = NULL;
4189 gchar *tmp_filename;
4190 gchar *timezone_bin;
4191 gchar *tmp_dir = NULL;
4194 if (!g_cancellable_is_cancelled(tz->cancellable))
4196 generic_dialog_close(tz->gd);
4200 if (g_file_copy_finish(G_FILE(source_object), res, &error))
4202 tmp_filename = g_file_get_path(tz->tmp_g_file);
4203 fd = file_data_new_simple(tmp_filename);
4204 tmp_dir = open_archive(fd);
4208 timezone_bin = g_build_filename(tmp_dir, TIMEZONE_DATABASE_VERSION, TIMEZONE_DATABASE_FILE, NULL);
4209 if (isfile(timezone_bin))
4211 move_file(timezone_bin, tz->timezone_database_user);
4215 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GTK_STOCK_DIALOG_WARNING, NULL);
4218 g_free(timezone_bin);
4219 g_free(tmp_dir); // The folder in /tmp is deleted in exit_program_final()
4223 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GTK_STOCK_DIALOG_WARNING, NULL);
4225 g_free(tmp_filename);
4226 file_data_unref(fd);
4230 file_util_warning_dialog(_("Error: Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4233 g_file_delete(tz->tmp_g_file, NULL, &error);
4234 g_object_unref(tz->tmp_g_file);
4235 tz->tmp_g_file = NULL;
4236 g_object_unref(tz->cancellable);
4237 g_object_unref(tz->timezone_database_gq);
4240 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
4244 if (!g_cancellable_is_cancelled(tz->cancellable))
4246 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
4250 static void timezone_cancel_button_cb(GenericDialog *gd, gpointer data)
4254 g_cancellable_cancel(tz->cancellable);
4257 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
4260 GError *error = NULL;
4261 GFileIOStream *io_stream;
4268 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
4272 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4273 log_printf("Error: Download timezone database failed:\n%s", error->message);
4274 g_error_free(error);
4275 g_object_unref(tz->tmp_g_file);
4279 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE_WEB);
4281 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
4283 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
4285 tz->progress = gtk_progress_bar_new();
4286 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
4287 gtk_widget_show(tz->progress);
4289 gtk_widget_show(tz->gd->dialog);
4290 tz->cancellable = g_cancellable_new();
4291 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);
4293 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
4296 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */