2 * Copyright (C) 2006 John Ellis
3 * Copyright (C) 2008 - 2016 The Geeqie Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "preferences.h"
26 #include "bar_keywords.h"
28 #include "cache_maint.h"
33 #include "filefilter.h"
34 #include "fullscreen.h"
36 #include "image-overlay.h"
37 #include "color-man.h"
39 #include "layout_config.h"
40 #include "layout_util.h"
44 #include "pixbuf_util.h"
46 #include "slideshow.h"
50 #include "ui_fileops.h"
52 #include "ui_spinner.h"
53 #include "ui_tabcomp.h"
54 #include "ui_utildlg.h"
56 #include "zonedetect.h"
67 #include <gspell/gspell.h>
70 #define EDITOR_NAME_MAX_LENGTH 32
71 #define EDITOR_COMMAND_MAX_LENGTH 1024
73 static void image_overlay_set_text_colours();
75 GtkWidget *keyword_text;
76 static void config_tab_keywords_save();
78 typedef struct _ThumbSize ThumbSize;
85 static ThumbSize thumb_size_list[] =
120 FILETYPES_COLUMN_FILTER = 0,
121 FILETYPES_COLUMN_DESCRIPTION,
122 FILETYPES_COLUMN_CLASS,
123 FILETYPES_COLUMN_WRITABLE,
124 FILETYPES_COLUMN_SIDECAR,
125 FILETYPES_COLUMN_COUNT
128 gchar *format_class_list[] = {
139 /* config memory values */
140 static ConfOptions *c_options = NULL;
147 static GtkWidget *configwindow = NULL;
148 static GtkListStore *filter_store = NULL;
149 static GtkTreeStore *accel_store = NULL;
151 static GtkWidget *safe_delete_path_entry;
153 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
154 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
155 static GtkWidget *color_profile_screen_file_entry;
156 static GtkWidget *external_preview_select_entry;
157 static GtkWidget *external_preview_extract_entry;
159 static GtkWidget *sidecar_ext_entry;
160 static GtkWidget *help_search_engine_entry;
163 #define CONFIG_WINDOW_DEF_WIDTH 700
164 #define CONFIG_WINDOW_DEF_HEIGHT 600
167 *-----------------------------------------------------------------------------
168 * option widget callbacks (private)
169 *-----------------------------------------------------------------------------
172 static void zoom_increment_cb(GtkWidget *spin, gpointer data)
174 c_options->image.zoom_increment = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
177 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer data)
179 gint mins_secs_tenths, delay;
181 mins_secs_tenths = c_options->slideshow.delay %
182 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
184 delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
185 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
188 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
189 SLIDESHOW_SUBSECOND_PRECISION;
192 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer data)
194 gint hours, secs_tenths, delay;
196 hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
197 secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
199 delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
200 (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
201 (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
203 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
204 SLIDESHOW_SUBSECOND_PRECISION;
207 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer data)
209 gint hours_mins, delay;
211 hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
213 delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
214 (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
215 (gdouble)(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
217 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
218 SLIDESHOW_SUBSECOND_PRECISION;
222 *-----------------------------------------------------------------------------
223 * sync program to config window routine (private)
224 *-----------------------------------------------------------------------------
227 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
233 buf = gtk_entry_get_text(GTK_ENTRY(entry));
234 if (buf && strlen(buf) > 0)
239 *option = g_strdup(buf);
244 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
246 gchar *accel_path, *accel;
248 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
250 if (accel_path && accel_path[0])
253 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
254 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
264 static void config_window_apply(void)
266 gboolean refresh = FALSE;
271 config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
273 if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
274 if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
275 if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
276 if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
277 if (options->file_sort.natural != c_options->file_sort.natural) refresh = TRUE;
278 if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
279 if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
281 options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
282 options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
283 options->file_ops.confirm_move_to_trash = c_options->file_ops.confirm_move_to_trash;
284 options->file_ops.use_system_trash = c_options->file_ops.use_system_trash;
285 options->file_ops.no_trash = c_options->file_ops.no_trash;
286 options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
287 options->tools_restore_state = c_options->tools_restore_state;
288 options->save_window_positions = c_options->save_window_positions;
289 options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
290 options->save_window_workspace = c_options->save_window_workspace;
291 options->save_dialog_window_positions = c_options->save_dialog_window_positions;
292 options->show_window_ids = c_options->show_window_ids;
293 options->image.scroll_reset_method = c_options->image.scroll_reset_method;
294 options->image.zoom_2pass = c_options->image.zoom_2pass;
295 options->image.fit_window_to_image = c_options->image.fit_window_to_image;
296 options->image.limit_window_size = c_options->image.limit_window_size;
297 options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
298 options->image.max_window_size = c_options->image.max_window_size;
299 options->image.limit_autofit_size = c_options->image.limit_autofit_size;
300 options->image.max_autofit_size = c_options->image.max_autofit_size;
301 options->image.max_enlargement_size = c_options->image.max_enlargement_size;
302 options->image.use_clutter_renderer = c_options->image.use_clutter_renderer;
303 options->image.tile_size = c_options->image.tile_size;
304 options->progressive_key_scrolling = c_options->progressive_key_scrolling;
305 options->keyboard_scroll_step = c_options->keyboard_scroll_step;
307 if (options->thumbnails.max_width != c_options->thumbnails.max_width
308 || options->thumbnails.max_height != c_options->thumbnails.max_height
309 || options->thumbnails.quality != c_options->thumbnails.quality)
311 thumb_format_changed = TRUE;
313 options->thumbnails.max_width = c_options->thumbnails.max_width;
314 options->thumbnails.max_height = c_options->thumbnails.max_height;
315 options->thumbnails.quality = c_options->thumbnails.quality;
317 options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
318 options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
319 options->thumbnails.use_exif = c_options->thumbnails.use_exif;
320 options->thumbnails.use_color_management = c_options->thumbnails.use_color_management;
321 options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
322 options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
323 // options->thumbnails.use_ft_metadata_small = c_options->thumbnails.use_ft_metadata_small;
324 options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
325 options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
326 options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
327 options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
328 options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
329 options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
331 options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
332 options->file_sort.natural = c_options->file_sort.natural;
333 options->file_filter.disable = c_options->file_filter.disable;
335 config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, NULL);
336 sidecar_ext_parse(options->sidecar.ext);
338 options->slideshow.random = c_options->slideshow.random;
339 options->slideshow.repeat = c_options->slideshow.repeat;
340 options->slideshow.delay = c_options->slideshow.delay;
342 options->mousewheel_scrolls = c_options->mousewheel_scrolls;
343 options->image_lm_click_nav = c_options->image_lm_click_nav;
344 options->image_l_click_archive = c_options->image_l_click_archive;
345 options->image_l_click_video = c_options->image_l_click_video;
346 options->image_l_click_video_editor = c_options->image_l_click_video_editor;
348 options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
350 options->image.tile_cache_max = c_options->image.tile_cache_max;
351 options->image.image_cache_max = c_options->image.image_cache_max;
353 options->image.zoom_quality = c_options->image.zoom_quality;
355 options->image.zoom_increment = c_options->image.zoom_increment;
357 options->image.zoom_style = c_options->image.zoom_style;
359 options->image.enable_read_ahead = c_options->image.enable_read_ahead;
362 if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
363 || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
364 || !gdk_color_equal(&options->image.border_color, &c_options->image.border_color))
366 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
367 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
368 options->image.border_color = c_options->image.border_color;
369 layout_colors_update();
370 view_window_colors_update();
373 options->image.alpha_color_1 = c_options->image.alpha_color_1;
374 options->image.alpha_color_2 = c_options->image.alpha_color_2;
376 options->fullscreen.screen = c_options->fullscreen.screen;
377 options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
378 options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
379 options->fullscreen.above = c_options->fullscreen.above;
380 if (c_options->image_overlay.template_string)
381 set_image_overlay_template_string(&options->image_overlay.template_string,
382 c_options->image_overlay.template_string);
383 if (c_options->image_overlay.font)
384 set_image_overlay_font_string(&options->image_overlay.font,
385 c_options->image_overlay.font);
386 options->image_overlay.text_red = c_options->image_overlay.text_red;
387 options->image_overlay.text_green = c_options->image_overlay.text_green;
388 options->image_overlay.text_blue = c_options->image_overlay.text_blue;
389 options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
390 options->image_overlay.background_red = c_options->image_overlay.background_red;
391 options->image_overlay.background_green = c_options->image_overlay.background_green;
392 options->image_overlay.background_blue = c_options->image_overlay.background_blue;
393 options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
394 options->update_on_time_change = c_options->update_on_time_change;
396 options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
397 options->rot_invariant_sim = c_options->rot_invariant_sim;
399 options->tree_descend_subdirs = c_options->tree_descend_subdirs;
401 options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
402 options->circular_selection_lists = c_options->circular_selection_lists;
404 options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
405 options->dnd_icon_size = c_options->dnd_icon_size;
406 options->clipboard_selection = c_options->clipboard_selection;
407 options->dnd_default_action = c_options->dnd_default_action;
409 options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
410 options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
411 options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
412 options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
413 options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
414 options->metadata.confirm_write = c_options->metadata.confirm_write;
415 options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
416 options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
417 options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
418 options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
419 options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
420 options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
421 options->metadata.write_orientation = c_options->metadata.write_orientation;
422 options->metadata.check_spelling = c_options->metadata.check_spelling;
423 options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
424 (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
425 (c_options->stereo.tmp.flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
426 (c_options->stereo.tmp.mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
427 (c_options->stereo.tmp.flip_left ? PR_STEREO_FLIP_LEFT : 0) |
428 (c_options->stereo.tmp.swap ? PR_STEREO_SWAP : 0) |
429 (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
430 options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
431 (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
432 (c_options->stereo.tmp.fs_flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
433 (c_options->stereo.tmp.fs_mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
434 (c_options->stereo.tmp.fs_flip_left ? PR_STEREO_FLIP_LEFT : 0) |
435 (c_options->stereo.tmp.fs_swap ? PR_STEREO_SWAP : 0) |
436 (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
437 options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
438 options->stereo.fixed_w = c_options->stereo.fixed_w;
439 options->stereo.fixed_h = c_options->stereo.fixed_h;
440 options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
441 options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
442 options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
443 options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
445 options->info_keywords.height = c_options->info_keywords.height;
446 options->info_title.height = c_options->info_title.height;
447 options->info_comment.height = c_options->info_comment.height;
448 options->info_rating.height = c_options->info_rating.height;
450 options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
451 options->expand_menu_toolbar = c_options->expand_menu_toolbar;
453 options->marks_save = c_options->marks_save;
454 options->with_rename = c_options->with_rename;
455 options->collections_on_top = c_options->collections_on_top;
456 options->hide_window_in_fullscreen = c_options->hide_window_in_fullscreen;
457 config_entry_to_option(help_search_engine_entry, &options->help_search_engine, NULL);
459 options->external_preview.enable = c_options->external_preview.enable;
460 config_entry_to_option(external_preview_select_entry, &options->external_preview.select, NULL);
461 config_entry_to_option(external_preview_extract_entry, &options->external_preview.extract, NULL);
463 options->read_metadata_in_idle = c_options->read_metadata_in_idle;
465 options->star_rating.star = c_options->star_rating.star;
466 options->star_rating.rejected = c_options->star_rating.rejected;
468 options->threads.duplicates = c_options->threads.duplicates > 0 ? c_options->threads.duplicates : -1;
471 set_debug_level(debug_c);
475 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
477 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
478 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
480 config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
481 options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
482 if (options->color_profile.render_intent != c_options->color_profile.render_intent)
484 options->color_profile.render_intent = c_options->color_profile.render_intent;
489 options->mouse_button_8 = c_options->mouse_button_8;
490 options->mouse_button_9 = c_options->mouse_button_9;
492 options->override_disable_gpu = c_options->override_disable_gpu;
494 config_tab_keywords_save();
496 image_options_sync();
501 layout_refresh(NULL);
504 if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, NULL);
506 toolbar_apply(TOOLBAR_MAIN);
507 toolbar_apply(TOOLBAR_STATUS);
511 *-----------------------------------------------------------------------------
512 * config window main button callbacks (private)
513 *-----------------------------------------------------------------------------
516 static void config_window_close_cb(GtkWidget *widget, gpointer data)
518 gtk_widget_destroy(configwindow);
523 static void config_window_help_cb(GtkWidget *widget, gpointer data)
525 GtkWidget *notebook = data;
528 static gchar *html_section[] =
530 "GuideOptionsGeneral.html",
531 "GuideOptionsImage.html",
532 "GuideOptionsOSD.html",
533 "GuideOptionsWindow.html",
534 "GuideOptionsKeyboard.html",
535 "GuideOptionsFiltering.html",
536 "GuideOptionsMetadata.html",
537 "GuideOptionsKeywords.html",
538 "GuideOptionsColor.html",
539 "GuideOptionsStereo.html",
540 "GuideOptionsBehavior.html",
541 "GuideOptionsToolbar.html",
542 "GuideOptionsToolbar.html",
543 "GuideOptionsAdvanced.html"
546 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
547 help_window_show(html_section[i]);
550 static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpointer data)
552 config_window_close_cb(NULL, NULL);
556 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
559 GtkNotebook *notebook = data;
567 lw = layout_window_list->data;
569 window = gtk_widget_get_window(widget);
570 gdk_window_get_root_origin(window, &x, &y);
571 w = gdk_window_get_width(window);
572 h = gdk_window_get_height(window);
573 page_number = gtk_notebook_get_current_page(notebook);
575 lw->options.preferences_window.x = x;
576 lw->options.preferences_window.y = y;
577 lw->options.preferences_window.w = w;
578 lw->options.preferences_window.h = h;
579 lw->options.preferences_window.page_number = page_number;
581 config_window_apply();
582 layout_util_sync(lw);
583 save_options(options);
584 config_window_close_cb(NULL, NULL);
588 *-----------------------------------------------------------------------------
589 * config window setup (private)
590 *-----------------------------------------------------------------------------
593 static void quality_menu_cb(GtkWidget *combo, gpointer data)
597 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
601 *option = GDK_INTERP_NEAREST;
604 *option = GDK_INTERP_TILES;
607 *option = GDK_INTERP_BILINEAR;
612 static void dnd_default_action_selection_menu_cb(GtkWidget *combo, gpointer data)
616 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
620 *option = DND_ACTION_ASK;
623 *option = DND_ACTION_COPY;
626 *option = DND_ACTION_MOVE;
630 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
634 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
637 *option = CLIPBOARD_PRIMARY;
640 *option = CLIPBOARD_CLIPBOARD;
643 *option = CLIPBOARD_BOTH;
646 *option = CLIPBOARD_BOTH;
650 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
651 guint option, guint *option_c)
658 pref_table_label(table, column, row, text, 0.0);
660 combo = gtk_combo_box_text_new();
662 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
663 if (option == GDK_INTERP_NEAREST) current = 0;
664 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
665 if (option == GDK_INTERP_TILES) current = 1;
666 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear (best, but slowest)"));
667 if (option == GDK_INTERP_BILINEAR) current = 2;
669 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
671 g_signal_connect(G_OBJECT(combo), "changed",
672 G_CALLBACK(quality_menu_cb), option_c);
674 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
675 gtk_widget_show(combo);
678 static void add_dnd_default_action_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, DnDAction option, DnDAction *option_c)
685 pref_table_label(table, column, row, text, 0.0);
687 combo = gtk_combo_box_text_new();
689 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Ask"));
690 if (option == DND_ACTION_ASK) current = 0;
691 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Copy"));
692 if (option == DND_ACTION_COPY) current = 1;
693 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Move"));
694 if (option == DND_ACTION_MOVE) current = 2;
696 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
698 g_signal_connect(G_OBJECT(combo), "changed",
699 G_CALLBACK(dnd_default_action_selection_menu_cb), option_c);
701 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
702 gtk_widget_show(combo);
705 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
706 gint option, gint *option_c)
713 pref_table_label(table, column, row, text, 0.0);
715 combo = gtk_combo_box_text_new();
717 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Primary"));
718 if (option == CLIPBOARD_PRIMARY) current = 0;
719 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Clipboard"));
720 if (option == CLIPBOARD_CLIPBOARD) current = 1;
721 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Both"));
722 if (option == CLIPBOARD_BOTH) current = 2;
724 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
726 g_signal_connect(G_OBJECT(combo), "changed",
727 G_CALLBACK(clipboard_selection_menu_cb), option_c);
729 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
730 gtk_widget_show(combo);
733 static void zoom_style_selection_menu_cb(GtkWidget *combo, gpointer data)
737 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
740 *option = ZOOM_GEOMETRIC;
743 *option = ZOOM_ARITHMETIC;
746 *option = ZOOM_GEOMETRIC;
750 static void add_zoom_style_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, ZoomStyle option, ZoomStyle *option_c)
757 pref_table_label(table, column, row, text, 0.0);
759 combo = gtk_combo_box_text_new();
761 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Geometric"));
762 if (option == ZOOM_GEOMETRIC) current = 0;
763 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Arithmetic"));
764 if (option == ZOOM_ARITHMETIC) current = 1;
766 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
768 g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(zoom_style_selection_menu_cb), option_c);
770 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
771 gtk_widget_show(combo);
774 typedef struct _UseableMouseItems UseableMouseItems;
775 struct _UseableMouseItems
777 gchar *name; /* GtkActionEntry terminology */
782 static const UseableMouseItems useable_mouse_items[] = {
784 {"FirstImage", N_("First Image"), GTK_STOCK_GOTO_TOP},
785 {"PrevImage", N_("Previous Image"), GTK_STOCK_GO_UP},
786 {"NextImage", N_("Next Image"), GTK_STOCK_GO_DOWN},
787 {"LastImage", N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
788 {"Back", N_("Back"), GTK_STOCK_GO_BACK},
789 {"Forward", N_("Forward"), GTK_STOCK_GO_FORWARD},
790 {"Home", N_("Home"), GTK_STOCK_HOME},
791 {"Up", N_("Up"), GTK_STOCK_GO_UP},
792 {"FirstPage", N_("First page"), GTK_STOCK_MEDIA_PREVIOUS},
793 {"LastPage", N_("Last Page"), GTK_STOCK_MEDIA_NEXT},
794 {"NextPage", N_("Next page"), GTK_STOCK_MEDIA_FORWARD},
795 {"PrevPage", N_("Previous Page"), GTK_STOCK_MEDIA_REWIND},
796 {"NewWindow", N_("New _window"), GTK_STOCK_NEW},
797 {"NewCollection", N_("New collection"), GTK_STOCK_INDEX},
798 {"OpenCollection", N_("Open collection"), GTK_STOCK_OPEN},
799 {"Search", N_("Search"), GTK_STOCK_FIND},
800 {"FindDupes", N_("Find duplicates"), GTK_STOCK_FIND},
801 {"NewFolder", N_("New folder"),GTK_STOCK_DIRECTORY},
802 {"Copy", N_("Copy"), GTK_STOCK_COPY},
803 {"Move", N_("Move"), PIXBUF_INLINE_ICON_MOVE},
804 {"Rename", N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
805 {"Delete", N_("Delete"), GTK_STOCK_DELETE},
806 {"CloseWindow", N_("Close Window"), GTK_STOCK_CLOSE},
807 {"PanView", N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
808 {"SelectAll", N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
809 {"SelectNone", N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
810 {"SelectInvert", N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
811 {"ShowFileFilter", N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
812 {"RectangularSelection", N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
813 {"Print", N_("Print"), GTK_STOCK_PRINT},
814 {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
815 {"LayoutConfig", N_("Configure this window"), GTK_STOCK_PREFERENCES},
816 {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
817 {"RotateCW", N_("Rotate clockwise 90°"), PIXBUF_INLINE_ICON_CW},
818 {"RotateCCW", N_("Rotate counterclockwise 90°"), PIXBUF_INLINE_ICON_CCW},
819 {"Rotate180", N_("Rotate 180°"), PIXBUF_INLINE_ICON_180},
820 {"Mirror", N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
821 {"Flip", N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
822 {"AlterNone", N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
823 {"ZoomIn", N_("Zoom in"), GTK_STOCK_ZOOM_IN},
824 {"ZoomOut", N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
825 {"Zoom100", N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
826 {"ZoomFit", N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
827 {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
828 {"ZoomFillVert", N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
829 {"Zoom200", N_("Zoom 2:1"), GTK_STOCK_FILE},
830 {"Zoom300", N_("Zoom 3:1"), GTK_STOCK_FILE},
831 {"Zoom400", N_("Zoom 4:1"), GTK_STOCK_FILE},
832 {"Zoom50", N_("Zoom 1:2"), GTK_STOCK_FILE},
833 {"Zoom33", N_("Zoom1:3"), GTK_STOCK_FILE},
834 {"Zoom25", N_("Zoom 1:4"), GTK_STOCK_FILE},
835 {"ConnectZoomIn", N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
836 {"SplitPaneSync", N_("Split Pane Sync"), PIXBUF_INLINE_SPLIT_PANE_SYNC},
837 {"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
838 {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
839 {"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
840 {"SlideShowPause", N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
841 {"SlideShowFaster", N_("Slideshow Faster"), GTK_STOCK_FILE},
842 {"SlideShowSlower", N_("Slideshow Slower"), GTK_STOCK_FILE},
843 {"Refresh", N_("Refresh"), GTK_STOCK_REFRESH},
844 {"HelpContents", N_("Help"), GTK_STOCK_HELP},
845 {"ExifWin", N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
846 {"Thumbnails", N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
847 {"ShowMarks", N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
848 {"DrawRectangle", N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
849 {"FloatTools", N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
850 {"SBar", N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
851 {"SBarSort", N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
852 {"Quit", N_("Quit"), GTK_STOCK_QUIT},
856 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
858 gchar **option = data;
861 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
863 const UseableMouseItems *list = useable_mouse_items;
867 if (g_strcmp0(list->label, label) == 0)
875 *option = g_strdup(list->name);
879 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
880 gchar *option, gchar **option_c)
888 pref_table_label(table, column, row, text, 0.0);
890 combo = gtk_combo_box_text_new();
892 const UseableMouseItems *list = useable_mouse_items;
896 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
897 if (g_strcmp0(list->name, option) == 0)
905 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
907 g_signal_connect(G_OBJECT(combo), "changed",
908 G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
910 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
911 gtk_widget_show(combo);
914 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
918 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
921 if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
923 c_options->thumbnails.max_width = thumb_size_list[n].w;
924 c_options->thumbnails.max_height = thumb_size_list[n].h;
928 c_options->thumbnails.max_width = options->thumbnails.max_width;
929 c_options->thumbnails.max_height = options->thumbnails.max_height;
933 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
939 c_options->thumbnails.max_width = options->thumbnails.max_width;
940 c_options->thumbnails.max_height = options->thumbnails.max_height;
942 pref_table_label(table, column, row, text, 0.0);
944 combo = gtk_combo_box_text_new();
947 for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
952 w = thumb_size_list[i].w;
953 h = thumb_size_list[i].h;
955 buf = g_strdup_printf("%d x %d", w, h);
956 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
959 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
966 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
967 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
973 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
974 g_signal_connect(G_OBJECT(combo), "changed",
975 G_CALLBACK(thumb_size_menu_cb), NULL);
977 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
978 gtk_widget_show(combo);
981 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
985 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
989 *option = PR_STEREO_NONE;
992 *option = PR_STEREO_ANAGLYPH_RC;
995 *option = PR_STEREO_ANAGLYPH_GM;
998 *option = PR_STEREO_ANAGLYPH_YB;
1001 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
1004 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
1007 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
1010 *option = PR_STEREO_ANAGLYPH_DB_RC;
1013 *option = PR_STEREO_ANAGLYPH_DB_GM;
1016 *option = PR_STEREO_ANAGLYPH_DB_YB;
1019 *option = PR_STEREO_HORIZ;
1022 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
1025 *option = PR_STEREO_VERT;
1028 *option = PR_STEREO_VERT | PR_STEREO_HALF;
1031 *option = PR_STEREO_FIXED;
1036 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1037 gint option, gint *option_c, gboolean add_fixed)
1044 pref_table_label(table, column, row, text, 0.0);
1046 combo = gtk_combo_box_text_new();
1048 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
1050 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
1051 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
1052 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
1053 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
1054 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
1055 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
1056 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
1057 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
1058 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
1059 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
1060 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
1061 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
1062 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
1063 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
1064 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
1065 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
1066 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
1067 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
1069 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
1070 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
1071 if (option & PR_STEREO_HORIZ)
1074 if (option & PR_STEREO_HALF) current = 11;
1077 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
1078 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
1079 if (option & PR_STEREO_VERT)
1082 if (option & PR_STEREO_HALF) current = 13;
1087 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
1088 if (option & PR_STEREO_FIXED) current = 14;
1091 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1093 g_signal_connect(G_OBJECT(combo), "changed",
1094 G_CALLBACK(stereo_mode_menu_cb), option_c);
1096 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1097 gtk_widget_show(combo);
1100 static void video_menu_cb(GtkWidget *combo, gpointer data)
1102 gchar **option = data;
1104 EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
1108 static void video_menu_populate(gpointer data, gpointer user_data)
1110 GtkWidget *combo = user_data;
1111 EditorDescription *ed = data;
1113 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1116 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1117 gchar *option, gchar **option_c)
1121 /* use lists since they are sorted */
1122 GList *eds = editor_list_get();
1126 pref_table_label(table, column, row, text, 0.0);
1128 combo = gtk_combo_box_text_new();
1129 g_list_foreach(eds,video_menu_populate,(gpointer)combo);
1130 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1132 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1134 g_signal_connect(G_OBJECT(combo), "changed",
1135 G_CALLBACK(video_menu_cb), option_c);
1137 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1138 gtk_widget_show(combo);
1141 static void filter_store_populate(void)
1145 if (!filter_store) return;
1147 gtk_list_store_clear(filter_store);
1149 work = filter_get_list();
1158 gtk_list_store_append(filter_store, &iter);
1159 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1163 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1164 gchar *new_text, gpointer data)
1166 GtkWidget *model = data;
1167 FilterEntry *fe = data;
1171 if (!new_text || strlen(new_text) < 1) return;
1173 tpath = gtk_tree_path_new_from_string(path_str);
1174 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1175 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1177 g_free(fe->extensions);
1178 fe->extensions = g_strdup(new_text);
1180 gtk_tree_path_free(tpath);
1184 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1185 gchar *new_text, gpointer data)
1187 GtkWidget *model = data;
1188 FilterEntry *fe = data;
1193 if (!new_text || !new_text[0]) return;
1195 tpath = gtk_tree_path_new_from_string(path_str);
1196 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1197 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1199 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1201 if (strcmp(new_text, _(format_class_list[i])) == 0)
1208 gtk_tree_path_free(tpath);
1212 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1213 gchar *new_text, gpointer data)
1215 GtkWidget *model = data;
1220 if (!new_text || !new_text[0]) return;
1222 tpath = gtk_tree_path_new_from_string(path_str);
1223 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1224 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1226 g_free(fe->description);
1227 fe->description = g_strdup(new_text);
1229 gtk_tree_path_free(tpath);
1232 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
1233 gchar *path_str, gpointer data)
1235 GtkWidget *model = data;
1240 tpath = gtk_tree_path_new_from_string(path_str);
1241 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1242 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1244 fe->enabled = !fe->enabled;
1246 gtk_tree_path_free(tpath);
1250 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
1251 gchar *path_str, gpointer data)
1253 GtkWidget *model = data;
1258 tpath = gtk_tree_path_new_from_string(path_str);
1259 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1260 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1262 fe->writable = !fe->writable;
1263 if (fe->writable) fe->allow_sidecar = FALSE;
1265 gtk_tree_path_free(tpath);
1269 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
1270 gchar *path_str, gpointer data)
1272 GtkWidget *model = data;
1277 tpath = gtk_tree_path_new_from_string(path_str);
1278 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1279 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1281 fe->allow_sidecar = !fe->allow_sidecar;
1282 if (fe->allow_sidecar) fe->writable = FALSE;
1284 gtk_tree_path_free(tpath);
1288 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1289 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1293 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1295 switch (GPOINTER_TO_INT(data))
1298 g_object_set(GTK_CELL_RENDERER(cell),
1299 "active", fe->enabled, NULL);
1302 g_object_set(GTK_CELL_RENDERER(cell),
1303 "text", fe->extensions, NULL);
1305 case FE_DESCRIPTION:
1306 g_object_set(GTK_CELL_RENDERER(cell),
1307 "text", fe->description, NULL);
1310 g_object_set(GTK_CELL_RENDERER(cell),
1311 "text", _(format_class_list[fe->file_class]), NULL);
1314 g_object_set(GTK_CELL_RENDERER(cell),
1315 "active", fe->writable, NULL);
1317 case FE_ALLOW_SIDECAR:
1318 g_object_set(GTK_CELL_RENDERER(cell),
1319 "active", fe->allow_sidecar, NULL);
1324 static gboolean filter_add_scroll(gpointer data)
1328 GtkCellRenderer *cell;
1329 GtkTreeViewColumn *column;
1332 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1333 path = gtk_tree_path_new_from_indices(rows-1, -1);
1335 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1337 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1338 cell = g_list_last(list_cells)->data;
1340 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1341 path, column, FALSE, 0.0, 0.0 );
1342 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1343 path, column, cell, TRUE);
1345 gtk_tree_path_free(path);
1346 g_list_free(list_cells);
1351 static void filter_add_cb(GtkWidget *widget, gpointer data)
1353 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1354 filter_store_populate();
1356 g_idle_add((GSourceFunc)filter_add_scroll, data);
1359 static void filter_remove_cb(GtkWidget *widget, gpointer data)
1361 GtkWidget *filter_view = data;
1362 GtkTreeSelection *selection;
1366 if (!filter_store) return;
1367 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1368 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1369 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1372 filter_remove_entry(fe);
1374 filter_store_populate();
1377 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1381 GtkTreeViewColumn *column;
1383 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1384 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1385 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1387 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1391 gtk_tree_path_free(path);
1396 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
1399 filter_add_defaults();
1401 filter_store_populate();
1403 g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1406 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1408 /* no op, only so cancel button appears */
1411 static void filter_default_cb(GtkWidget *widget, gpointer data)
1415 gd = generic_dialog_new(_("Reset filters"),
1416 "reset_filter", widget, TRUE,
1417 dummy_cancel_cb, data);
1418 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1419 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1420 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1421 gtk_widget_show(gd->dialog);
1424 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1426 GtkWidget *frame = data;
1428 gtk_widget_set_sensitive(frame,
1429 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1432 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
1434 layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1437 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
1439 file_util_trash_clear();
1442 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
1446 gd = generic_dialog_new(_("Clear trash"),
1447 "clear_trash", widget, TRUE,
1448 dummy_cancel_cb, NULL);
1449 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1450 _("This will remove the trash contents."), FALSE);
1451 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1452 entry = gtk_entry_new();
1453 gtk_widget_set_can_focus(entry, FALSE);
1454 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1455 if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1456 gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1457 gtk_widget_show(entry);
1458 gtk_widget_show(gd->dialog);
1461 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
1463 GtkWidget *pTextView;
1464 GtkTextBuffer *pTextBuffer;
1468 pTextView = GTK_WIDGET(data);
1470 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1471 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1472 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1474 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1475 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1478 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
1480 GtkTextView *text_view = data;
1481 GtkTextBuffer *buffer;
1483 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1484 if (!configwindow) return;
1486 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1487 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1490 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1494 gd = generic_dialog_new(_("Reset image overlay template string"),
1495 "reset_image_overlay_template_string", widget, TRUE,
1496 dummy_cancel_cb, data);
1497 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1498 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1499 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1500 gtk_widget_show(gd->dialog);
1503 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
1505 help_window_show("GuideOptionsOSD.html");
1508 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer data)
1510 #if GTK_CHECK_VERSION(3,4,0)
1513 PangoFontDescription *font_desc;
1515 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1516 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1518 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1520 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1521 font = pango_font_description_to_string(font_desc);
1522 g_free(c_options->image_overlay.font);
1523 c_options->image_overlay.font = g_strdup(font);
1527 gtk_widget_destroy(dialog);
1531 font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
1532 c_options->image_overlay.font = g_strdup(font);
1536 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer data)
1539 #if GTK_CHECK_VERSION(3,4,0)
1542 dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1543 colour.red = options->image_overlay.text_red;
1544 colour.green = options->image_overlay.text_green;
1545 colour.blue = options->image_overlay.text_blue;
1546 colour.alpha = options->image_overlay.text_alpha;
1547 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1548 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1550 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1552 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1553 c_options->image_overlay.text_red = colour.red*255;
1554 c_options->image_overlay.text_green = colour.green*255;
1555 c_options->image_overlay.text_blue = colour.blue*255;
1556 c_options->image_overlay.text_alpha = colour.alpha*255;
1558 gtk_widget_destroy(dialog);
1561 GtkColorSelection *colorsel;
1563 dialog = gtk_color_selection_dialog_new("Image Overlay Text Colour");
1564 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1565 colour.red = options->image_overlay.text_red*257;
1566 colour.green = options->image_overlay.text_green*257;
1567 colour.blue = options->image_overlay.text_blue*257;
1568 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1569 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1570 gtk_color_selection_set_current_color(colorsel, &colour);
1571 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.text_alpha*257);
1573 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1575 gtk_color_selection_get_current_color(colorsel, &colour);
1576 c_options->image_overlay.text_red = colour.red/257;
1577 c_options->image_overlay.text_green = colour.green/257;
1578 c_options->image_overlay.text_blue = colour.blue/257;
1579 c_options->image_overlay.text_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1581 gtk_widget_destroy (dialog);
1586 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer data)
1589 #if GTK_CHECK_VERSION(3,4,0)
1592 dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1593 colour.red = options->image_overlay.background_red;
1594 colour.green = options->image_overlay.background_green;
1595 colour.blue = options->image_overlay.background_blue;
1596 colour.alpha = options->image_overlay.background_alpha;
1597 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1598 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1600 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1602 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1603 c_options->image_overlay.background_red = colour.red*255;
1604 c_options->image_overlay.background_green = colour.green*255;
1605 c_options->image_overlay.background_blue = colour.blue*255;
1606 c_options->image_overlay.background_alpha = colour.alpha*255;
1608 gtk_widget_destroy(dialog);
1611 GtkColorSelection *colorsel;
1613 dialog = gtk_color_selection_dialog_new("Image Overlay Background Colour");
1614 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1615 colour.red = options->image_overlay.background_red*257;
1616 colour.green = options->image_overlay.background_green*257;
1617 colour.blue = options->image_overlay.background_blue*257;
1618 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1619 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1620 gtk_color_selection_set_current_color(colorsel, &colour);
1621 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.background_alpha*257);
1623 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1625 gtk_color_selection_get_current_color(colorsel, &colour);
1626 c_options->image_overlay.background_red = colour.red/257;
1627 c_options->image_overlay.background_green = colour.green/257;
1628 c_options->image_overlay.background_blue = colour.blue/257;
1629 c_options->image_overlay.background_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1631 gtk_widget_destroy(dialog);
1635 static void accel_store_populate(void)
1638 GList *groups, *actions;
1640 const gchar *accel_path;
1644 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1646 gtk_tree_store_clear(accel_store);
1647 lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
1649 g_assert(lw && lw->ui_manager);
1650 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1653 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1656 action = GTK_ACTION(actions->data);
1657 accel_path = gtk_action_get_accel_path(action);
1658 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1660 gchar *label, *label2, *tooltip, *accel;
1661 g_object_get(action,
1662 "tooltip", &tooltip,
1666 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1672 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1676 gtk_tree_store_append(accel_store, &iter, NULL);
1677 gtk_tree_store_set(accel_store, &iter,
1680 AE_TOOLTIP, tooltip ? tooltip : "",
1681 AE_ACCEL, accel_path,
1689 actions = actions->next;
1692 groups = groups->next;
1696 static void accel_store_cleared_cb(GtkCellRendererAccel *accel, gchar *path_string, gpointer user_data)
1701 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1703 gchar *accel1 = data;
1708 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1710 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1711 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1713 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1715 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1716 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1725 static void accel_store_edited_cb(GtkCellRendererAccel *accel, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode, gpointer user_data)
1727 GtkTreeModel *model = (GtkTreeModel *)accel_store;
1731 GtkAccelKey old_key, key;
1732 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1734 gtk_tree_model_get_iter(model, &iter, path);
1735 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1737 /* test if the accelerator can be stored without conflicts*/
1738 gtk_accel_map_lookup_entry(accel_path, &old_key);
1740 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1741 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1742 gtk_accel_map_lookup_entry(accel_path, &key);
1744 /* restore the original for now, the key will be really changed when the changes are confirmed */
1745 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1747 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1748 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1750 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1751 gtk_tree_path_free(path);
1755 static gboolean accel_default_scroll(GtkTreeView *data)
1759 GtkTreeViewColumn *column;
1761 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1762 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1763 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1765 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1769 gtk_tree_path_free(path);
1774 static void accel_default_cb(GtkWidget *widget, gpointer data)
1776 accel_store_populate();
1778 g_idle_add((GSourceFunc)accel_default_scroll, data);
1781 void accel_remove_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1783 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1786 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1789 gchar *accel_path, *accel;
1791 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1792 gtk_accel_map_lookup_entry(accel_path, &key);
1793 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1795 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1797 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1802 static void accel_reset_cb(GtkWidget *widget, gpointer data)
1804 GtkTreeSelection *selection;
1806 if (!accel_store) return;
1807 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1808 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1813 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1817 GtkWidget *scrolled;
1818 GtkWidget *viewport;
1820 scrolled = gtk_scrolled_window_new(NULL, NULL);
1821 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1822 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1823 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1824 label = gtk_label_new(title);
1825 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1826 gtk_widget_show(scrolled);
1828 viewport = gtk_viewport_new(NULL, NULL);
1829 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1830 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1831 gtk_widget_show(viewport);
1833 vbox = gtk_vbox_new(FALSE, 0);
1834 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1835 gtk_widget_show(vbox);
1840 static void cache_standard_cb(GtkWidget *widget, gpointer data)
1842 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1844 c_options->thumbnails.spec_standard =TRUE;
1845 c_options->thumbnails.cache_into_dirs = FALSE;
1849 static void cache_geeqie_cb(GtkWidget *widget, gpointer data)
1851 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1853 c_options->thumbnails.spec_standard =FALSE;
1854 c_options->thumbnails.cache_into_dirs = FALSE;
1858 static void cache_local_cb(GtkWidget *widget, gpointer data)
1860 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1862 c_options->thumbnails.cache_into_dirs = TRUE;
1863 c_options->thumbnails.spec_standard =FALSE;
1867 static void help_search_engine_entry_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1868 GdkEvent *event, gpointer userdata)
1870 if (pos == GTK_ENTRY_ICON_PRIMARY)
1872 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1876 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1880 static void star_rating_star_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1881 GdkEvent *event, gpointer userdata)
1883 gchar *rating_symbol;
1885 if (pos == GTK_ENTRY_ICON_PRIMARY)
1887 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1888 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1889 g_free(rating_symbol);
1893 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1894 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1895 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1899 static void star_rating_rejected_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1900 GdkEvent *event, gpointer userdata)
1902 gchar *rating_symbol;
1904 if (pos == GTK_ENTRY_ICON_PRIMARY)
1906 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1907 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1908 g_free(rating_symbol);
1912 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1913 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1914 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1918 static guint star_rating_symbol_test(GtkWidget *widget, gpointer data)
1920 GtkContainer *hbox = data;
1921 GString *str = g_string_new(NULL);
1922 GtkEntry *hex_code_entry;
1923 gchar *hex_code_full;
1926 guint64 hex_value = 0;
1928 list = gtk_container_get_children(hbox);
1930 hex_code_entry = g_list_nth_data(list, 2);
1931 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1933 hex_code = g_strsplit(hex_code_full, "+", 2);
1934 if (hex_code[0] && hex_code[1])
1936 hex_value = strtoull(hex_code[1], NULL, 16);
1938 if (!hex_value || hex_value > 0x10FFFF)
1940 hex_value = 0x003F; // Unicode 'Question Mark'
1942 str = g_string_append_unichar(str, (gunichar)hex_value);
1943 gtk_label_set_text(g_list_nth_data(list, 1), str->str);
1945 g_strfreev(hex_code);
1946 g_string_free(str, TRUE);
1947 g_free(hex_code_full);
1952 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1954 guint64 star_symbol;
1956 star_symbol = star_rating_symbol_test(widget, data);
1957 c_options->star_rating.star = star_symbol;
1960 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1962 guint64 rejected_symbol;
1964 rejected_symbol = star_rating_symbol_test(widget, data);
1965 c_options->star_rating.rejected = rejected_symbol;
1968 /* general options tab */
1969 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1970 typedef struct _TZData TZData;
1974 GCancellable *cancellable;
1976 GtkWidget *progress;
1978 GFile *timezone_database_gq;
1979 gchar *timezone_database_user;
1982 static void config_tab_general(GtkWidget *notebook)
1987 GtkWidget *group_frame;
1988 GtkWidget *subgroup;
1990 GtkWidget *ct_button;
1993 gint hours, minutes, remainder;
1995 GtkWidget *star_rating_entry;
1997 gchar *rating_symbol;
2000 gchar *download_locn;
2001 GNetworkMonitor *net_mon;
2002 GSocketConnectable *tz_org;
2003 gboolean internet_available = FALSE;
2006 vbox = scrolled_notebook_page(notebook, _("General"));
2008 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
2010 table = pref_table_new(group, 2, 2, FALSE, FALSE);
2011 add_thumb_size_menu(table, 0, 0, _("Size:"));
2012 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
2014 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2015 pref_label_new(hbox, _("Custom size: "));
2016 pref_spin_new_int(hbox, _("Width:"), NULL, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
2017 pref_spin_new_int(hbox, _("Height:"), NULL, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
2019 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
2020 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
2022 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2023 pref_checkbox_link_sensitivity(ct_button, subgroup);
2025 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
2026 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
2027 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
2028 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2029 button = pref_radiobutton_new(group_frame, NULL, get_thumbnails_cache_dir(),
2030 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2031 G_CALLBACK(cache_geeqie_cb), NULL);
2033 group_frame = pref_frame_new(subgroup, TRUE,
2034 _("Store thumbnails local to image folder (non-standard)"),
2035 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2036 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
2037 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
2038 G_CALLBACK(cache_local_cb), NULL);
2040 group_frame = pref_frame_new(subgroup, TRUE,
2041 _("Use standard thumbnail style and cache, shared with other applications"),
2042 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2043 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
2044 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
2045 G_CALLBACK(cache_standard_cb), NULL);
2047 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
2048 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
2050 pref_checkbox_new_int(group, _("Thumbnail color management"),
2051 options->thumbnails.use_color_management, &c_options->thumbnails.use_color_management);
2053 spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
2055 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
2056 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
2058 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
2059 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
2060 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
2062 // pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
2063 // options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
2066 pref_spacer(group, PREF_PAD_GROUP);
2068 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
2070 c_options->star_rating.star = options->star_rating.star;
2071 c_options->star_rating.rejected = options->star_rating.rejected;
2073 str = g_string_new(NULL);
2074 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2075 pref_label_new(hbox, _("Star character: "));
2076 str = g_string_append_unichar(str, options->star_rating.star);
2077 pref_label_new(hbox, g_strdup(str->str));
2078 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
2079 star_rating_entry = gtk_entry_new();
2080 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2081 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2082 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2083 gtk_widget_show(star_rating_entry);
2084 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2085 G_CALLBACK(star_rating_star_test_cb), hbox);
2086 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2087 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2088 gtk_widget_show(button);
2089 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."));
2090 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2091 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2092 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2093 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2094 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2095 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2096 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2097 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2098 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2099 G_CALLBACK(star_rating_star_icon_cb),
2102 g_string_free(str, TRUE);
2103 g_free(rating_symbol);
2105 str = g_string_new(NULL);
2106 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2107 pref_label_new(hbox, _("Rejected character: "));
2108 str = g_string_append_unichar(str, options->star_rating.rejected);
2109 pref_label_new(hbox, g_strdup(str->str));
2110 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2111 star_rating_entry = gtk_entry_new();
2112 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2113 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2114 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2115 gtk_widget_show(star_rating_entry);
2116 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2117 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2118 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2119 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2120 gtk_widget_show(button);
2121 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."));
2122 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2123 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2124 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2125 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2126 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2127 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2128 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2129 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2130 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2131 G_CALLBACK(star_rating_rejected_icon_cb),
2134 g_string_free(str, TRUE);
2135 g_free(rating_symbol);
2137 pref_spacer(group, PREF_PAD_GROUP);
2139 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2141 c_options->slideshow.delay = options->slideshow.delay;
2142 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2143 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2144 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2145 seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2146 SLIDESHOW_SUBSECOND_PRECISION;
2148 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2150 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2152 options->slideshow.delay ? hours : 0.0,
2153 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2154 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2155 spin = pref_spin_new(hbox, ":" , NULL,
2157 options->slideshow.delay ? minutes: 0.0,
2158 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2159 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2160 spin = pref_spin_new(hbox, ":", NULL,
2161 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2162 options->slideshow.delay ? seconds : 10.0,
2163 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2164 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2166 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2167 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2169 pref_spacer(group, PREF_PAD_GROUP);
2171 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2173 pref_spin_new_int(group, _("Decoded image cache size (MiB):"), NULL,
2174 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2175 pref_checkbox_new_int(group, _("Preload next image"),
2176 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2178 pref_checkbox_new_int(group, _("Refresh on file change"),
2179 options->update_on_time_change, &c_options->update_on_time_change);
2182 pref_spacer(group, PREF_PAD_GROUP);
2184 group = pref_group_new(vbox, FALSE, _("Expand menu and toolbar"), GTK_ORIENTATION_VERTICAL);
2186 pref_checkbox_new_int(group, _("Expand menu and toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2187 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2188 gtk_widget_set_tooltip_text(group, _("Expand the menu and toolbar to the full width of the window"));
2190 pref_spacer(group, PREF_PAD_GROUP);
2192 net_mon = g_network_monitor_get_default();
2193 tz_org = g_network_address_parse_uri(TIMEZONE_DATABASE_WEB, 80, NULL);
2196 internet_available = g_network_monitor_can_reach(net_mon, tz_org, NULL, NULL);
2197 g_object_unref(tz_org);
2200 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2201 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2203 if (!internet_available)
2205 gtk_widget_set_sensitive(group, FALSE);
2208 tz = g_new0(TZData, 1);
2210 path = path_from_utf8(TIMEZONE_DATABASE_WEB);
2211 basename = g_path_get_basename(path);
2212 tz->timezone_database_user = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
2216 if (isfile(tz->timezone_database_user))
2218 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2222 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2225 download_locn = g_strconcat(_("Download database from: "), TIMEZONE_DATABASE_WEB, NULL);
2226 pref_label_new(GTK_WIDGET(hbox), download_locn);
2227 g_free(download_locn);
2229 if (!internet_available)
2231 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"));
2235 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"));
2237 gtk_widget_show(button);
2239 pref_spacer(group, PREF_PAD_GROUP);
2241 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2243 help_search_engine_entry = gtk_entry_new();
2244 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2245 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2246 gtk_widget_show(help_search_engine_entry);
2248 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"));
2250 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2251 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2252 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2253 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2254 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2255 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2256 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2257 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2258 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2259 G_CALLBACK(help_search_engine_entry_icon_cb),
2260 help_search_engine_entry);
2264 static void config_tab_image(GtkWidget *notebook)
2269 GtkWidget *ct_button;
2270 GtkWidget *enlargement_button;
2273 GtkWidget *two_pass;
2275 GtkWidget *gpu_accel;
2278 vbox = scrolled_notebook_page(notebook, _("Image"));
2280 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2282 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2283 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2284 if (options->image.use_clutter_renderer && !options->disable_gpu)
2286 gtk_widget_set_sensitive(table, FALSE);
2290 gpu_accel = pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library (Requires restart)"),
2291 options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2292 if (options->disable_gpu && !options->override_disable_gpu)
2294 gtk_widget_set_sensitive(gpu_accel, FALSE);
2298 two_pass = pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2299 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2300 if (options->image.use_clutter_renderer && !options->disable_gpu)
2302 gtk_widget_set_sensitive(two_pass, FALSE);
2305 c_options->image.zoom_increment = options->image.zoom_increment;
2306 spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2307 0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2308 G_CALLBACK(zoom_increment_cb), NULL);
2309 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2311 c_options->image.zoom_style = options->image.zoom_style;
2312 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2313 add_zoom_style_selection_menu(table, 0, 0, _("Zoom style:"), options->image.zoom_style, &c_options->image.zoom_style);
2315 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2317 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2318 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2319 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2320 spin = pref_spin_new_int(hbox, NULL, NULL,
2322 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2323 pref_checkbox_link_sensitivity(enlargement_button, spin);
2324 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."));
2326 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2327 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2328 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2329 spin = pref_spin_new_int(hbox, NULL, NULL,
2331 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2332 pref_checkbox_link_sensitivity(ct_button, spin);
2333 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."));
2335 group = pref_group_new(vbox, FALSE, _("Tile size"), GTK_ORIENTATION_VERTICAL);
2336 gtk_widget_set_sensitive(group, !options->image.use_clutter_renderer);
2338 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2339 spin = pref_spin_new_int(hbox, _("Pixels"), _("(Requires restart)"),
2341 options->image.tile_size, &c_options->image.tile_size);
2342 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."));
2344 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2346 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2347 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2349 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2350 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2352 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2353 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2355 c_options->image.border_color = options->image.border_color;
2357 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2358 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2360 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2361 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2363 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2364 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2369 static void save_default_window_layout_cb(GtkWidget *widget, gpointer data)
2371 LayoutWindow *lw = NULL;
2372 gchar *default_path;
2375 /* Get current lw */
2378 tmp_id = lw->options.id;
2379 lw->options.id = g_strdup("lw_default");
2381 default_path = g_build_filename(get_rc_dir(), DEFAULT_WINDOW_LAYOUT, NULL);
2382 save_default_layout_options_to_file(default_path, options, lw);
2383 g_free(lw->options.id);
2384 lw->options.id = tmp_id;
2385 g_free(default_path);
2388 #if GTK_CHECK_VERSION(3,22,0)
2389 static gboolean popover_cb(gpointer data)
2391 GtkPopover *popover = data;
2393 gtk_popover_popdown(popover);
2398 static void default_layout_changed_cb(GtkWidget *button, GtkPopover *popover)
2400 gtk_popover_popup(popover);
2402 g_timeout_add(2000, popover_cb, popover);
2405 static GtkWidget *create_popover(GtkWidget *parent, GtkWidget *child, GtkPositionType pos)
2409 popover = gtk_popover_new(parent);
2410 gtk_popover_set_position(GTK_POPOVER (popover), pos);
2411 gtk_container_add (GTK_CONTAINER(popover), child);
2412 gtk_container_set_border_width(GTK_CONTAINER (popover), 6);
2413 gtk_widget_show (child);
2419 static void config_tab_windows(GtkWidget *notebook)
2424 GtkWidget *subgroup;
2426 GtkWidget *ct_button;
2429 vbox = scrolled_notebook_page(notebook, _("Windows"));
2431 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2433 ct_button = pref_checkbox_new_int(group, _("Remember session"),
2434 options->save_window_positions, &c_options->save_window_positions);
2436 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2437 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2438 pref_checkbox_link_sensitivity(ct_button, button);
2440 button = pref_checkbox_new_int(group, _("Remember window workspace"),
2441 options->save_window_workspace, &c_options->save_window_workspace);
2442 pref_checkbox_link_sensitivity(ct_button, button);
2444 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2445 options->tools_restore_state, &c_options->tools_restore_state);
2447 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2448 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2450 pref_checkbox_new_int(group, _("Show window IDs"),
2451 options->show_window_ids, &c_options->show_window_ids);
2453 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2454 pref_label_new(subgroup, _("Use current layout for default: "));
2455 button = pref_button_new(subgroup, NULL, _("Set"), FALSE, G_CALLBACK(save_default_window_layout_cb), NULL);
2457 #if GTK_CHECK_VERSION(3,22,0)
2460 popover = create_popover(button, gtk_label_new(_("Current window layout\nhas been set as default")), GTK_POS_TOP);
2461 gtk_popover_set_modal(GTK_POPOVER (popover), FALSE);
2462 g_signal_connect(button, "clicked", G_CALLBACK(default_layout_changed_cb), popover);
2465 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2467 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2468 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2470 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2471 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2472 options->image.limit_window_size, &c_options->image.limit_window_size);
2473 spin = pref_spin_new_int(hbox, NULL, NULL,
2475 options->image.max_window_size, &c_options->image.max_window_size);
2476 pref_checkbox_link_sensitivity(ct_button, spin);
2478 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2480 c_options->fullscreen.screen = options->fullscreen.screen;
2481 c_options->fullscreen.above = options->fullscreen.above;
2482 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2483 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2484 gtk_widget_show(hbox);
2486 pref_checkbox_new_int(group, _("Smooth image flip"),
2487 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2488 pref_checkbox_new_int(group, _("Disable screen saver"),
2489 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2492 #define PRE_FORMATTED_COLUMNS 5
2493 static void config_tab_osd(GtkWidget *notebook)
2499 GtkWidget *image_overlay_template_view;
2500 GtkWidget *scrolled;
2501 GtkWidget *scrolled_pre_formatted;
2502 GtkTextBuffer *buffer;
2504 GtkWidget *subgroup;
2506 vbox = scrolled_notebook_page(notebook, _("OSD"));
2508 image_overlay_template_view = gtk_text_view_new();
2510 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2512 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2514 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2515 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2516 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2517 gtk_widget_show(scrolled_pre_formatted);
2518 gtk_widget_show(subgroup);
2520 pref_line(group, PREF_PAD_GAP);
2522 pref_label_new(group, _("Image overlay template"));
2524 scrolled = gtk_scrolled_window_new(NULL, NULL);
2525 gtk_widget_set_size_request(scrolled, 200, 150);
2526 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2527 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2528 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2529 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2530 gtk_widget_show(scrolled);
2532 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2533 _("Extensive formatting options are shown in the Help file"));
2535 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2536 gtk_widget_show(image_overlay_template_view);
2538 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2540 #if GTK_CHECK_VERSION(3,4,0)
2541 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2542 G_CALLBACK(image_overlay_set_font_cb), notebook);
2544 button = gtk_font_button_new();
2545 gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
2546 gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
2547 g_signal_connect(G_OBJECT(button), "font-set",
2548 G_CALLBACK(image_overlay_set_font_cb),NULL);
2550 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2551 gtk_widget_show(button);
2553 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2554 G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2555 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2556 gtk_widget_show(button);
2558 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2559 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2560 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2561 gtk_widget_show(button);
2562 image_overlay_set_text_colours();
2564 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2565 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2566 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2567 gtk_widget_show(button);
2569 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2570 G_CALLBACK(image_overlay_help_cb), NULL);
2571 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2572 gtk_widget_show(button);
2574 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2575 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2576 g_signal_connect(G_OBJECT(buffer), "changed",
2577 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2579 pref_line(group, PREF_PAD_GAP);
2581 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2582 hbox = gtk_hbox_new(FALSE, 0);
2583 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2584 gtk_widget_show(hbox);
2585 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2586 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2587 gtk_widget_show(label);
2588 pref_spacer(group,TRUE);
2590 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2591 hbox = gtk_hbox_new(FALSE, 0);
2592 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2593 gtk_widget_show(hbox);
2594 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2595 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2596 gtk_widget_show(label);
2597 pref_spacer(group,TRUE);
2599 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2600 hbox = gtk_hbox_new(FALSE, 0);
2601 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2602 gtk_widget_show(hbox);
2603 label = gtk_label_new(_("%path:39%"));
2604 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2605 gtk_widget_show(label);
2606 pref_spacer(group,TRUE);
2608 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2609 hbox = gtk_hbox_new(FALSE, 0);
2610 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2611 gtk_widget_show(hbox);
2612 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%"));
2613 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2614 gtk_widget_show(label);
2615 pref_spacer(group,TRUE);
2617 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2618 hbox = gtk_hbox_new(FALSE, 0);
2619 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2620 gtk_widget_show(hbox);
2621 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2622 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2623 gtk_widget_show(label);
2626 static GtkTreeModel *create_class_model(void)
2628 GtkListStore *model;
2632 /* create list store */
2633 model = gtk_list_store_new(1, G_TYPE_STRING);
2634 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2636 gtk_list_store_append(model, &iter);
2637 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2639 return GTK_TREE_MODEL (model);
2644 static gint filter_table_sort_cb(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data)
2646 gint n = GPOINTER_TO_INT(data);
2648 FilterEntry *filter_a;
2649 FilterEntry *filter_b;
2651 gtk_tree_model_get(model, a, 0, &filter_a, -1);
2652 gtk_tree_model_get(model, b, 0, &filter_b, -1);
2656 case FILETYPES_COLUMN_DESCRIPTION:
2658 ret = g_utf8_collate(filter_a->description, filter_b->description);
2661 case FILETYPES_COLUMN_CLASS:
2663 ret = g_strcmp0(format_class_list[filter_a->file_class], format_class_list[filter_b->file_class]);
2666 case FILETYPES_COLUMN_WRITABLE:
2668 ret = filter_a->writable - filter_b->writable;
2671 case FILETYPES_COLUMN_SIDECAR:
2673 ret = filter_a->allow_sidecar - filter_b->allow_sidecar;
2677 g_return_val_if_reached(0);
2683 static gboolean search_function_cb(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer search_data)
2686 gboolean ret = TRUE;
2688 gtk_tree_model_get(model, iter, 0, &fe, -1);
2690 if (g_strstr_len(fe->extensions, -1, key))
2698 static void config_tab_files(GtkWidget *notebook)
2705 GtkWidget *ct_button;
2706 GtkWidget *scrolled;
2707 GtkWidget *filter_view;
2708 GtkCellRenderer *renderer;
2709 GtkTreeSelection *selection;
2710 GtkTreeViewColumn *column;
2712 vbox = scrolled_notebook_page(notebook, _("Files"));
2714 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2716 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2717 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2718 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2719 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2720 pref_checkbox_new_int(group, _("Case sensitive sort"),
2721 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2722 pref_checkbox_new_int(group, _("Natural sort order"),
2723 options->file_sort.natural, &c_options->file_sort.natural);
2724 pref_checkbox_new_int(group, _("Disable file extension checks"),
2725 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2727 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2728 options->file_filter.disable, &c_options->file_filter.disable);
2731 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2733 sidecar_ext_entry = gtk_entry_new();
2734 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2735 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2736 gtk_widget_show(sidecar_ext_entry);
2738 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2740 frame = pref_group_parent(group);
2741 g_signal_connect(G_OBJECT(ct_button), "toggled",
2742 G_CALLBACK(filter_disable_cb), frame);
2743 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2745 scrolled = gtk_scrolled_window_new(NULL, NULL);
2746 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2747 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2748 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2749 gtk_widget_show(scrolled);
2751 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2752 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2753 g_object_unref(filter_store);
2754 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2755 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2757 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2759 column = gtk_tree_view_column_new();
2760 gtk_tree_view_column_set_title(column, _("Filter"));
2761 gtk_tree_view_column_set_resizable(column, TRUE);
2763 renderer = gtk_cell_renderer_toggle_new();
2764 g_signal_connect(G_OBJECT(renderer), "toggled",
2765 G_CALLBACK(filter_store_enable_cb), filter_store);
2766 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2767 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2768 GINT_TO_POINTER(FE_ENABLE), NULL);
2770 renderer = gtk_cell_renderer_text_new();
2771 g_signal_connect(G_OBJECT(renderer), "edited",
2772 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2773 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2774 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2775 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2776 GINT_TO_POINTER(FE_EXTENSION), NULL);
2777 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2779 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), TRUE);
2780 gtk_tree_view_set_search_column(GTK_TREE_VIEW(filter_view), FILETYPES_COLUMN_FILTER);
2781 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(filter_view), search_function_cb, NULL, NULL);
2783 column = gtk_tree_view_column_new();
2784 gtk_tree_view_column_set_title(column, _("Description"));
2785 gtk_tree_view_column_set_resizable(column, TRUE);
2786 gtk_tree_view_column_set_fixed_width(column, 200);
2787 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2789 renderer = gtk_cell_renderer_text_new();
2790 g_signal_connect(G_OBJECT(renderer), "edited",
2791 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2792 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2793 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2794 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2795 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2796 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2797 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(filter_store), FILETYPES_COLUMN_DESCRIPTION, filter_table_sort_cb, GINT_TO_POINTER(FILETYPES_COLUMN_DESCRIPTION), NULL);
2798 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_DESCRIPTION);
2800 column = gtk_tree_view_column_new();
2801 gtk_tree_view_column_set_title(column, _("Class"));
2802 gtk_tree_view_column_set_resizable(column, TRUE);
2803 renderer = gtk_cell_renderer_combo_new();
2804 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2805 "model", create_class_model(),
2810 g_signal_connect(G_OBJECT(renderer), "edited",
2811 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2812 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2813 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2814 GINT_TO_POINTER(FE_CLASS), NULL);
2815 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2816 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);
2817 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_CLASS);
2819 column = gtk_tree_view_column_new();
2820 gtk_tree_view_column_set_title(column, _("Writable"));
2821 gtk_tree_view_column_set_resizable(column, FALSE);
2822 renderer = gtk_cell_renderer_toggle_new();
2823 g_signal_connect(G_OBJECT(renderer), "toggled",
2824 G_CALLBACK(filter_store_writable_cb), filter_store);
2825 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2826 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2827 GINT_TO_POINTER(FE_WRITABLE), NULL);
2828 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2829 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);
2830 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_WRITABLE);
2832 column = gtk_tree_view_column_new();
2833 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2834 gtk_tree_view_column_set_resizable(column, FALSE);
2835 renderer = gtk_cell_renderer_toggle_new();
2836 g_signal_connect(G_OBJECT(renderer), "toggled",
2837 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2838 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2839 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2840 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2841 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2842 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);
2843 gtk_tree_view_column_set_sort_column_id(column, FILETYPES_COLUMN_SIDECAR);
2845 filter_store_populate();
2846 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2847 gtk_widget_show(filter_view);
2849 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2851 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2852 G_CALLBACK(filter_default_cb), filter_view);
2853 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2854 gtk_widget_show(button);
2856 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2857 G_CALLBACK(filter_remove_cb), filter_view);
2858 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2859 gtk_widget_show(button);
2861 button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2862 G_CALLBACK(filter_add_cb), filter_view);
2863 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2864 gtk_widget_show(button);
2868 static void config_tab_metadata(GtkWidget *notebook)
2873 GtkWidget *ct_button;
2877 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2880 group = pref_group_new(vbox, FALSE, _("Metadata writing process"), GTK_ORIENTATION_VERTICAL);
2882 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2884 label = pref_label_new(group, _("Metadata are written in the following order. The process ends after first success."));
2885 #if GTK_CHECK_VERSION(3,16,0)
2886 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2887 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2889 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2892 ct_button = pref_checkbox_new_int(group, _("1) Save metadata in image files, or sidecar files, according to the XMP standard"),
2893 options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2895 gtk_widget_set_sensitive(ct_button, FALSE);
2898 pref_checkbox_new_int(group, _("2) Save metadata in '.metadata' folder, local to image folder (non-standard)"),
2899 options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2901 text = g_strdup_printf(_("3) Save metadata in Geeqie private directory '%s'"), get_metadata_cache_dir());
2902 label = pref_label_new(group, text);
2903 #if GTK_CHECK_VERSION(3,16,0)
2904 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2905 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2907 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2909 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2912 group = pref_group_new(vbox, FALSE, _("Step 1: Write to image files"), GTK_ORIENTATION_VERTICAL);
2914 gtk_widget_set_sensitive(group, FALSE);
2917 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2918 pref_checkbox_link_sensitivity(ct_button, hbox);
2920 pref_checkbox_new_int(hbox, _("Store metadata also in legacy IPTC tags (converted according to IPTC4XMP standard)"),
2921 options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2923 pref_checkbox_new_int(hbox, _("Warn if the image files are unwritable"),
2924 options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2926 pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
2927 options->metadata.confirm_write, &c_options->metadata.confirm_write);
2929 pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
2930 options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2932 group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
2934 gtk_widget_set_sensitive(group, FALSE);
2937 pref_checkbox_new_int(group, _("Use GQview legacy metadata format (supports only keywords and comments) instead of XMP"),
2938 options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2941 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2942 pref_checkbox_new_int(group, _("Write the same description tags (keywords, comment, etc.) to all grouped sidecars"),
2943 options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2945 pref_checkbox_new_int(group, _("Allow keywords to differ only in case"),
2946 options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2948 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"),
2949 options->metadata.write_orientation, &c_options->metadata.write_orientation);
2951 gtk_widget_set_sensitive(ct_button, FALSE);
2954 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2956 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"),
2957 options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2959 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2960 pref_checkbox_link_sensitivity(ct_button, hbox);
2962 pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1,
2963 options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2965 pref_checkbox_new_int(group, _("Write metadata on image change"),
2966 options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2968 pref_checkbox_new_int(group, _("Write metadata on directory change"),
2969 options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2972 #if GTK_CHECK_VERSION(3,20,0)
2973 group = pref_group_new(vbox, FALSE, _("Spelling checks"), GTK_ORIENTATION_VERTICAL);
2975 ct_button = pref_checkbox_new_int(group, _("Check spelling -Requires restart"), options->metadata.check_spelling, &c_options->metadata.check_spelling);
2979 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2981 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"),
2982 options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2983 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");
2988 typedef struct _KeywordFindData KeywordFindData;
2989 struct _KeywordFindData
2996 GtkWidget *button_close;
2997 GtkWidget *button_stop;
2998 GtkWidget *button_start;
2999 GtkWidget *progress;
3007 guint idle_id; /* event source id */
3010 #define KEYWORD_DIALOG_WIDTH 400
3012 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
3014 GList *list_d = NULL;
3015 GList *list_f = NULL;
3019 filelist_read(dir_fd, &list_f, &list_d);
3023 filelist_read(dir_fd, &list_f, NULL);
3026 list_f = filelist_filter(list_f, FALSE);
3027 list_d = filelist_filter(list_d, TRUE);
3029 kfd->list = g_list_concat(list_f, kfd->list);
3030 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
3033 static void keywords_find_reset(KeywordFindData *kfd)
3035 filelist_free(kfd->list);
3038 filelist_free(kfd->list_dir);
3039 kfd->list_dir = NULL;
3042 static void keywords_find_close_cb(GenericDialog *fd, gpointer data)
3044 KeywordFindData *kfd = data;
3046 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
3048 keywords_find_reset(kfd);
3049 generic_dialog_close(kfd->gd);
3053 static void keywords_find_finish(KeywordFindData *kfd)
3055 keywords_find_reset(kfd);
3057 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
3058 spinner_set_interval(kfd->spinner, -1);
3060 gtk_widget_set_sensitive(kfd->group, TRUE);
3061 gtk_widget_set_sensitive(kfd->button_start, TRUE);
3062 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3063 gtk_widget_set_sensitive(kfd->button_close, TRUE);
3066 static void keywords_find_stop_cb(GenericDialog *fd, gpointer data)
3068 KeywordFindData *kfd = data;
3070 g_idle_remove_by_data(kfd);
3072 keywords_find_finish(kfd);
3075 static gboolean keywords_find_file(gpointer data)
3077 KeywordFindData *kfd = data;
3079 GtkTextBuffer *buffer;
3087 fd = kfd->list->data;
3088 kfd->list = g_list_remove(kfd->list, fd);
3090 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
3091 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3095 gtk_text_buffer_get_end_iter(buffer, &iter);
3096 tmp = g_strconcat(keywords->data, "\n", NULL);
3097 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3099 keywords = keywords->next;
3102 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
3103 file_data_unref(fd);
3104 string_list_free(keywords);
3108 else if (kfd->list_dir)
3112 fd = kfd->list_dir->data;
3113 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
3115 keywords_find_folder(kfd, fd);
3117 file_data_unref(fd);
3122 keywords_find_finish(kfd);
3127 static void keywords_find_start_cb(GenericDialog *fd, gpointer data)
3129 KeywordFindData *kfd = data;
3132 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
3134 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
3135 parse_out_relatives(path);
3139 warning_dialog(_("Invalid folder"),
3140 _("The specified folder can not be found."),
3141 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
3147 gtk_widget_set_sensitive(kfd->group, FALSE);
3148 gtk_widget_set_sensitive(kfd->button_start, FALSE);
3149 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
3150 gtk_widget_set_sensitive(kfd->button_close, FALSE);
3151 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
3153 dir_fd = file_data_new_dir(path);
3154 keywords_find_folder(kfd, dir_fd);
3155 file_data_unref(dir_fd);
3156 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
3162 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
3164 KeywordFindData *kfd;
3168 kfd = g_new0(KeywordFindData, 1);
3170 kfd->gd = generic_dialog_new(_("Search for keywords"),
3171 "search_for_keywords",
3174 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
3175 kfd->gd->cancel_cb = keywords_find_close_cb;
3176 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
3177 keywords_find_close_cb, FALSE);
3178 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
3179 keywords_find_start_cb, FALSE);
3180 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
3181 keywords_find_stop_cb, FALSE);
3182 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3184 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
3186 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
3187 pref_spacer(hbox, PREF_PAD_INDENT);
3188 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
3190 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3191 pref_label_new(hbox, _("Folder:"));
3193 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
3194 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
3195 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
3196 gtk_widget_show(label);
3198 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
3200 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
3201 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3203 kfd->progress = gtk_entry_new();
3204 gtk_widget_set_can_focus(kfd->progress, FALSE);
3205 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
3206 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
3207 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
3208 gtk_widget_show(kfd->progress);
3210 kfd->spinner = spinner_new(NULL, -1);
3211 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
3212 gtk_widget_show(kfd->spinner);
3216 gtk_widget_show(kfd->gd->dialog);
3219 static void keywords_find_cb(GtkWidget *widget, gpointer data)
3221 const gchar *path = layout_get_path(NULL);
3223 if (!path || !*path) path = homedir();
3224 keywords_find_dialog(widget, path);
3227 static void config_tab_keywords_save()
3229 GtkTextIter start, end;
3230 GtkTextBuffer *buffer;
3231 GList *kw_list = NULL;
3237 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3238 gtk_text_buffer_get_bounds(buffer, &start, &end);
3240 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3242 kw_split = strtok(buffer_text, "\n");
3243 while (kw_split != NULL)
3249 if (g_strcmp0(work->data, kw_split) == 0)
3258 kw_list = g_list_append(kw_list, g_strdup(kw_split));
3260 kw_split = strtok(NULL, "\n");
3263 keyword_list_set(kw_list);
3265 string_list_free(kw_list);
3266 g_free(buffer_text);
3269 static void config_tab_keywords(GtkWidget *notebook)
3275 GtkWidget *scrolled;
3277 GtkTextBuffer *buffer;
3280 GspellTextView *gspell_view;
3283 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3285 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3287 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3289 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
3290 G_CALLBACK(keywords_find_cb), keyword_text);
3291 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
3294 keyword_text = gtk_text_view_new();
3295 gtk_widget_set_size_request(keyword_text, 20, 20);
3296 scrolled = gtk_scrolled_window_new(NULL, NULL);
3297 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3298 gtk_widget_show(scrolled);
3301 #if GTK_CHECK_VERSION(3,20,0)
3302 if (options->metadata.check_spelling)
3304 gspell_view = gspell_text_view_get_from_gtk_text_view(GTK_TEXT_VIEW(keyword_text));
3305 gspell_text_view_basic_setup(gspell_view);
3310 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
3311 gtk_widget_show(keyword_text);
3313 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3315 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3316 gtk_text_buffer_create_tag(buffer, "monospace",
3317 "family", "monospace", NULL);
3319 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3320 gtk_text_buffer_get_start_iter(buffer, &iter);
3321 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3324 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3326 GList *kwl = keyword_list_get();
3327 kwl = g_list_first(kwl);
3330 gtk_text_buffer_get_end_iter (buffer, &iter);
3331 tmp = g_strconcat(kwl->data, "\n", NULL);
3332 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3337 gtk_text_buffer_set_modified(buffer, FALSE);
3344 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3346 gint *option = data;
3348 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3352 *option = INTENT_PERCEPTUAL;
3355 *option = INTENT_RELATIVE_COLORIMETRIC;
3358 *option = INTENT_SATURATION;
3361 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3366 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3367 gint option, gint *option_c)
3374 pref_table_label(table, column, row, text, 0.0);
3376 combo = gtk_combo_box_text_new();
3378 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3379 if (option == INTENT_PERCEPTUAL) current = 0;
3380 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3381 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3382 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3383 if (option == INTENT_SATURATION) current = 2;
3384 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3385 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3387 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3389 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3391 g_signal_connect(G_OBJECT(combo), "changed",
3392 G_CALLBACK(intent_menu_cb), option_c);
3394 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
3395 gtk_widget_show(combo);
3399 static void config_tab_color(GtkWidget *notebook)
3408 vbox = scrolled_notebook_page(notebook, _("Color management"));
3410 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3412 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3415 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3416 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3418 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3419 pref_label_bold(label, TRUE, FALSE);
3421 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3422 pref_label_bold(label, TRUE, FALSE);
3424 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3425 pref_label_bold(label, TRUE, FALSE);
3427 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3432 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3433 pref_table_label(table, 0, i + 1, buf, 1.0);
3436 entry = gtk_entry_new();
3437 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3438 if (options->color_profile.input_name[i])
3440 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3442 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3443 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3444 gtk_widget_show(entry);
3445 color_profile_input_name_entry[i] = entry;
3447 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3448 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3449 gtk_widget_set_size_request(entry, 160, -1);
3450 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3451 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3452 gtk_widget_show(tabcomp);
3453 color_profile_input_file_entry[i] = entry;
3456 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3458 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3460 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3461 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3463 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3465 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3466 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3467 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3468 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3469 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3471 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3473 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3475 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3477 gtk_widget_show(tabcomp);
3480 /* advanced entry tab */
3481 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer data)
3483 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3485 c_options->file_ops.use_system_trash = FALSE;
3486 c_options->file_ops.no_trash = FALSE;
3490 static void use_system_trash_cb(GtkWidget *widget, gpointer data)
3492 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3494 c_options->file_ops.use_system_trash = TRUE;
3495 c_options->file_ops.no_trash = FALSE;
3499 static void use_no_cache_cb(GtkWidget *widget, gpointer data)
3501 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3503 c_options->file_ops.no_trash = TRUE;
3507 static void config_tab_behavior(GtkWidget *notebook)
3514 GtkWidget *ct_button;
3518 GtkWidget *with_rename;
3519 GtkWidget *collections_on_top;
3520 GtkWidget *hide_window_in_fullscreen;
3521 GtkWidget *checkbox;
3524 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3526 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3528 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3529 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3530 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3531 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3532 pref_checkbox_new_int(group, _("Enable Delete key"),
3533 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3535 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3536 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3538 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3539 pref_checkbox_link_sensitivity(ct_button, hbox);
3541 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3542 pref_label_new(hbox, _("Folder:"));
3544 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3545 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3546 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3547 gtk_widget_show(tabcomp);
3549 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3550 pref_checkbox_link_sensitivity(ct_button, hbox);
3552 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3553 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MiB"),
3554 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3555 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3556 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3557 G_CALLBACK(safe_delete_view_cb), NULL);
3558 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3559 gtk_widget_show(button);
3561 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3562 G_CALLBACK(safe_delete_clear_cb), NULL);
3563 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3565 c_options->file_ops.no_trash = options->file_ops.no_trash;
3566 c_options->file_ops.use_system_trash = options->file_ops.use_system_trash;
3568 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3569 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3571 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3572 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3574 gtk_widget_show(button);
3576 pref_spacer(group, PREF_PAD_GROUP);
3579 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3581 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3582 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3584 pref_checkbox_new_int(group, _("In place renaming"),
3585 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3587 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3588 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3590 tmp = pref_checkbox_new_int(group, _("Circular selection lists"),
3591 options->circular_selection_lists, &c_options->circular_selection_lists);
3592 gtk_widget_set_tooltip_text(tmp, _("Traverse selection lists in a circular manner"));
3594 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3595 options->marks_save, &c_options->marks_save);
3596 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3598 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3599 options->with_rename, &c_options->with_rename);
3600 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3602 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3603 options->collections_on_top, &c_options->collections_on_top);
3604 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3606 hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3607 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3608 gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice");
3610 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3611 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3613 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3614 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3616 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3617 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3619 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3620 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3622 pref_spacer(group, PREF_PAD_GROUP);
3624 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3626 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3627 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3628 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3629 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3630 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3631 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3632 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3633 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3634 pref_checkbox_new_int(group, _("Open archive by left click on image"),
3635 options->image_l_click_archive, &c_options->image_l_click_archive);
3636 pref_checkbox_new_int(group, _("Play video by left click on image"),
3637 options->image_l_click_video, &c_options->image_l_click_video);
3638 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3639 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3641 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3642 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3643 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3644 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3645 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3647 pref_spacer(group, PREF_PAD_GROUP);
3649 group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3651 checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3652 options->override_disable_gpu, &c_options->override_disable_gpu);
3653 gtk_widget_set_tooltip_text(checkbox, "Contact the developers for usage");
3656 pref_spacer(group, PREF_PAD_GROUP);
3658 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3660 pref_spin_new_int(group, _("Debug level:"), NULL,
3661 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3663 pref_checkbox_new_int(group, _("Timer data"),
3664 options->log_window.timer_data, &c_options->log_window.timer_data);
3666 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3667 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3671 /* accelerators tab */
3672 static void config_tab_accelerators(GtkWidget *notebook)
3678 GtkWidget *scrolled;
3679 GtkWidget *accel_view;
3680 GtkCellRenderer *renderer;
3681 GtkTreeSelection *selection;
3682 GtkTreeViewColumn *column;
3684 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3686 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3688 scrolled = gtk_scrolled_window_new(NULL, NULL);
3689 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3690 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3691 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3692 gtk_widget_show(scrolled);
3694 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3696 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3697 g_object_unref(accel_store);
3698 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3699 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3701 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3703 renderer = gtk_cell_renderer_text_new();
3705 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3710 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3711 gtk_tree_view_column_set_resizable(column, TRUE);
3712 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3715 renderer = gtk_cell_renderer_accel_new();
3716 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3717 G_CALLBACK(accel_store_cleared_cb), accel_store);
3718 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3719 G_CALLBACK(accel_store_edited_cb), accel_store);
3722 g_object_set (renderer,
3724 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3727 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3732 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3733 gtk_tree_view_column_set_resizable(column, TRUE);
3734 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3736 renderer = gtk_cell_renderer_text_new();
3738 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3743 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3744 gtk_tree_view_column_set_resizable(column, TRUE);
3745 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3747 renderer = gtk_cell_renderer_text_new();
3749 column = gtk_tree_view_column_new_with_attributes("Accel",
3754 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3755 gtk_tree_view_column_set_resizable(column, TRUE);
3756 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3758 accel_store_populate();
3759 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3760 gtk_widget_show(accel_view);
3762 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3764 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3765 G_CALLBACK(accel_default_cb), accel_view);
3766 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3767 gtk_widget_show(button);
3769 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3770 G_CALLBACK(accel_reset_cb), accel_view);
3771 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3772 gtk_widget_show(button);
3775 /* toolbar main tab */
3776 static void config_tab_toolbar_main(GtkWidget *notebook)
3779 GtkWidget *toolbardata;
3782 lw = layout_window_list->data;
3784 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3786 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3787 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3788 gtk_widget_show(vbox);
3791 /* toolbar status tab */
3792 static void config_tab_toolbar_status(GtkWidget *notebook)
3795 GtkWidget *toolbardata;
3798 lw = layout_window_list->data;
3800 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3802 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3803 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3804 gtk_widget_show(vbox);
3808 static gint extension_sort_cb(gconstpointer a, gconstpointer b)
3810 return g_strcmp0((gchar *)a, (gchar *)b);
3813 static void config_tab_advanced(GtkWidget *notebook)
3817 GSList *formats_list;
3818 GList *extensions_list = NULL;
3821 GdkPixbufFormat *fm;
3823 GString *types_string = g_string_new(NULL);
3824 GtkWidget *types_string_label;
3825 GtkWidget *threads_string_label;
3826 GtkWidget *dupes_threads_spin;
3828 vbox = scrolled_notebook_page(notebook, _("Advanced"));
3829 group = pref_group_new(vbox, FALSE, _("External preview extraction"), GTK_ORIENTATION_VERTICAL);
3831 pref_checkbox_new_int(group, _("Use external preview extraction - Requires restart"), options->external_preview.enable, &c_options->external_preview.enable);
3833 pref_spacer(group, PREF_PAD_GROUP);
3835 formats_list = gdk_pixbuf_get_formats();
3837 while (formats_list)
3839 fm = formats_list->data;
3840 extensions = gdk_pixbuf_format_get_extensions(fm);
3843 while (extensions[i])
3845 extensions_list = g_list_insert_sorted(extensions_list, g_strdup(extensions[i]), extension_sort_cb);
3849 g_strfreev(extensions);
3850 formats_list = formats_list->next;
3853 while (extensions_list)
3855 if (types_string->len == 0)
3857 types_string = g_string_append(types_string, extensions_list->data);
3861 types_string = g_string_append(types_string, ", ");
3862 types_string = g_string_append(types_string, extensions_list->data);
3865 extensions_list = extensions_list->next;
3868 types_string = g_string_prepend(types_string, _("Usable file types:\n"));
3869 types_string_label = pref_label_new(group, types_string->str);
3870 gtk_label_set_line_wrap(GTK_LABEL(types_string_label), TRUE);
3872 pref_spacer(group, PREF_PAD_GROUP);
3874 group = pref_group_new(vbox, FALSE, _("File identification tool"), GTK_ORIENTATION_VERTICAL);
3875 external_preview_select_entry = gtk_entry_new();
3876 tabcomp = tab_completion_new(&external_preview_select_entry, options->external_preview.select, NULL, NULL, NULL, NULL);
3877 tab_completion_add_select_button(external_preview_select_entry, _("Select file identification tool"), FALSE);
3878 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3879 gtk_widget_show(tabcomp);
3881 group = pref_group_new(vbox, FALSE, _("Preview extraction tool"), GTK_ORIENTATION_VERTICAL);
3882 external_preview_extract_entry = gtk_entry_new();
3883 tabcomp = tab_completion_new(&external_preview_extract_entry, options->external_preview.extract, NULL, NULL, NULL, NULL);
3884 tab_completion_add_select_button(external_preview_extract_entry, _("Select preview extraction tool"), FALSE);
3885 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3886 gtk_widget_show(tabcomp);
3888 gtk_widget_show(vbox);
3890 g_slist_free(formats_list);
3891 string_list_free(extensions_list);
3892 g_string_free(types_string, TRUE);
3894 pref_spacer(group, PREF_PAD_GROUP);
3896 pref_line(vbox, PREF_PAD_SPACE);
3897 group = pref_group_new(vbox, FALSE, _("Thread pool limits"), GTK_ORIENTATION_VERTICAL);
3899 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.");
3900 gtk_label_set_line_wrap(GTK_LABEL(threads_string_label), TRUE);
3902 pref_spacer(vbox, PREF_PAD_GROUP);
3904 dupes_threads_spin = pref_spin_new_int(vbox, _("Duplicate check:"), _("max. threads"), 0, get_cpu_cores(), 1, options->threads.duplicates, &c_options->threads.duplicates);
3905 gtk_widget_set_tooltip_markup(dupes_threads_spin, _("Set to 0 for unlimited"));
3909 static void config_tab_stereo(GtkWidget *notebook)
3917 GtkWidget *fs_button;
3918 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3920 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3922 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3923 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3925 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3926 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3927 pref_checkbox_new_int(box, _("Mirror left image"),
3928 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3929 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3930 pref_checkbox_new_int(box, _("Flip left image"),
3931 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3932 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3933 pref_checkbox_new_int(box, _("Mirror right image"),
3934 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3935 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3936 pref_checkbox_new_int(box, _("Flip right image"),
3937 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3938 pref_checkbox_new_int(group, _("Swap left and right images"),
3939 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3940 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3941 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3943 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3944 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3945 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3946 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3947 pref_checkbox_link_sensitivity(fs_button, box2);
3948 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3949 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3950 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3951 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3952 pref_checkbox_new_int(box, _("Mirror left image"),
3953 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3954 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3955 pref_checkbox_new_int(box, _("Flip left image"),
3956 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3957 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3958 pref_checkbox_new_int(box, _("Mirror right image"),
3959 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3960 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3961 pref_checkbox_new_int(box, _("Flip right image"),
3962 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3963 pref_checkbox_new_int(box2, _("Swap left and right images"),
3964 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3965 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3966 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3968 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3969 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3970 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3971 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3972 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
3973 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3974 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
3975 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3976 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
3977 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3978 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
3979 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3980 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
3981 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3985 /* Main preferences window */
3986 static void config_window_create(LayoutWindow *lw)
3988 GtkWidget *win_vbox;
3990 GtkWidget *notebook;
3992 GtkWidget *ct_button;
3994 if (!c_options) c_options = init_options(NULL);
3996 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3997 DEBUG_NAME(configwindow);
3998 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3999 g_signal_connect(G_OBJECT(configwindow), "delete_event",
4000 G_CALLBACK(config_window_delete), NULL);
4001 if (options->save_dialog_window_positions)
4003 gtk_window_resize(GTK_WINDOW(configwindow), lw->options.preferences_window.w, lw->options.preferences_window.h);
4004 gtk_window_move(GTK_WINDOW(configwindow), lw->options.preferences_window.x, lw->options.preferences_window.y);
4008 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
4010 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
4011 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
4013 win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
4014 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
4015 gtk_widget_show(win_vbox);
4017 notebook = gtk_notebook_new();
4018 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
4019 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
4020 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
4022 config_tab_general(notebook);
4023 config_tab_image(notebook);
4024 config_tab_osd(notebook);
4025 config_tab_windows(notebook);
4026 config_tab_accelerators(notebook);
4027 config_tab_files(notebook);
4028 config_tab_metadata(notebook);
4029 config_tab_keywords(notebook);
4030 config_tab_color(notebook);
4031 config_tab_stereo(notebook);
4032 config_tab_behavior(notebook);
4033 config_tab_toolbar_main(notebook);
4034 config_tab_toolbar_status(notebook);
4035 config_tab_advanced(notebook);
4037 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), lw->options.preferences_window.page_number);
4039 hbox = gtk_hbutton_box_new();
4040 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
4041 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
4042 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
4043 gtk_widget_show(hbox);
4045 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
4046 G_CALLBACK(config_window_help_cb), notebook);
4047 gtk_container_add(GTK_CONTAINER(hbox), button);
4048 gtk_widget_set_can_default(button, TRUE);
4049 gtk_widget_show(button);
4051 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
4052 G_CALLBACK(config_window_ok_cb), notebook);
4053 gtk_container_add(GTK_CONTAINER(hbox), button);
4054 gtk_widget_set_can_default(button, TRUE);
4055 gtk_widget_grab_default(button);
4056 gtk_widget_show(button);
4060 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
4061 G_CALLBACK(config_window_close_cb), NULL);
4062 gtk_container_add(GTK_CONTAINER(hbox), button);
4063 gtk_widget_set_can_default(button, TRUE);
4064 gtk_widget_show(button);
4066 if (!generic_dialog_get_alternative_button_order(configwindow))
4068 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
4071 gtk_widget_show(notebook);
4073 gtk_widget_show(configwindow);
4077 *-----------------------------------------------------------------------------
4078 * config window show (public)
4079 *-----------------------------------------------------------------------------
4082 void show_config_window(LayoutWindow *lw)
4086 gtk_window_present(GTK_WINDOW(configwindow));
4090 config_window_create(lw);
4099 void show_about_window(LayoutWindow *lw)
4101 GdkPixbuf *pixbuf_logo;
4102 GdkPixbuf *pixbuf_icon;
4103 gchar *authors[1000];
4108 gchar *timezone_path;
4111 #define LINE_LENGTH 1000
4112 gchar line[LINE_LENGTH];
4114 copyright = g_string_new(NULL);
4115 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");
4117 timezone_path = g_build_filename(get_rc_dir(), TIMEZONE_DATABASE_FILE, NULL);
4118 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
4120 cd = ZDOpenDatabase(timezone_path);
4123 copyright = g_string_append(copyright, ZDGetNotice(cd));
4127 log_printf("Error: Init of timezone database %s failed\n", timezone_path);
4129 ZDCloseDatabase(cd);
4131 g_free(timezone_path);
4134 path = g_build_filename(gq_helpdir, "AUTHORS", NULL);
4135 fp = fopen(path, "r");
4138 while(fgets(line, LINE_LENGTH, fp))
4140 /* get rid of ending \n from fgets */
4141 line[strlen(line) - 1] = '\0';
4142 authors[i_authors] = g_strdup(line);
4145 authors[i_authors] = NULL;
4150 comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
4151 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
4153 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
4154 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
4155 gtk_show_about_dialog(GTK_WINDOW(lw->window),
4156 "title", _("About Geeqie"),
4158 "program-name", GQ_APPNAME,
4160 "logo", pixbuf_logo,
4161 "icon", pixbuf_icon,
4162 "website", GQ_WEBSITE,
4163 "website-label", "Website",
4164 "comments", comment,
4166 "translator-credits", _("translator-credits"),
4167 "wrap-license", TRUE,
4168 "license", copyright->str,
4171 g_string_free(copyright, TRUE);
4174 while(n < i_authors)
4184 static void image_overlay_set_text_colours()
4186 c_options->image_overlay.text_red = options->image_overlay.text_red;
4187 c_options->image_overlay.text_green = options->image_overlay.text_green;
4188 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
4189 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
4190 c_options->image_overlay.background_red = options->image_overlay.background_red;
4191 c_options->image_overlay.background_green = options->image_overlay.background_green;
4192 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
4193 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
4197 *-----------------------------------------------------------------------------
4198 * timezone database routines
4199 *-----------------------------------------------------------------------------
4202 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
4204 GError *error = NULL;
4206 gchar *tmp_filename;
4207 gchar *timezone_bin;
4208 gchar *tmp_dir = NULL;
4211 if (!g_cancellable_is_cancelled(tz->cancellable))
4213 generic_dialog_close(tz->gd);
4217 if (g_file_copy_finish(G_FILE(source_object), res, &error))
4219 tmp_filename = g_file_get_path(tz->tmp_g_file);
4220 fd = file_data_new_simple(tmp_filename);
4221 tmp_dir = open_archive(fd);
4225 timezone_bin = g_build_filename(tmp_dir, TIMEZONE_DATABASE_VERSION, TIMEZONE_DATABASE_FILE, NULL);
4226 if (isfile(timezone_bin))
4228 move_file(timezone_bin, tz->timezone_database_user);
4232 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GTK_STOCK_DIALOG_WARNING, NULL);
4235 g_free(timezone_bin);
4236 g_free(tmp_dir); // The folder in /tmp is deleted in exit_program_final()
4240 warning_dialog(_("Warning: Cannot open timezone database file"), _("See the Log Window"), GTK_STOCK_DIALOG_WARNING, NULL);
4242 g_free(tmp_filename);
4243 file_data_unref(fd);
4247 file_util_warning_dialog(_("Error: Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4250 g_file_delete(tz->tmp_g_file, NULL, &error);
4251 g_object_unref(tz->tmp_g_file);
4252 tz->tmp_g_file = NULL;
4253 g_object_unref(tz->cancellable);
4254 g_object_unref(tz->timezone_database_gq);
4257 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
4261 if (!g_cancellable_is_cancelled(tz->cancellable))
4263 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
4267 static void timezone_cancel_button_cb(GenericDialog *gd, gpointer data)
4271 g_cancellable_cancel(tz->cancellable);
4274 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
4277 GError *error = NULL;
4278 GFileIOStream *io_stream;
4285 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
4289 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4290 log_printf("Error: Download timezone database failed:\n%s", error->message);
4291 g_error_free(error);
4292 g_object_unref(tz->tmp_g_file);
4296 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE_WEB);
4298 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
4300 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
4302 tz->progress = gtk_progress_bar_new();
4303 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
4304 gtk_widget_show(tz->progress);
4306 gtk_widget_show(tz->gd->dialog);
4307 tz->cancellable = g_cancellable_new();
4308 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);
4310 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
4313 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */