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"
43 #include "pixbuf_util.h"
44 #include "slideshow.h"
48 #include "ui_fileops.h"
50 #include "ui_spinner.h"
51 #include "ui_tabcomp.h"
52 #include "ui_utildlg.h"
54 #include "zonedetect.h"
64 #define EDITOR_NAME_MAX_LENGTH 32
65 #define EDITOR_COMMAND_MAX_LENGTH 1024
67 static void image_overlay_set_text_colours();
69 GtkWidget *keyword_text;
70 static void config_tab_keywords_save();
72 typedef struct _ThumbSize ThumbSize;
79 static ThumbSize thumb_size_list[] =
113 gchar *format_class_list[] = {
123 /* config memory values */
124 static ConfOptions *c_options = NULL;
131 static GtkWidget *configwindow = NULL;
132 static GtkListStore *filter_store = NULL;
133 static GtkTreeStore *accel_store = NULL;
135 static GtkWidget *safe_delete_path_entry;
137 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
138 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
139 static GtkWidget *color_profile_screen_file_entry;
141 static GtkWidget *sidecar_ext_entry;
142 static GtkWidget *help_search_engine_entry;
145 #define CONFIG_WINDOW_DEF_WIDTH 700
146 #define CONFIG_WINDOW_DEF_HEIGHT 600
149 *-----------------------------------------------------------------------------
150 * option widget callbacks (private)
151 *-----------------------------------------------------------------------------
154 static void zoom_increment_cb(GtkWidget *spin, gpointer data)
156 c_options->image.zoom_increment = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
159 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer data)
161 gint mins_secs_tenths, delay;
163 mins_secs_tenths = c_options->slideshow.delay %
164 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
166 delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
167 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
170 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
171 SLIDESHOW_SUBSECOND_PRECISION;
174 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer data)
176 gint hours, secs_tenths, delay;
178 hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
179 secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
181 delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
182 (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
183 (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
185 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
186 SLIDESHOW_SUBSECOND_PRECISION;
189 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer data)
191 gint hours_mins, delay;
193 hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
195 delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
196 (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
197 (gdouble)(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
199 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
200 SLIDESHOW_SUBSECOND_PRECISION;
204 *-----------------------------------------------------------------------------
205 * sync progam to config window routine (private)
206 *-----------------------------------------------------------------------------
209 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
215 buf = gtk_entry_get_text(GTK_ENTRY(entry));
216 if (buf && strlen(buf) > 0)
221 *option = g_strdup(buf);
226 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
228 gchar *accel_path, *accel;
230 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
232 if (accel_path && accel_path[0])
235 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
236 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
246 static void config_window_apply(void)
248 gboolean refresh = FALSE;
253 config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
255 if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
256 if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
257 if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
258 if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
259 if (options->file_sort.natural != c_options->file_sort.natural) refresh = TRUE;
260 if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
261 if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
263 options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
264 options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
265 options->file_ops.confirm_move_to_trash = c_options->file_ops.confirm_move_to_trash;
266 options->file_ops.use_system_trash = c_options->file_ops.use_system_trash;
267 options->file_ops.no_trash = c_options->file_ops.no_trash;
268 options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
269 options->tools_restore_state = c_options->tools_restore_state;
270 options->save_window_positions = c_options->save_window_positions;
271 options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
272 options->save_window_workspace = c_options->save_window_workspace;
273 options->save_dialog_window_positions = c_options->save_dialog_window_positions;
274 options->show_window_ids = c_options->show_window_ids;
275 options->image.scroll_reset_method = c_options->image.scroll_reset_method;
276 options->image.zoom_2pass = c_options->image.zoom_2pass;
277 options->image.fit_window_to_image = c_options->image.fit_window_to_image;
278 options->image.limit_window_size = c_options->image.limit_window_size;
279 options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
280 options->image.max_window_size = c_options->image.max_window_size;
281 options->image.limit_autofit_size = c_options->image.limit_autofit_size;
282 options->image.max_autofit_size = c_options->image.max_autofit_size;
283 options->image.max_enlargement_size = c_options->image.max_enlargement_size;
284 options->image.use_clutter_renderer = c_options->image.use_clutter_renderer;
285 options->progressive_key_scrolling = c_options->progressive_key_scrolling;
286 options->keyboard_scroll_step = c_options->keyboard_scroll_step;
288 if (options->thumbnails.max_width != c_options->thumbnails.max_width
289 || options->thumbnails.max_height != c_options->thumbnails.max_height
290 || options->thumbnails.quality != c_options->thumbnails.quality)
292 thumb_format_changed = TRUE;
294 options->thumbnails.max_width = c_options->thumbnails.max_width;
295 options->thumbnails.max_height = c_options->thumbnails.max_height;
296 options->thumbnails.quality = c_options->thumbnails.quality;
298 options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
299 options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
300 options->thumbnails.use_exif = c_options->thumbnails.use_exif;
301 options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
302 options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
303 // options->thumbnails.use_ft_metadata_small = c_options->thumbnails.use_ft_metadata_small;
304 options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
305 options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
306 options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
307 options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
308 options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
309 options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
311 options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
312 options->file_sort.natural = c_options->file_sort.natural;
313 options->file_filter.disable = c_options->file_filter.disable;
315 config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, NULL);
316 sidecar_ext_parse(options->sidecar.ext);
318 options->slideshow.random = c_options->slideshow.random;
319 options->slideshow.repeat = c_options->slideshow.repeat;
320 options->slideshow.delay = c_options->slideshow.delay;
322 options->mousewheel_scrolls = c_options->mousewheel_scrolls;
323 options->image_lm_click_nav = c_options->image_lm_click_nav;
324 options->image_l_click_video = c_options->image_l_click_video;
325 options->image_l_click_video_editor = c_options->image_l_click_video_editor;
327 options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
329 options->image.tile_cache_max = c_options->image.tile_cache_max;
330 options->image.image_cache_max = c_options->image.image_cache_max;
332 options->image.zoom_quality = c_options->image.zoom_quality;
334 options->image.zoom_increment = c_options->image.zoom_increment;
336 options->image.enable_read_ahead = c_options->image.enable_read_ahead;
339 if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
340 || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
341 || !gdk_color_equal(&options->image.border_color, &c_options->image.border_color))
343 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
344 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
345 options->image.border_color = c_options->image.border_color;
346 layout_colors_update();
347 view_window_colors_update();
350 options->image.alpha_color_1 = c_options->image.alpha_color_1;
351 options->image.alpha_color_2 = c_options->image.alpha_color_2;
353 options->fullscreen.screen = c_options->fullscreen.screen;
354 options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
355 options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
356 options->fullscreen.above = c_options->fullscreen.above;
357 if (c_options->image_overlay.template_string)
358 set_image_overlay_template_string(&options->image_overlay.template_string,
359 c_options->image_overlay.template_string);
360 if (c_options->image_overlay.font)
361 set_image_overlay_font_string(&options->image_overlay.font,
362 c_options->image_overlay.font);
363 options->image_overlay.text_red = c_options->image_overlay.text_red;
364 options->image_overlay.text_green = c_options->image_overlay.text_green;
365 options->image_overlay.text_blue = c_options->image_overlay.text_blue;
366 options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
367 options->image_overlay.background_red = c_options->image_overlay.background_red;
368 options->image_overlay.background_green = c_options->image_overlay.background_green;
369 options->image_overlay.background_blue = c_options->image_overlay.background_blue;
370 options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
371 options->update_on_time_change = c_options->update_on_time_change;
372 options->image.exif_proof_rotate_enable = c_options->image.exif_proof_rotate_enable;
374 options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
375 options->rot_invariant_sim = c_options->rot_invariant_sim;
377 options->tree_descend_subdirs = c_options->tree_descend_subdirs;
379 options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
381 options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
382 options->dnd_icon_size = c_options->dnd_icon_size;
383 options->clipboard_selection = c_options->clipboard_selection;
384 options->dnd_default_action = c_options->dnd_default_action;
386 options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
387 options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
388 options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
389 options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
390 options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
391 options->metadata.confirm_write = c_options->metadata.confirm_write;
392 options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
393 options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
394 options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
395 options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
396 options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
397 options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
398 options->metadata.write_orientation = c_options->metadata.write_orientation;
399 options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
400 (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
401 (c_options->stereo.tmp.flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
402 (c_options->stereo.tmp.mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
403 (c_options->stereo.tmp.flip_left ? PR_STEREO_FLIP_LEFT : 0) |
404 (c_options->stereo.tmp.swap ? PR_STEREO_SWAP : 0) |
405 (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
406 options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
407 (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
408 (c_options->stereo.tmp.fs_flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
409 (c_options->stereo.tmp.fs_mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
410 (c_options->stereo.tmp.fs_flip_left ? PR_STEREO_FLIP_LEFT : 0) |
411 (c_options->stereo.tmp.fs_swap ? PR_STEREO_SWAP : 0) |
412 (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
413 options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
414 options->stereo.fixed_w = c_options->stereo.fixed_w;
415 options->stereo.fixed_h = c_options->stereo.fixed_h;
416 options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
417 options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
418 options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
419 options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
421 options->info_keywords.height = c_options->info_keywords.height;
422 options->info_title.height = c_options->info_title.height;
423 options->info_comment.height = c_options->info_comment.height;
424 options->info_rating.height = c_options->info_rating.height;
426 options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
427 options->expand_menu_toolbar = c_options->expand_menu_toolbar;
429 options->marks_save = c_options->marks_save;
430 options->with_rename = c_options->with_rename;
431 options->collections_on_top = c_options->collections_on_top;
432 options->hide_window_in_fullscreen = c_options->hide_window_in_fullscreen;
433 config_entry_to_option(help_search_engine_entry, &options->help_search_engine, NULL);
435 options->read_metadata_in_idle = c_options->read_metadata_in_idle;
437 options->star_rating.star = c_options->star_rating.star;
438 options->star_rating.rejected = c_options->star_rating.rejected;
440 set_debug_level(debug_c);
444 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
446 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
447 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
449 config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
450 options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
451 if (options->color_profile.render_intent != c_options->color_profile.render_intent)
453 options->color_profile.render_intent = c_options->color_profile.render_intent;
458 options->mouse_button_8 = c_options->mouse_button_8;
459 options->mouse_button_9 = c_options->mouse_button_9;
461 options->override_disable_gpu = c_options->override_disable_gpu;
463 config_tab_keywords_save();
465 image_options_sync();
470 layout_refresh(NULL);
473 if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, NULL);
475 toolbar_apply(TOOLBAR_MAIN);
476 toolbar_apply(TOOLBAR_STATUS);
480 *-----------------------------------------------------------------------------
481 * config window main button callbacks (private)
482 *-----------------------------------------------------------------------------
485 static void config_window_close_cb(GtkWidget *widget, gpointer data)
487 gtk_widget_destroy(configwindow);
492 static void config_window_help_cb(GtkWidget *widget, gpointer data)
494 GtkWidget *notebook = data;
497 static gchar *html_section[] =
499 "GuideOptionsGeneral.html",
500 "GuideOptionsImage.html",
501 "GuideOptionsOSD.html",
502 "GuideOptionsWindow.html",
503 "GuideOptionsKeyboard.html",
504 "GuideOptionsFiltering.html",
505 "GuideOptionsMetadata.html",
506 "GuideOptionsKeywords.html",
507 "GuideOptionsColor.html",
508 "GuideOptionsStereo.html",
509 "GuideOptionsBehavior.html",
510 "GuideOptionsToolbar.html",
511 "GuideOptionsToolbar.html"
514 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
515 help_window_show(html_section[i]);
518 static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpointer data)
520 config_window_close_cb(NULL, NULL);
524 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
527 lw = layout_window_list->data;
529 config_window_apply();
530 layout_util_sync(lw);
531 save_options(options);
532 config_window_close_cb(NULL, NULL);
536 *-----------------------------------------------------------------------------
537 * config window setup (private)
538 *-----------------------------------------------------------------------------
541 static void quality_menu_cb(GtkWidget *combo, gpointer data)
545 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
549 *option = GDK_INTERP_NEAREST;
552 *option = GDK_INTERP_TILES;
555 *option = GDK_INTERP_BILINEAR;
560 static void dnd_default_action_selection_menu_cb(GtkWidget *combo, gpointer data)
564 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
568 *option = DND_ACTION_ASK;
571 *option = DND_ACTION_COPY;
574 *option = DND_ACTION_MOVE;
578 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
582 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
585 *option = CLIPBOARD_PRIMARY;
588 *option = CLIPBOARD_CLIPBOARD;
591 *option = CLIPBOARD_BOTH;
594 *option = CLIPBOARD_BOTH;
598 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
599 guint option, guint *option_c)
606 pref_table_label(table, column, row, text, 0.0);
608 combo = gtk_combo_box_text_new();
610 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
611 if (option == GDK_INTERP_NEAREST) current = 0;
612 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
613 if (option == GDK_INTERP_TILES) current = 1;
614 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear (best, but slowest)"));
615 if (option == GDK_INTERP_BILINEAR) current = 2;
617 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
619 g_signal_connect(G_OBJECT(combo), "changed",
620 G_CALLBACK(quality_menu_cb), option_c);
622 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
623 gtk_widget_show(combo);
626 static void add_dnd_default_action_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, DnDAction option, DnDAction *option_c)
633 pref_table_label(table, column, row, text, 0.0);
635 combo = gtk_combo_box_text_new();
637 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Ask"));
638 if (option == DND_ACTION_ASK) current = 0;
639 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Copy"));
640 if (option == DND_ACTION_COPY) current = 1;
641 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Move"));
642 if (option == DND_ACTION_MOVE) current = 2;
644 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
646 g_signal_connect(G_OBJECT(combo), "changed",
647 G_CALLBACK(dnd_default_action_selection_menu_cb), option_c);
649 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
650 gtk_widget_show(combo);
653 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
654 gint option, gint *option_c)
661 pref_table_label(table, column, row, text, 0.0);
663 combo = gtk_combo_box_text_new();
665 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Primary"));
666 if (option == CLIPBOARD_PRIMARY) current = 0;
667 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Clipboard"));
668 if (option == CLIPBOARD_CLIPBOARD) current = 1;
669 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Both"));
670 if (option == CLIPBOARD_BOTH) current = 2;
672 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
674 g_signal_connect(G_OBJECT(combo), "changed",
675 G_CALLBACK(clipboard_selection_menu_cb), option_c);
677 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
678 gtk_widget_show(combo);
681 typedef struct _UseableMouseItems UseableMouseItems;
682 struct _UseableMouseItems
684 gchar *name; /* GtkActionEntry terminology */
689 static const UseableMouseItems useable_mouse_items[] = {
691 {"FirstImage", N_("First Image"), GTK_STOCK_GOTO_TOP},
692 {"PrevImage", N_("Previous Image"), GTK_STOCK_GO_UP},
693 {"NextImage", N_("Next Image"), GTK_STOCK_GO_DOWN},
694 {"LastImage", N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
695 {"Back", N_("Back"), GTK_STOCK_GO_BACK},
696 {"Forward", N_("Forward"), GTK_STOCK_GO_FORWARD},
697 {"Home", N_("Home"), GTK_STOCK_HOME},
698 {"Up", N_("Up"), GTK_STOCK_GO_UP},
699 {"FirstPage", N_("First page"), GTK_STOCK_MEDIA_PREVIOUS},
700 {"LastPage", N_("Last Page"), GTK_STOCK_MEDIA_NEXT},
701 {"NextPage", N_("Next page"), GTK_STOCK_MEDIA_FORWARD},
702 {"PrevPage", N_("Previous Page"), GTK_STOCK_MEDIA_REWIND},
703 {"NewWindow", N_("New _window"), GTK_STOCK_NEW},
704 {"NewCollection", N_("New collection"), GTK_STOCK_INDEX},
705 {"OpenCollection", N_("Open collection"), GTK_STOCK_OPEN},
706 {"Search", N_("Search"), GTK_STOCK_FIND},
707 {"FindDupes", N_("Find duplicates"), GTK_STOCK_FIND},
708 {"NewFolder", N_("New folder"),GTK_STOCK_DIRECTORY},
709 {"Copy", N_("Copy"), GTK_STOCK_COPY},
710 {"Move", N_("Move"), PIXBUF_INLINE_ICON_MOVE},
711 {"Rename", N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
712 {"Delete", N_("Delete"), GTK_STOCK_DELETE},
713 {"CloseWindow", N_("Close Window"), GTK_STOCK_CLOSE},
714 {"PanView", N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
715 {"SelectAll", N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
716 {"SelectNone", N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
717 {"SelectInvert", N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
718 {"ShowFileFilter", N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
719 {"RectangularSelection", N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
720 {"Print", N_("Print"), GTK_STOCK_PRINT},
721 {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
722 {"LayoutConfig", N_("Configure this window"), GTK_STOCK_PREFERENCES},
723 {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
724 {"RotateCW", N_("Rotate clockwise 90°"), PIXBUF_INLINE_ICON_CW},
725 {"RotateCCW", N_("Rotate counterclockwise 90°"), PIXBUF_INLINE_ICON_CCW},
726 {"Rotate180", N_("Rotate 180°"), PIXBUF_INLINE_ICON_180},
727 {"Mirror", N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
728 {"Flip", N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
729 {"AlterNone", N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
730 {"ZoomIn", N_("Zoom in"), GTK_STOCK_ZOOM_IN},
731 {"ZoomOut", N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
732 {"Zoom100", N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
733 {"ZoomFit", N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
734 {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
735 {"ZoomFillVert", N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
736 {"Zoom200", N_("Zoom 2:1"), GTK_STOCK_FILE},
737 {"Zoom300", N_("Zoom 3:1"), GTK_STOCK_FILE},
738 {"Zoom400", N_("Zoom 4:1"), GTK_STOCK_FILE},
739 {"Zoom50", N_("Zoom 1:2"), GTK_STOCK_FILE},
740 {"Zoom33", N_("Zoom1:3"), GTK_STOCK_FILE},
741 {"Zoom25", N_("Zoom 1:4"), GTK_STOCK_FILE},
742 {"ConnectZoomIn", N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
743 {"SplitPaneSync", N_("Split Pane Sync"), PIXBUF_INLINE_SPLIT_PANE_SYNC},
744 {"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
745 {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
746 {"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
747 {"SlideShowPause", N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
748 {"SlideShowFaster", N_("Slideshow Faster"), GTK_STOCK_FILE},
749 {"SlideShowSlower", N_("Slideshow Slower"), GTK_STOCK_FILE},
750 {"Refresh", N_("Refresh"), GTK_STOCK_REFRESH},
751 {"HelpContents", N_("Help"), GTK_STOCK_HELP},
752 {"ExifWin", N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
753 {"Thumbnails", N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
754 {"ShowMarks", N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
755 {"ImageGuidelines", N_("Show guidelines"), PIXBUF_INLINE_ICON_GUIDELINES},
756 {"DrawRectangle", N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
757 {"FloatTools", N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
758 {"SBar", N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
759 {"SBarSort", N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
760 {"Quit", N_("Quit"), GTK_STOCK_QUIT},
764 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
766 gchar **option = data;
769 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
771 const UseableMouseItems *list = useable_mouse_items;
775 if (g_strcmp0(list->label, label) == 0)
783 *option = g_strdup(list->name);
787 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
788 gchar *option, gchar **option_c)
796 pref_table_label(table, column, row, text, 0.0);
798 combo = gtk_combo_box_text_new();
800 const UseableMouseItems *list = useable_mouse_items;
804 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
805 if (g_strcmp0(list->name, option) == 0)
813 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
815 g_signal_connect(G_OBJECT(combo), "changed",
816 G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
818 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
819 gtk_widget_show(combo);
822 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
826 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
829 if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
831 c_options->thumbnails.max_width = thumb_size_list[n].w;
832 c_options->thumbnails.max_height = thumb_size_list[n].h;
836 c_options->thumbnails.max_width = options->thumbnails.max_width;
837 c_options->thumbnails.max_height = options->thumbnails.max_height;
841 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
847 c_options->thumbnails.max_width = options->thumbnails.max_width;
848 c_options->thumbnails.max_height = options->thumbnails.max_height;
850 pref_table_label(table, column, row, text, 0.0);
852 combo = gtk_combo_box_text_new();
855 for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
860 w = thumb_size_list[i].w;
861 h = thumb_size_list[i].h;
863 buf = g_strdup_printf("%d x %d", w, h);
864 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
867 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
874 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
875 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
881 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
882 g_signal_connect(G_OBJECT(combo), "changed",
883 G_CALLBACK(thumb_size_menu_cb), NULL);
885 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
886 gtk_widget_show(combo);
889 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
893 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
897 *option = PR_STEREO_NONE;
900 *option = PR_STEREO_ANAGLYPH_RC;
903 *option = PR_STEREO_ANAGLYPH_GM;
906 *option = PR_STEREO_ANAGLYPH_YB;
909 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
912 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
915 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
918 *option = PR_STEREO_ANAGLYPH_DB_RC;
921 *option = PR_STEREO_ANAGLYPH_DB_GM;
924 *option = PR_STEREO_ANAGLYPH_DB_YB;
927 *option = PR_STEREO_HORIZ;
930 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
933 *option = PR_STEREO_VERT;
936 *option = PR_STEREO_VERT | PR_STEREO_HALF;
939 *option = PR_STEREO_FIXED;
944 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
945 gint option, gint *option_c, gboolean add_fixed)
952 pref_table_label(table, column, row, text, 0.0);
954 combo = gtk_combo_box_text_new();
956 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
958 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
959 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
960 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
961 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
962 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
963 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
964 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
965 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
966 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
967 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
968 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
969 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
970 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
971 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
972 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
973 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
974 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
975 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
977 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
978 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
979 if (option & PR_STEREO_HORIZ)
982 if (option & PR_STEREO_HALF) current = 11;
985 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
986 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
987 if (option & PR_STEREO_VERT)
990 if (option & PR_STEREO_HALF) current = 13;
995 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
996 if (option & PR_STEREO_FIXED) current = 14;
999 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1001 g_signal_connect(G_OBJECT(combo), "changed",
1002 G_CALLBACK(stereo_mode_menu_cb), option_c);
1004 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1005 gtk_widget_show(combo);
1008 static void video_menu_cb(GtkWidget *combo, gpointer data)
1010 gchar **option = data;
1012 EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
1016 static void video_menu_populate(gpointer data, gpointer user_data)
1018 GtkWidget *combo = user_data;
1019 EditorDescription *ed = data;
1021 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1024 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1025 gchar *option, gchar **option_c)
1029 /* use lists since they are sorted */
1030 GList *eds = editor_list_get();
1034 pref_table_label(table, column, row, text, 0.0);
1036 combo = gtk_combo_box_text_new();
1037 g_list_foreach(eds,video_menu_populate,(gpointer)combo);
1038 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1040 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1042 g_signal_connect(G_OBJECT(combo), "changed",
1043 G_CALLBACK(video_menu_cb), option_c);
1045 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1046 gtk_widget_show(combo);
1049 static void filter_store_populate(void)
1053 if (!filter_store) return;
1055 gtk_list_store_clear(filter_store);
1057 work = filter_get_list();
1066 gtk_list_store_append(filter_store, &iter);
1067 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1071 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1072 gchar *new_text, gpointer data)
1074 GtkWidget *model = data;
1075 FilterEntry *fe = data;
1079 if (!new_text || strlen(new_text) < 1) return;
1081 tpath = gtk_tree_path_new_from_string(path_str);
1082 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1083 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1085 g_free(fe->extensions);
1086 fe->extensions = g_strdup(new_text);
1088 gtk_tree_path_free(tpath);
1092 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1093 gchar *new_text, gpointer data)
1095 GtkWidget *model = data;
1096 FilterEntry *fe = data;
1101 if (!new_text || !new_text[0]) return;
1103 tpath = gtk_tree_path_new_from_string(path_str);
1104 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1105 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1107 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1109 if (strcmp(new_text, _(format_class_list[i])) == 0)
1116 gtk_tree_path_free(tpath);
1120 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1121 gchar *new_text, gpointer data)
1123 GtkWidget *model = data;
1128 if (!new_text || !new_text[0]) return;
1130 tpath = gtk_tree_path_new_from_string(path_str);
1131 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1132 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1134 g_free(fe->description);
1135 fe->description = g_strdup(new_text);
1137 gtk_tree_path_free(tpath);
1140 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
1141 gchar *path_str, gpointer data)
1143 GtkWidget *model = data;
1148 tpath = gtk_tree_path_new_from_string(path_str);
1149 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1150 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1152 fe->enabled = !fe->enabled;
1154 gtk_tree_path_free(tpath);
1158 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
1159 gchar *path_str, gpointer data)
1161 GtkWidget *model = data;
1166 tpath = gtk_tree_path_new_from_string(path_str);
1167 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1168 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1170 fe->writable = !fe->writable;
1171 if (fe->writable) fe->allow_sidecar = FALSE;
1173 gtk_tree_path_free(tpath);
1177 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
1178 gchar *path_str, gpointer data)
1180 GtkWidget *model = data;
1185 tpath = gtk_tree_path_new_from_string(path_str);
1186 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1187 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1189 fe->allow_sidecar = !fe->allow_sidecar;
1190 if (fe->allow_sidecar) fe->writable = FALSE;
1192 gtk_tree_path_free(tpath);
1196 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1197 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1201 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1203 switch (GPOINTER_TO_INT(data))
1206 g_object_set(GTK_CELL_RENDERER(cell),
1207 "active", fe->enabled, NULL);
1210 g_object_set(GTK_CELL_RENDERER(cell),
1211 "text", fe->extensions, NULL);
1213 case FE_DESCRIPTION:
1214 g_object_set(GTK_CELL_RENDERER(cell),
1215 "text", fe->description, NULL);
1218 g_object_set(GTK_CELL_RENDERER(cell),
1219 "text", _(format_class_list[fe->file_class]), NULL);
1222 g_object_set(GTK_CELL_RENDERER(cell),
1223 "active", fe->writable, NULL);
1225 case FE_ALLOW_SIDECAR:
1226 g_object_set(GTK_CELL_RENDERER(cell),
1227 "active", fe->allow_sidecar, NULL);
1232 static gboolean filter_add_scroll(gpointer data)
1236 GtkCellRenderer *cell;
1237 GtkTreeViewColumn *column;
1240 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1241 path = gtk_tree_path_new_from_indices(rows-1, -1);
1243 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1245 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1246 cell = g_list_last(list_cells)->data;
1248 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1249 path, column, FALSE, 0.0, 0.0 );
1250 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1251 path, column, cell, TRUE);
1253 gtk_tree_path_free(path);
1254 g_list_free(list_cells);
1259 static void filter_add_cb(GtkWidget *widget, gpointer data)
1261 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1262 filter_store_populate();
1264 g_idle_add((GSourceFunc)filter_add_scroll, data);
1267 static void filter_remove_cb(GtkWidget *widget, gpointer data)
1269 GtkWidget *filter_view = data;
1270 GtkTreeSelection *selection;
1274 if (!filter_store) return;
1275 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1276 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1277 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1280 filter_remove_entry(fe);
1282 filter_store_populate();
1285 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1289 GtkTreeViewColumn *column;
1291 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1292 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1293 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1295 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1299 gtk_tree_path_free(path);
1304 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
1307 filter_add_defaults();
1309 filter_store_populate();
1311 g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1314 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1316 /* no op, only so cancel button appears */
1319 static void filter_default_cb(GtkWidget *widget, gpointer data)
1323 gd = generic_dialog_new(_("Reset filters"),
1324 "reset_filter", widget, TRUE,
1325 dummy_cancel_cb, data);
1326 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1327 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1328 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1329 gtk_widget_show(gd->dialog);
1332 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1334 GtkWidget *frame = data;
1336 gtk_widget_set_sensitive(frame,
1337 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1340 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
1342 layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1345 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
1347 file_util_trash_clear();
1350 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
1354 gd = generic_dialog_new(_("Clear trash"),
1355 "clear_trash", widget, TRUE,
1356 dummy_cancel_cb, NULL);
1357 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1358 _("This will remove the trash contents."), FALSE);
1359 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1360 entry = gtk_entry_new();
1361 gtk_widget_set_can_focus(entry, FALSE);
1362 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1363 if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1364 gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1365 gtk_widget_show(entry);
1366 gtk_widget_show(gd->dialog);
1369 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
1371 GtkWidget *pTextView;
1372 GtkTextBuffer *pTextBuffer;
1376 pTextView = GTK_WIDGET(data);
1378 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1379 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1380 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1382 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1383 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1386 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
1388 GtkTextView *text_view = data;
1389 GtkTextBuffer *buffer;
1391 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1392 if (!configwindow) return;
1394 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1395 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1398 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1402 gd = generic_dialog_new(_("Reset image overlay template string"),
1403 "reset_image_overlay_template_string", widget, TRUE,
1404 dummy_cancel_cb, data);
1405 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1406 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1407 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1408 gtk_widget_show(gd->dialog);
1411 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
1413 help_window_show("GuideOptionsOSD.html");
1416 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer data)
1418 #if GTK_CHECK_VERSION(3,4,0)
1421 PangoFontDescription *font_desc;
1423 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1424 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1426 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1428 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1429 font = pango_font_description_to_string(font_desc);
1430 g_free(c_options->image_overlay.font);
1431 c_options->image_overlay.font = g_strdup(font);
1435 gtk_widget_destroy(dialog);
1439 font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
1440 c_options->image_overlay.font = g_strdup(font);
1444 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer data)
1447 #if GTK_CHECK_VERSION(3,4,0)
1450 dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1451 colour.red = options->image_overlay.text_red;
1452 colour.green = options->image_overlay.text_green;
1453 colour.blue = options->image_overlay.text_blue;
1454 colour.alpha = options->image_overlay.text_alpha;
1455 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1456 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1458 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1460 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1461 c_options->image_overlay.text_red = colour.red*255;
1462 c_options->image_overlay.text_green = colour.green*255;
1463 c_options->image_overlay.text_blue = colour.blue*255;
1464 c_options->image_overlay.text_alpha = colour.alpha*255;
1466 gtk_widget_destroy(dialog);
1469 GtkColorSelection *colorsel;
1471 dialog = gtk_color_selection_dialog_new("Image Overlay Text Colour");
1472 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1473 colour.red = options->image_overlay.text_red*257;
1474 colour.green = options->image_overlay.text_green*257;
1475 colour.blue = options->image_overlay.text_blue*257;
1476 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1477 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1478 gtk_color_selection_set_current_color(colorsel, &colour);
1479 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.text_alpha*257);
1481 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1483 gtk_color_selection_get_current_color(colorsel, &colour);
1484 c_options->image_overlay.text_red = colour.red/257;
1485 c_options->image_overlay.text_green = colour.green/257;
1486 c_options->image_overlay.text_blue = colour.blue/257;
1487 c_options->image_overlay.text_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1489 gtk_widget_destroy (dialog);
1494 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer data)
1497 #if GTK_CHECK_VERSION(3,4,0)
1500 dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1501 colour.red = options->image_overlay.background_red;
1502 colour.green = options->image_overlay.background_green;
1503 colour.blue = options->image_overlay.background_blue;
1504 colour.alpha = options->image_overlay.background_alpha;
1505 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1506 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1508 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1510 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1511 c_options->image_overlay.background_red = colour.red*255;
1512 c_options->image_overlay.background_green = colour.green*255;
1513 c_options->image_overlay.background_blue = colour.blue*255;
1514 c_options->image_overlay.background_alpha = colour.alpha*255;
1516 gtk_widget_destroy(dialog);
1519 GtkColorSelection *colorsel;
1521 dialog = gtk_color_selection_dialog_new("Image Overlay Background Colour");
1522 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1523 colour.red = options->image_overlay.background_red*257;
1524 colour.green = options->image_overlay.background_green*257;
1525 colour.blue = options->image_overlay.background_blue*257;
1526 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1527 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1528 gtk_color_selection_set_current_color(colorsel, &colour);
1529 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.background_alpha*257);
1531 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1533 gtk_color_selection_get_current_color(colorsel, &colour);
1534 c_options->image_overlay.background_red = colour.red/257;
1535 c_options->image_overlay.background_green = colour.green/257;
1536 c_options->image_overlay.background_blue = colour.blue/257;
1537 c_options->image_overlay.background_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1539 gtk_widget_destroy(dialog);
1543 static void accel_store_populate(void)
1546 GList *groups, *actions;
1548 const gchar *accel_path;
1552 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1554 gtk_tree_store_clear(accel_store);
1555 lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
1557 g_assert(lw && lw->ui_manager);
1558 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1561 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1564 action = GTK_ACTION(actions->data);
1565 accel_path = gtk_action_get_accel_path(action);
1566 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1568 gchar *label, *label2, *tooltip, *accel;
1569 g_object_get(action,
1570 "tooltip", &tooltip,
1574 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1580 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1584 gtk_tree_store_append(accel_store, &iter, NULL);
1585 gtk_tree_store_set(accel_store, &iter,
1588 AE_TOOLTIP, tooltip ? tooltip : "",
1589 AE_ACCEL, accel_path,
1597 actions = actions->next;
1600 groups = groups->next;
1604 static void accel_store_cleared_cb(GtkCellRendererAccel *accel, gchar *path_string, gpointer user_data)
1609 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1611 gchar *accel1 = data;
1616 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1618 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1619 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1621 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1623 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1624 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1633 static void accel_store_edited_cb(GtkCellRendererAccel *accel, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode, gpointer user_data)
1635 GtkTreeModel *model = (GtkTreeModel *)accel_store;
1639 GtkAccelKey old_key, key;
1640 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1642 gtk_tree_model_get_iter(model, &iter, path);
1643 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1645 /* test if the accelerator can be stored without conflicts*/
1646 gtk_accel_map_lookup_entry(accel_path, &old_key);
1648 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1649 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1650 gtk_accel_map_lookup_entry(accel_path, &key);
1652 /* restore the original for now, the key will be really changed when the changes are confirmed */
1653 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1655 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1656 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1658 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1659 gtk_tree_path_free(path);
1663 static gboolean accel_default_scroll(GtkTreeView *data)
1667 GtkTreeViewColumn *column;
1669 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1670 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1671 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1673 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1677 gtk_tree_path_free(path);
1682 static void accel_default_cb(GtkWidget *widget, gpointer data)
1684 accel_store_populate();
1686 g_idle_add((GSourceFunc)accel_default_scroll, data);
1689 void accel_remove_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1691 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1694 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1697 gchar *accel_path, *accel;
1699 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1700 gtk_accel_map_lookup_entry(accel_path, &key);
1701 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1703 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1705 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1710 static void accel_reset_cb(GtkWidget *widget, gpointer data)
1712 GtkTreeSelection *selection;
1714 if (!accel_store) return;
1715 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1716 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1721 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1725 GtkWidget *scrolled;
1726 GtkWidget *viewport;
1728 scrolled = gtk_scrolled_window_new(NULL, NULL);
1729 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1730 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1731 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1732 label = gtk_label_new(title);
1733 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1734 gtk_widget_show(scrolled);
1736 viewport = gtk_viewport_new(NULL, NULL);
1737 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1738 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1739 gtk_widget_show(viewport);
1741 vbox = gtk_vbox_new(FALSE, 0);
1742 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1743 gtk_widget_show(vbox);
1748 static void cache_standard_cb(GtkWidget *widget, gpointer data)
1750 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1752 c_options->thumbnails.spec_standard =TRUE;
1753 c_options->thumbnails.cache_into_dirs = FALSE;
1757 static void cache_geeqie_cb(GtkWidget *widget, gpointer data)
1759 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1761 c_options->thumbnails.spec_standard =FALSE;
1762 c_options->thumbnails.cache_into_dirs = FALSE;
1766 static void cache_local_cb(GtkWidget *widget, gpointer data)
1768 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1770 c_options->thumbnails.cache_into_dirs = TRUE;
1771 c_options->thumbnails.spec_standard =FALSE;
1775 static void help_search_engine_entry_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1776 GdkEvent *event, gpointer userdata)
1778 if (pos == GTK_ENTRY_ICON_PRIMARY)
1780 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1784 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1788 static void star_rating_star_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1789 GdkEvent *event, gpointer userdata)
1791 gchar *rating_symbol;
1793 if (pos == GTK_ENTRY_ICON_PRIMARY)
1795 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1796 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1797 g_free(rating_symbol);
1801 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1802 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1803 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1807 static void star_rating_rejected_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1808 GdkEvent *event, gpointer userdata)
1810 gchar *rating_symbol;
1812 if (pos == GTK_ENTRY_ICON_PRIMARY)
1814 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1815 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1816 g_free(rating_symbol);
1820 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1821 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1822 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1826 static guint star_rating_symbol_test(GtkWidget *widget, gpointer data)
1828 GtkContainer *hbox = data;
1829 GString *str = g_string_new(NULL);
1830 GtkEntry *hex_code_entry;
1831 gchar *hex_code_full;
1834 guint64 hex_value = 0;
1836 list = gtk_container_get_children(hbox);
1838 hex_code_entry = g_list_nth_data(list, 2);
1839 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1841 hex_code = g_strsplit(hex_code_full, "+", 2);
1842 if (hex_code[0] && hex_code[1])
1844 hex_value = strtoull(hex_code[1], NULL, 16);
1846 if (!hex_value || hex_value > 0x10FFFF)
1848 hex_value = 0x003F; // Unicode 'Question Mark'
1850 str = g_string_append_unichar(str, (gunichar)hex_value);
1851 gtk_label_set_text(g_list_nth_data(list, 1), str->str);
1853 g_strfreev(hex_code);
1854 g_string_free(str, TRUE);
1855 g_free(hex_code_full);
1860 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1862 guint64 star_symbol;
1864 star_symbol = star_rating_symbol_test(widget, data);
1865 c_options->star_rating.star = star_symbol;
1868 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1870 guint64 rejected_symbol;
1872 rejected_symbol = star_rating_symbol_test(widget, data);
1873 c_options->star_rating.rejected = rejected_symbol;
1876 /* general options tab */
1877 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1878 typedef struct _TZData TZData;
1882 GCancellable *cancellable;
1884 GtkWidget *progress;
1886 GFile *timezone_database_gq;
1887 gchar *timezone_database_user;
1890 static void config_tab_general(GtkWidget *notebook)
1895 GtkWidget *group_frame;
1896 GtkWidget *subgroup;
1898 GtkWidget *ct_button;
1901 gint hours, minutes, remainder;
1903 GtkWidget *star_rating_entry;
1905 gchar *rating_symbol;
1908 GNetworkMonitor *net_mon;
1909 GSocketConnectable *geeqie_org;
1910 gboolean internet_available;
1913 vbox = scrolled_notebook_page(notebook, _("General"));
1915 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1917 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1918 add_thumb_size_menu(table, 0, 0, _("Size:"));
1919 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1921 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1922 pref_label_new(hbox, _("Custom size: "));
1923 pref_spin_new_int(hbox, _("Width:"), NULL, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
1924 pref_spin_new_int(hbox, _("Height:"), NULL, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
1926 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
1927 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1929 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1930 pref_checkbox_link_sensitivity(ct_button, subgroup);
1932 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
1933 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
1934 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
1935 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1936 button = pref_radiobutton_new(group_frame, NULL, get_thumbnails_cache_dir(),
1937 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1938 G_CALLBACK(cache_geeqie_cb), NULL);
1940 group_frame = pref_frame_new(subgroup, TRUE,
1941 _("Store thumbnails local to image folder (non-standard)"),
1942 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1943 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
1944 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
1945 G_CALLBACK(cache_local_cb), NULL);
1947 group_frame = pref_frame_new(subgroup, TRUE,
1948 _("Use standard thumbnail style and cache, shared with other applications"),
1949 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1950 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
1951 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1952 G_CALLBACK(cache_standard_cb), NULL);
1954 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
1955 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
1957 spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
1959 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
1960 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
1962 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
1963 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
1964 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
1966 // pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
1967 // options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
1970 pref_spacer(group, PREF_PAD_GROUP);
1972 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
1974 c_options->star_rating.star = options->star_rating.star;
1975 c_options->star_rating.rejected = options->star_rating.rejected;
1977 str = g_string_new(NULL);
1978 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1979 pref_label_new(hbox, "Star character: ");
1980 str = g_string_append_unichar(str, options->star_rating.star);
1981 pref_label_new(hbox, g_strdup(str->str));
1982 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
1983 star_rating_entry = gtk_entry_new();
1984 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
1985 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
1986 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
1987 gtk_widget_show(star_rating_entry);
1988 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
1989 G_CALLBACK(star_rating_star_test_cb), hbox);
1990 gtk_widget_set_tooltip_text(button, _("Display selected character"));
1991 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1992 gtk_widget_show(button);
1993 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."));
1994 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1995 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
1996 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
1997 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
1998 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1999 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2000 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2001 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2002 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2003 G_CALLBACK(star_rating_star_icon_cb),
2006 g_string_free(str, TRUE);
2007 g_free(rating_symbol);
2009 str = g_string_new(NULL);
2010 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2011 pref_label_new(hbox, "Rejected character: ");
2012 str = g_string_append_unichar(str, options->star_rating.rejected);
2013 pref_label_new(hbox, g_strdup(str->str));
2014 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2015 star_rating_entry = gtk_entry_new();
2016 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2017 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2018 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2019 gtk_widget_show(star_rating_entry);
2020 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2021 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2022 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2023 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2024 gtk_widget_show(button);
2025 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."));
2026 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2027 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2028 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2029 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2030 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2031 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2032 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2033 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2034 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2035 G_CALLBACK(star_rating_rejected_icon_cb),
2038 g_string_free(str, TRUE);
2039 g_free(rating_symbol);
2041 pref_spacer(group, PREF_PAD_GROUP);
2043 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2045 c_options->slideshow.delay = options->slideshow.delay;
2046 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2047 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2048 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2049 seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2050 SLIDESHOW_SUBSECOND_PRECISION;
2052 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2054 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2056 options->slideshow.delay ? hours : 0.0,
2057 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2058 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2059 spin = pref_spin_new(hbox, ":" , NULL,
2061 options->slideshow.delay ? minutes: 0.0,
2062 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2063 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2064 spin = pref_spin_new(hbox, ":", NULL,
2065 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2066 options->slideshow.delay ? seconds : 10.0,
2067 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2068 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2070 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2071 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2073 pref_spacer(group, PREF_PAD_GROUP);
2075 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2077 pref_spin_new_int(group, _("Decoded image cache size (Mb):"), NULL,
2078 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2079 pref_checkbox_new_int(group, _("Preload next image"),
2080 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2082 pref_checkbox_new_int(group, _("Refresh on file change"),
2083 options->update_on_time_change, &c_options->update_on_time_change);
2086 pref_spacer(group, PREF_PAD_GROUP);
2088 group = pref_group_new(vbox, FALSE, _("Expand menu and toolbar"), GTK_ORIENTATION_VERTICAL);
2090 pref_checkbox_new_int(group, _("Expand menu and toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2091 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2092 gtk_widget_set_tooltip_text(group, _("Expand the menu and toolbar to the full width of the window"));
2094 pref_spacer(group, PREF_PAD_GROUP);
2096 group = pref_group_new(vbox, FALSE, _("Info sidebar heights"), GTK_ORIENTATION_VERTICAL);
2097 pref_label_new(group, _("NOTE! Geeqie must be restarted for changes to take effect"));
2098 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2099 pref_spin_new_int(hbox, _("Keywords:"), NULL,
2101 options->info_keywords.height, &c_options->info_keywords.height);
2102 pref_spin_new_int(hbox, _("Title:"), NULL,
2104 options->info_title.height, &c_options->info_title.height);
2105 pref_spin_new_int(hbox, _("Comment:"), NULL,
2107 options->info_comment.height, &c_options->info_comment.height);
2108 pref_spin_new_int(hbox, _("Rating:"), NULL,
2110 options->info_rating.height, &c_options->info_rating.height);
2112 pref_spacer(group, PREF_PAD_GROUP);
2114 group = pref_group_new(vbox, FALSE, _("Show predefined keyword tree"), GTK_ORIENTATION_VERTICAL);
2116 pref_checkbox_new_int(group, _("Show predefined keyword tree (NOTE! Geeqie must be restarted for change to take effect)"),
2117 options->show_predefined_keyword_tree, &c_options->show_predefined_keyword_tree);
2119 pref_spacer(group, PREF_PAD_GROUP);
2121 net_mon = g_network_monitor_get_default();
2122 geeqie_org = g_network_address_parse_uri(GQ_WEBSITE, 80, NULL);
2123 internet_available = g_network_monitor_can_reach(net_mon, geeqie_org, NULL, NULL);
2124 g_object_unref(geeqie_org);
2126 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2127 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2129 if (!internet_available)
2131 gtk_widget_set_sensitive(group, FALSE);
2134 tz = g_new0(TZData, 1);
2136 path = path_from_utf8(TIMEZONE_DATABASE);
2137 basename = g_path_get_basename(path);
2138 tz->timezone_database_user = g_build_filename(get_rc_dir(), basename, NULL);
2142 if (isfile(tz->timezone_database_user))
2144 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2148 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2151 if (!internet_available)
2153 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"));
2157 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"));
2159 gtk_widget_show(button);
2161 pref_spacer(group, PREF_PAD_GROUP);
2163 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2165 help_search_engine_entry = gtk_entry_new();
2166 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2167 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2168 gtk_widget_show(help_search_engine_entry);
2170 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"));
2172 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2173 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2174 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2175 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2176 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2177 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2178 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2179 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2180 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2181 G_CALLBACK(help_search_engine_entry_icon_cb),
2182 help_search_engine_entry);
2186 static void config_tab_image(GtkWidget *notebook)
2191 GtkWidget *ct_button;
2192 GtkWidget *enlargement_button;
2195 GtkWidget *two_pass;
2197 GtkWidget *gpu_accel;
2200 vbox = scrolled_notebook_page(notebook, _("Image"));
2202 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2204 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2205 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2206 if (options->image.use_clutter_renderer && !options->disable_gpu)
2208 gtk_widget_set_sensitive(table, FALSE);
2212 gpu_accel = pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library (Requires restart)"),
2213 options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2214 if (options->disable_gpu && !options->override_disable_gpu)
2216 gtk_widget_set_sensitive(gpu_accel, FALSE);
2220 two_pass = pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2221 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2222 if (options->image.use_clutter_renderer && !options->disable_gpu)
2224 gtk_widget_set_sensitive(two_pass, FALSE);
2227 c_options->image.zoom_increment = options->image.zoom_increment;
2228 spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2229 0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2230 G_CALLBACK(zoom_increment_cb), NULL);
2231 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2233 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2235 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2236 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2237 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2238 spin = pref_spin_new_int(hbox, NULL, NULL,
2240 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2241 pref_checkbox_link_sensitivity(enlargement_button, spin);
2242 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."));
2244 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2245 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2246 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2247 spin = pref_spin_new_int(hbox, NULL, NULL,
2249 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2250 pref_checkbox_link_sensitivity(ct_button, spin);
2251 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."));
2253 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2255 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2256 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2258 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2259 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2261 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2262 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2264 c_options->image.border_color = options->image.border_color;
2266 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2267 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2269 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2270 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2272 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2273 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2275 group = pref_group_new(vbox, FALSE, _("Convenience"), GTK_ORIENTATION_VERTICAL);
2277 pref_checkbox_new_int(group, _("Auto rotate proofs using Exif information"),
2278 options->image.exif_proof_rotate_enable, &c_options->image.exif_proof_rotate_enable);
2282 static void config_tab_windows(GtkWidget *notebook)
2288 GtkWidget *ct_button;
2291 vbox = scrolled_notebook_page(notebook, _("Windows"));
2293 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2295 ct_button = pref_checkbox_new_int(group, _("Remember window positions"),
2296 options->save_window_positions, &c_options->save_window_positions);
2298 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2299 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2300 pref_checkbox_link_sensitivity(ct_button, button);
2302 button = pref_checkbox_new_int(group, _("Remember window workspace"),
2303 options->save_window_workspace, &c_options->save_window_workspace);
2304 pref_checkbox_link_sensitivity(ct_button, button);
2306 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2307 options->tools_restore_state, &c_options->tools_restore_state);
2309 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2310 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2312 pref_checkbox_new_int(group, _("Show window IDs"),
2313 options->show_window_ids, &c_options->show_window_ids);
2315 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2317 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2318 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2320 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2321 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2322 options->image.limit_window_size, &c_options->image.limit_window_size);
2323 spin = pref_spin_new_int(hbox, NULL, NULL,
2325 options->image.max_window_size, &c_options->image.max_window_size);
2326 pref_checkbox_link_sensitivity(ct_button, spin);
2328 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2330 c_options->fullscreen.screen = options->fullscreen.screen;
2331 c_options->fullscreen.above = options->fullscreen.above;
2332 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2333 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2334 gtk_widget_show(hbox);
2336 pref_checkbox_new_int(group, _("Smooth image flip"),
2337 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2338 pref_checkbox_new_int(group, _("Disable screen saver"),
2339 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2342 #define PRE_FORMATTED_COLUMNS 5
2343 static void config_tab_osd(GtkWidget *notebook)
2349 GtkWidget *image_overlay_template_view;
2350 GtkWidget *scrolled;
2351 GtkWidget *scrolled_pre_formatted;
2352 GtkTextBuffer *buffer;
2354 GtkWidget *subgroup;
2356 vbox = scrolled_notebook_page(notebook, _("OSD"));
2358 image_overlay_template_view = gtk_text_view_new();
2360 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2362 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2364 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2365 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2366 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2367 gtk_widget_show(scrolled_pre_formatted);
2368 gtk_widget_show(subgroup);
2370 pref_line(group, PREF_PAD_GAP);
2372 pref_label_new(group, _("Image overlay template"));
2374 scrolled = gtk_scrolled_window_new(NULL, NULL);
2375 gtk_widget_set_size_request(scrolled, 200, 150);
2376 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2377 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2378 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2379 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2380 gtk_widget_show(scrolled);
2382 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2383 _("Extensive formatting options are shown in the Help file"));
2385 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2386 gtk_widget_show(image_overlay_template_view);
2388 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2390 #if GTK_CHECK_VERSION(3,4,0)
2391 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2392 G_CALLBACK(image_overlay_set_font_cb), notebook);
2394 button = gtk_font_button_new();
2395 gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
2396 gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
2397 g_signal_connect(G_OBJECT(button), "font-set",
2398 G_CALLBACK(image_overlay_set_font_cb),NULL);
2400 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2401 gtk_widget_show(button);
2403 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2404 G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2405 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2406 gtk_widget_show(button);
2408 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2409 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2410 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2411 gtk_widget_show(button);
2412 image_overlay_set_text_colours();
2414 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2415 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2416 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2417 gtk_widget_show(button);
2419 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2420 G_CALLBACK(image_overlay_help_cb), NULL);
2421 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2422 gtk_widget_show(button);
2424 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2425 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2426 g_signal_connect(G_OBJECT(buffer), "changed",
2427 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2429 pref_line(group, PREF_PAD_GAP);
2431 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2432 hbox = gtk_hbox_new(FALSE, 0);
2433 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2434 gtk_widget_show(hbox);
2435 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2436 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2437 gtk_widget_show(label);
2438 pref_spacer(group,TRUE);
2440 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2441 hbox = gtk_hbox_new(FALSE, 0);
2442 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2443 gtk_widget_show(hbox);
2444 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2445 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2446 gtk_widget_show(label);
2447 pref_spacer(group,TRUE);
2449 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2450 hbox = gtk_hbox_new(FALSE, 0);
2451 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2452 gtk_widget_show(hbox);
2453 label = gtk_label_new(_("%path:39%"));
2454 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2455 gtk_widget_show(label);
2456 pref_spacer(group,TRUE);
2458 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2459 hbox = gtk_hbox_new(FALSE, 0);
2460 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2461 gtk_widget_show(hbox);
2462 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%"));
2463 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2464 gtk_widget_show(label);
2465 pref_spacer(group,TRUE);
2467 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2468 hbox = gtk_hbox_new(FALSE, 0);
2469 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2470 gtk_widget_show(hbox);
2471 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2472 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2473 gtk_widget_show(label);
2476 static GtkTreeModel *create_class_model(void)
2478 GtkListStore *model;
2482 /* create list store */
2483 model = gtk_list_store_new(1, G_TYPE_STRING);
2484 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2486 gtk_list_store_append(model, &iter);
2487 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2489 return GTK_TREE_MODEL (model);
2494 static void config_tab_files(GtkWidget *notebook)
2501 GtkWidget *ct_button;
2502 GtkWidget *scrolled;
2503 GtkWidget *filter_view;
2504 GtkCellRenderer *renderer;
2505 GtkTreeSelection *selection;
2506 GtkTreeViewColumn *column;
2508 vbox = scrolled_notebook_page(notebook, _("Files"));
2510 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2512 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2513 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2514 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2515 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2516 pref_checkbox_new_int(group, _("Case sensitive sort"),
2517 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2518 pref_checkbox_new_int(group, _("Natural sort order"),
2519 options->file_sort.natural, &c_options->file_sort.natural);
2520 pref_checkbox_new_int(group, _("Disable file extension checks"),
2521 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2523 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2524 options->file_filter.disable, &c_options->file_filter.disable);
2527 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2529 sidecar_ext_entry = gtk_entry_new();
2530 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2531 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2532 gtk_widget_show(sidecar_ext_entry);
2534 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2536 frame = pref_group_parent(group);
2537 g_signal_connect(G_OBJECT(ct_button), "toggled",
2538 G_CALLBACK(filter_disable_cb), frame);
2539 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2541 scrolled = gtk_scrolled_window_new(NULL, NULL);
2542 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2543 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2544 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2545 gtk_widget_show(scrolled);
2547 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2548 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2549 g_object_unref(filter_store);
2550 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2551 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2553 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2555 column = gtk_tree_view_column_new();
2556 gtk_tree_view_column_set_title(column, _("Filter"));
2557 gtk_tree_view_column_set_resizable(column, TRUE);
2559 renderer = gtk_cell_renderer_toggle_new();
2560 g_signal_connect(G_OBJECT(renderer), "toggled",
2561 G_CALLBACK(filter_store_enable_cb), filter_store);
2562 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2563 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2564 GINT_TO_POINTER(FE_ENABLE), NULL);
2566 renderer = gtk_cell_renderer_text_new();
2567 g_signal_connect(G_OBJECT(renderer), "edited",
2568 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2569 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2570 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2571 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2572 GINT_TO_POINTER(FE_EXTENSION), NULL);
2573 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2575 column = gtk_tree_view_column_new();
2576 gtk_tree_view_column_set_title(column, _("Description"));
2577 gtk_tree_view_column_set_resizable(column, TRUE);
2578 gtk_tree_view_column_set_fixed_width(column, 200);
2579 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2581 renderer = gtk_cell_renderer_text_new();
2582 g_signal_connect(G_OBJECT(renderer), "edited",
2583 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2584 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2585 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2586 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2587 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2588 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2590 column = gtk_tree_view_column_new();
2591 gtk_tree_view_column_set_title(column, _("Class"));
2592 gtk_tree_view_column_set_resizable(column, TRUE);
2593 renderer = gtk_cell_renderer_combo_new();
2594 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2595 "model", create_class_model(),
2600 g_signal_connect(G_OBJECT(renderer), "edited",
2601 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2602 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2603 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2604 GINT_TO_POINTER(FE_CLASS), NULL);
2605 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2607 column = gtk_tree_view_column_new();
2608 gtk_tree_view_column_set_title(column, _("Writable"));
2609 gtk_tree_view_column_set_resizable(column, FALSE);
2610 renderer = gtk_cell_renderer_toggle_new();
2611 g_signal_connect(G_OBJECT(renderer), "toggled",
2612 G_CALLBACK(filter_store_writable_cb), filter_store);
2613 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2614 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2615 GINT_TO_POINTER(FE_WRITABLE), NULL);
2616 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2618 column = gtk_tree_view_column_new();
2619 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2620 gtk_tree_view_column_set_resizable(column, FALSE);
2621 renderer = gtk_cell_renderer_toggle_new();
2622 g_signal_connect(G_OBJECT(renderer), "toggled",
2623 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2624 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2625 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2626 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2627 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2630 filter_store_populate();
2631 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2632 gtk_widget_show(filter_view);
2634 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2636 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2637 G_CALLBACK(filter_default_cb), filter_view);
2638 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2639 gtk_widget_show(button);
2641 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2642 G_CALLBACK(filter_remove_cb), filter_view);
2643 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2644 gtk_widget_show(button);
2646 button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2647 G_CALLBACK(filter_add_cb), filter_view);
2648 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2649 gtk_widget_show(button);
2653 static void config_tab_metadata(GtkWidget *notebook)
2658 GtkWidget *ct_button;
2662 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2665 group = pref_group_new(vbox, FALSE, _("Metadata writing process"), GTK_ORIENTATION_VERTICAL);
2667 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2669 label = pref_label_new(group, _("Metadata are written in the following order. The process ends after first success."));
2670 #if GTK_CHECK_VERSION(3,16,0)
2671 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2672 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2674 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2677 ct_button = pref_checkbox_new_int(group, _("1) Save metadata in image files, or sidecar files, according to the XMP standard"),
2678 options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2680 gtk_widget_set_sensitive(ct_button, FALSE);
2683 pref_checkbox_new_int(group, _("2) Save metadata in '.metadata' folder, local to image folder (non-standard)"),
2684 options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2686 text = g_strdup_printf(_("3) Save metadata in Geeqie private directory '%s'"), get_metadata_cache_dir());
2687 label = pref_label_new(group, text);
2688 #if GTK_CHECK_VERSION(3,16,0)
2689 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2690 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2692 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2694 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2697 group = pref_group_new(vbox, FALSE, _("Step 1: Write to image files"), GTK_ORIENTATION_VERTICAL);
2699 gtk_widget_set_sensitive(group, FALSE);
2702 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2703 pref_checkbox_link_sensitivity(ct_button, hbox);
2705 pref_checkbox_new_int(hbox, _("Store metadata also in legacy IPTC tags (converted according to IPTC4XMP standard)"),
2706 options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2708 pref_checkbox_new_int(hbox, _("Warn if the image files are unwritable"),
2709 options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2711 pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
2712 options->metadata.confirm_write, &c_options->metadata.confirm_write);
2714 pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
2715 options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2717 group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
2719 gtk_widget_set_sensitive(group, FALSE);
2722 pref_checkbox_new_int(group, _("Use GQview legacy metadata format (supports only keywords and comments) instead of XMP"),
2723 options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2726 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2727 pref_checkbox_new_int(group, _("Write the same description tags (keywords, comment, etc.) to all grouped sidecars"),
2728 options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2730 pref_checkbox_new_int(group, _("Allow keywords to differ only in case"),
2731 options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2733 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"),
2734 options->metadata.write_orientation, &c_options->metadata.write_orientation);
2736 gtk_widget_set_sensitive(ct_button, FALSE);
2739 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2741 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"),
2742 options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2744 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2745 pref_checkbox_link_sensitivity(ct_button, hbox);
2747 pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1,
2748 options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2750 pref_checkbox_new_int(group, _("Write metadata on image change"),
2751 options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2753 pref_checkbox_new_int(group, _("Write metadata on directory change"),
2754 options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2756 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2758 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"),
2759 options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2760 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");
2765 typedef struct _KeywordFindData KeywordFindData;
2766 struct _KeywordFindData
2773 GtkWidget *button_close;
2774 GtkWidget *button_stop;
2775 GtkWidget *button_start;
2776 GtkWidget *progress;
2784 guint idle_id; /* event source id */
2787 #define KEYWORD_DIALOG_WIDTH 400
2789 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
2791 GList *list_d = NULL;
2792 GList *list_f = NULL;
2796 filelist_read(dir_fd, &list_f, &list_d);
2800 filelist_read(dir_fd, &list_f, NULL);
2803 list_f = filelist_filter(list_f, FALSE);
2804 list_d = filelist_filter(list_d, TRUE);
2806 kfd->list = g_list_concat(list_f, kfd->list);
2807 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
2810 static void keywords_find_reset(KeywordFindData *kfd)
2812 filelist_free(kfd->list);
2815 filelist_free(kfd->list_dir);
2816 kfd->list_dir = NULL;
2819 static void keywords_find_close_cb(GenericDialog *fd, gpointer data)
2821 KeywordFindData *kfd = data;
2823 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
2825 keywords_find_reset(kfd);
2826 generic_dialog_close(kfd->gd);
2830 static void keywords_find_finish(KeywordFindData *kfd)
2832 keywords_find_reset(kfd);
2834 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
2835 spinner_set_interval(kfd->spinner, -1);
2837 gtk_widget_set_sensitive(kfd->group, TRUE);
2838 gtk_widget_set_sensitive(kfd->button_start, TRUE);
2839 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2840 gtk_widget_set_sensitive(kfd->button_close, TRUE);
2843 static void keywords_find_stop_cb(GenericDialog *fd, gpointer data)
2845 KeywordFindData *kfd = data;
2847 g_idle_remove_by_data(kfd);
2849 keywords_find_finish(kfd);
2852 static gboolean keywords_find_file(gpointer data)
2854 KeywordFindData *kfd = data;
2856 GtkTextBuffer *buffer;
2864 fd = kfd->list->data;
2865 kfd->list = g_list_remove(kfd->list, fd);
2867 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
2868 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2872 gtk_text_buffer_get_end_iter(buffer, &iter);
2873 tmp = g_strconcat(keywords->data, "\n", NULL);
2874 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
2876 keywords = keywords->next;
2879 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
2880 file_data_unref(fd);
2881 string_list_free(keywords);
2885 else if (kfd->list_dir)
2889 fd = kfd->list_dir->data;
2890 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
2892 keywords_find_folder(kfd, fd);
2894 file_data_unref(fd);
2899 keywords_find_finish(kfd);
2904 static void keywords_find_start_cb(GenericDialog *fd, gpointer data)
2906 KeywordFindData *kfd = data;
2909 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
2911 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
2912 parse_out_relatives(path);
2916 warning_dialog(_("Invalid folder"),
2917 _("The specified folder can not be found."),
2918 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
2924 gtk_widget_set_sensitive(kfd->group, FALSE);
2925 gtk_widget_set_sensitive(kfd->button_start, FALSE);
2926 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
2927 gtk_widget_set_sensitive(kfd->button_close, FALSE);
2928 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
2930 dir_fd = file_data_new_dir(path);
2931 keywords_find_folder(kfd, dir_fd);
2932 file_data_unref(dir_fd);
2933 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
2939 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
2941 KeywordFindData *kfd;
2945 kfd = g_new0(KeywordFindData, 1);
2947 kfd->gd = generic_dialog_new(_("Search for keywords"),
2948 "search_for_keywords",
2951 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
2952 kfd->gd->cancel_cb = keywords_find_close_cb;
2953 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
2954 keywords_find_close_cb, FALSE);
2955 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
2956 keywords_find_start_cb, FALSE);
2957 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
2958 keywords_find_stop_cb, FALSE);
2959 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2961 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
2963 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
2964 pref_spacer(hbox, PREF_PAD_INDENT);
2965 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2967 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2968 pref_label_new(hbox, _("Folder:"));
2970 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
2971 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
2972 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
2973 gtk_widget_show(label);
2975 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
2977 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
2978 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2980 kfd->progress = gtk_entry_new();
2981 gtk_widget_set_can_focus(kfd->progress, FALSE);
2982 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
2983 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
2984 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
2985 gtk_widget_show(kfd->progress);
2987 kfd->spinner = spinner_new(NULL, -1);
2988 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
2989 gtk_widget_show(kfd->spinner);
2993 gtk_widget_show(kfd->gd->dialog);
2996 static void keywords_find_cb(GtkWidget *widget, gpointer data)
2998 const gchar *path = layout_get_path(NULL);
3000 if (!path || !*path) path = homedir();
3001 keywords_find_dialog(widget, path);
3004 static void config_tab_keywords_save()
3006 GtkTextIter start, end;
3007 GtkTextBuffer *buffer;
3008 GList *kw_list = NULL;
3014 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3015 gtk_text_buffer_get_bounds(buffer, &start, &end);
3017 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3019 kw_split = strtok(buffer_text, "\n");
3020 while (kw_split != NULL)
3026 if (g_strcmp0(work->data, kw_split) == 0)
3035 kw_list = g_list_append(kw_list, g_strdup(kw_split));
3037 kw_split = strtok(NULL, "\n");
3040 keyword_list_set(kw_list);
3042 string_list_free(kw_list);
3043 g_free(buffer_text);
3046 static void config_tab_keywords(GtkWidget *notebook)
3052 GtkWidget *scrolled;
3054 GtkTextBuffer *buffer;
3057 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3059 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3061 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3063 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
3064 G_CALLBACK(keywords_find_cb), keyword_text);
3065 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
3068 keyword_text = gtk_text_view_new();
3069 gtk_widget_set_size_request(keyword_text, 20, 20);
3070 scrolled = gtk_scrolled_window_new(NULL, NULL);
3071 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3072 gtk_widget_show(scrolled);
3074 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
3075 gtk_widget_show(keyword_text);
3077 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3079 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3080 gtk_text_buffer_create_tag(buffer, "monospace",
3081 "family", "monospace", NULL);
3083 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3084 gtk_text_buffer_get_start_iter(buffer, &iter);
3085 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3088 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3090 GList *kwl = keyword_list_get();
3091 kwl = g_list_first(kwl);
3094 gtk_text_buffer_get_end_iter (buffer, &iter);
3095 tmp = g_strconcat(kwl->data, "\n", NULL);
3096 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3101 gtk_text_buffer_set_modified(buffer, FALSE);
3108 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3110 gint *option = data;
3112 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3116 *option = INTENT_PERCEPTUAL;
3119 *option = INTENT_RELATIVE_COLORIMETRIC;
3122 *option = INTENT_SATURATION;
3125 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3130 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3131 gint option, gint *option_c)
3138 pref_table_label(table, column, row, text, 0.0);
3140 combo = gtk_combo_box_text_new();
3142 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3143 if (option == INTENT_PERCEPTUAL) current = 0;
3144 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3145 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3146 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3147 if (option == INTENT_SATURATION) current = 2;
3148 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3149 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3151 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3153 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3155 g_signal_connect(G_OBJECT(combo), "changed",
3156 G_CALLBACK(intent_menu_cb), option_c);
3158 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
3159 gtk_widget_show(combo);
3163 static void config_tab_color(GtkWidget *notebook)
3172 vbox = scrolled_notebook_page(notebook, _("Color management"));
3174 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3176 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3179 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3180 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3182 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3183 pref_label_bold(label, TRUE, FALSE);
3185 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3186 pref_label_bold(label, TRUE, FALSE);
3188 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3189 pref_label_bold(label, TRUE, FALSE);
3191 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3196 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3197 pref_table_label(table, 0, i + 1, buf, 1.0);
3200 entry = gtk_entry_new();
3201 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3202 if (options->color_profile.input_name[i])
3204 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3206 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3207 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3208 gtk_widget_show(entry);
3209 color_profile_input_name_entry[i] = entry;
3211 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3212 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3213 gtk_widget_set_size_request(entry, 160, -1);
3214 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3215 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3216 gtk_widget_show(tabcomp);
3217 color_profile_input_file_entry[i] = entry;
3220 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3222 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3224 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3225 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3227 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3229 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3230 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3231 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3232 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3233 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3235 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3237 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3239 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3241 gtk_widget_show(tabcomp);
3244 /* advanced entry tab */
3245 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer data)
3247 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3249 c_options->file_ops.use_system_trash = FALSE;
3250 c_options->file_ops.no_trash = FALSE;
3254 static void use_system_trash_cb(GtkWidget *widget, gpointer data)
3256 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3258 c_options->file_ops.use_system_trash = TRUE;
3259 c_options->file_ops.no_trash = FALSE;
3263 static void use_no_cache_cb(GtkWidget *widget, gpointer data)
3265 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3267 c_options->file_ops.no_trash = TRUE;
3271 static void config_tab_behavior(GtkWidget *notebook)
3278 GtkWidget *ct_button;
3282 GtkWidget *with_rename;
3283 GtkWidget *collections_on_top;
3284 GtkWidget *hide_window_in_fullscreen;
3285 GtkWidget *checkbox;
3287 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3289 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3291 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3292 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3293 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3294 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3295 pref_checkbox_new_int(group, _("Enable Delete key"),
3296 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3298 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3299 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3301 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3302 pref_checkbox_link_sensitivity(ct_button, hbox);
3304 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3305 pref_label_new(hbox, _("Folder:"));
3307 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3308 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3309 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3310 gtk_widget_show(tabcomp);
3312 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3313 pref_checkbox_link_sensitivity(ct_button, hbox);
3315 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3316 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MB"),
3317 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3318 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3319 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3320 G_CALLBACK(safe_delete_view_cb), NULL);
3321 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3322 gtk_widget_show(button);
3324 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3325 G_CALLBACK(safe_delete_clear_cb), NULL);
3326 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3327 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3328 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3330 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3331 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3333 gtk_widget_show(button);
3335 pref_spacer(group, PREF_PAD_GROUP);
3338 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3340 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3341 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3343 pref_checkbox_new_int(group, _("In place renaming"),
3344 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3346 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3347 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3349 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3350 options->marks_save, &c_options->marks_save);
3351 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3353 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3354 options->with_rename, &c_options->with_rename);
3355 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3357 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3358 options->collections_on_top, &c_options->collections_on_top);
3359 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3361 hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3362 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3363 gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice");
3365 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3366 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3368 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3369 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3371 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3372 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3374 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3375 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3377 pref_spacer(group, PREF_PAD_GROUP);
3379 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3381 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3382 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3383 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3384 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3385 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3386 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3387 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3388 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3389 pref_checkbox_new_int(group, _("Play video by left click on image"),
3390 options->image_l_click_video, &c_options->image_l_click_video);
3391 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3392 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3394 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3395 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3396 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3397 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3398 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3400 pref_spacer(group, PREF_PAD_GROUP);
3402 group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3404 checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3405 options->override_disable_gpu, &c_options->override_disable_gpu);
3406 gtk_widget_set_tooltip_text(checkbox, "Contact the developers for usage");
3409 pref_spacer(group, PREF_PAD_GROUP);
3411 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3413 pref_spin_new_int(group, _("Debug level:"), NULL,
3414 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3416 pref_checkbox_new_int(group, _("Timer data"),
3417 options->log_window.timer_data, &c_options->log_window.timer_data);
3419 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3420 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3424 /* accelerators tab */
3425 static void config_tab_accelerators(GtkWidget *notebook)
3431 GtkWidget *scrolled;
3432 GtkWidget *accel_view;
3433 GtkCellRenderer *renderer;
3434 GtkTreeSelection *selection;
3435 GtkTreeViewColumn *column;
3437 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3439 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3441 scrolled = gtk_scrolled_window_new(NULL, NULL);
3442 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3443 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3444 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3445 gtk_widget_show(scrolled);
3447 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3449 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3450 g_object_unref(accel_store);
3451 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3452 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3454 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3456 renderer = gtk_cell_renderer_text_new();
3458 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3463 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3464 gtk_tree_view_column_set_resizable(column, TRUE);
3465 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3468 renderer = gtk_cell_renderer_accel_new();
3469 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3470 G_CALLBACK(accel_store_cleared_cb), accel_store);
3471 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3472 G_CALLBACK(accel_store_edited_cb), accel_store);
3475 g_object_set (renderer,
3477 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3480 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3485 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3486 gtk_tree_view_column_set_resizable(column, TRUE);
3487 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3489 renderer = gtk_cell_renderer_text_new();
3491 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3496 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3497 gtk_tree_view_column_set_resizable(column, TRUE);
3498 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3500 renderer = gtk_cell_renderer_text_new();
3502 column = gtk_tree_view_column_new_with_attributes("Accel",
3507 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3508 gtk_tree_view_column_set_resizable(column, TRUE);
3509 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3511 accel_store_populate();
3512 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3513 gtk_widget_show(accel_view);
3515 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3517 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3518 G_CALLBACK(accel_default_cb), accel_view);
3519 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3520 gtk_widget_show(button);
3522 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3523 G_CALLBACK(accel_reset_cb), accel_view);
3524 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3525 gtk_widget_show(button);
3528 /* toolbar main tab */
3529 static void config_tab_toolbar_main(GtkWidget *notebook)
3532 GtkWidget *toolbardata;
3535 lw = layout_window_list->data;
3537 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3539 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3540 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3541 gtk_widget_show(vbox);
3544 /* toolbar status tab */
3545 static void config_tab_toolbar_status(GtkWidget *notebook)
3548 GtkWidget *toolbardata;
3551 lw = layout_window_list->data;
3553 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3555 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3556 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3557 gtk_widget_show(vbox);
3561 static void config_tab_stereo(GtkWidget *notebook)
3569 GtkWidget *fs_button;
3570 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3572 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3574 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3575 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3577 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3578 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3579 pref_checkbox_new_int(box, _("Mirror left image"),
3580 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3581 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3582 pref_checkbox_new_int(box, _("Flip left image"),
3583 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3584 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3585 pref_checkbox_new_int(box, _("Mirror right image"),
3586 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3587 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3588 pref_checkbox_new_int(box, _("Flip right image"),
3589 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3590 pref_checkbox_new_int(group, _("Swap left and right images"),
3591 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3592 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3593 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3595 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3596 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3597 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3598 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3599 pref_checkbox_link_sensitivity(fs_button, box2);
3600 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3601 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3602 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3603 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3604 pref_checkbox_new_int(box, _("Mirror left image"),
3605 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3606 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3607 pref_checkbox_new_int(box, _("Flip left image"),
3608 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3609 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3610 pref_checkbox_new_int(box, _("Mirror right image"),
3611 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3612 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3613 pref_checkbox_new_int(box, _("Flip right image"),
3614 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3615 pref_checkbox_new_int(box2, _("Swap left and right images"),
3616 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3617 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3618 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3620 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3621 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3622 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3623 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3624 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
3625 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3626 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
3627 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3628 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
3629 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3630 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
3631 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3632 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
3633 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3637 /* Main preferences window */
3638 static void config_window_create(void)
3640 GtkWidget *win_vbox;
3642 GtkWidget *notebook;
3644 GtkWidget *ct_button;
3646 if (!c_options) c_options = init_options(NULL);
3648 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3649 DEBUG_NAME(configwindow);
3650 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3651 g_signal_connect(G_OBJECT(configwindow), "delete_event",
3652 G_CALLBACK(config_window_delete), NULL);
3653 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
3654 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
3655 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
3657 win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
3658 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
3659 gtk_widget_show(win_vbox);
3661 notebook = gtk_notebook_new();
3662 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
3663 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
3664 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
3666 config_tab_general(notebook);
3667 config_tab_image(notebook);
3668 config_tab_osd(notebook);
3669 config_tab_windows(notebook);
3670 config_tab_accelerators(notebook);
3671 config_tab_files(notebook);
3672 config_tab_metadata(notebook);
3673 config_tab_keywords(notebook);
3674 config_tab_color(notebook);
3675 config_tab_stereo(notebook);
3676 config_tab_behavior(notebook);
3677 config_tab_toolbar_main(notebook);
3678 config_tab_toolbar_status(notebook);
3680 hbox = gtk_hbutton_box_new();
3681 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
3682 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
3683 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
3684 gtk_widget_show(hbox);
3686 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
3687 G_CALLBACK(config_window_help_cb), notebook);
3688 gtk_container_add(GTK_CONTAINER(hbox), button);
3689 gtk_widget_set_can_default(button, TRUE);
3690 gtk_widget_show(button);
3692 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
3693 G_CALLBACK(config_window_ok_cb), NULL);
3694 gtk_container_add(GTK_CONTAINER(hbox), button);
3695 gtk_widget_set_can_default(button, TRUE);
3696 gtk_widget_grab_default(button);
3697 gtk_widget_show(button);
3701 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
3702 G_CALLBACK(config_window_close_cb), NULL);
3703 gtk_container_add(GTK_CONTAINER(hbox), button);
3704 gtk_widget_set_can_default(button, TRUE);
3705 gtk_widget_show(button);
3707 if (!generic_dialog_get_alternative_button_order(configwindow))
3709 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
3712 gtk_widget_show(notebook);
3714 gtk_widget_show(configwindow);
3718 *-----------------------------------------------------------------------------
3719 * config window show (public)
3720 *-----------------------------------------------------------------------------
3723 void show_config_window(void)
3727 gtk_window_present(GTK_WINDOW(configwindow));
3731 config_window_create();
3740 void show_about_window(LayoutWindow *lw)
3742 GdkPixbuf *pixbuf_logo;
3743 GdkPixbuf *pixbuf_icon;
3744 gchar *authors[1000];
3749 gchar *timezone_path;
3753 #define LINE_LENGTH 1000
3754 gchar line[LINE_LENGTH];
3756 copyright = g_string_new(NULL);
3757 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");
3759 path = path_from_utf8(TIMEZONE_DATABASE);
3760 basename = g_path_get_basename(path);
3761 timezone_path = g_build_filename(get_rc_dir(), basename, NULL);
3762 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
3764 cd = ZDOpenDatabase(timezone_path);
3767 copyright = g_string_append(copyright, ZDGetNotice(cd));
3768 ZDCloseDatabase(cd);
3772 g_free(timezone_path);
3776 path = g_build_filename(GQ_HELPDIR, "AUTHORS", NULL);
3777 fp = fopen(path, "r");
3780 while(fgets(line, LINE_LENGTH, fp))
3782 /* get rid of ending \n from fgets */
3783 line[strlen(line) - 1] = '\0';
3784 authors[i_authors] = g_strdup(line);
3787 authors[i_authors] = NULL;
3792 comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
3793 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
3795 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
3796 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
3797 gtk_show_about_dialog(GTK_WINDOW(lw->window),
3798 "title", _("About Geeqie"),
3800 "program-name", GQ_APPNAME,
3802 "logo", pixbuf_logo,
3803 "icon", pixbuf_icon,
3804 "website", GQ_WEBSITE,
3805 "website-label", "Website",
3806 "comments", comment,
3808 "translator-credits", _("translator-credits"),
3809 "wrap-license", TRUE,
3810 "license", copyright->str,
3813 g_string_free(copyright, TRUE);
3816 while(n < i_authors)
3826 static void image_overlay_set_text_colours()
3828 c_options->image_overlay.text_red = options->image_overlay.text_red;
3829 c_options->image_overlay.text_green = options->image_overlay.text_green;
3830 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
3831 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
3832 c_options->image_overlay.background_red = options->image_overlay.background_red;
3833 c_options->image_overlay.background_green = options->image_overlay.background_green;
3834 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
3835 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
3839 *-----------------------------------------------------------------------------
3840 * timezone database routines
3841 *-----------------------------------------------------------------------------
3844 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
3846 GError *error = NULL;
3848 gchar *tmp_filename;
3850 if (!g_cancellable_is_cancelled(tz->cancellable))
3852 generic_dialog_close(tz->gd);
3856 if (g_file_copy_finish(G_FILE(source_object), res, &error))
3858 tmp_filename = g_file_get_parse_name(tz->tmp_g_file);
3859 move_file(tmp_filename, tz->timezone_database_user);
3860 g_free(tmp_filename);
3864 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3867 g_file_delete(tz->tmp_g_file, NULL, &error);
3868 g_object_unref(tz->tmp_g_file);
3869 tz->tmp_g_file = NULL;
3870 g_object_unref(tz->cancellable);
3871 g_object_unref(tz->timezone_database_gq);
3874 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
3878 if (!g_cancellable_is_cancelled(tz->cancellable))
3880 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
3884 static void timezone_cancel_button_cb(GenericDialog *gd, gpointer data)
3888 g_cancellable_cancel(tz->cancellable);
3891 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
3894 GError *error = NULL;
3895 GFileIOStream *io_stream;
3902 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
3906 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3907 log_printf("Error: Download timezone database failed:\n%s", error->message);
3908 g_error_free(error);
3909 g_object_unref(tz->tmp_g_file);
3913 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE);
3915 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
3917 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
3919 tz->progress = gtk_progress_bar_new();
3920 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
3921 gtk_widget_show(tz->progress);
3923 gtk_widget_show(tz->gd->dialog);
3924 tz->cancellable = g_cancellable_new();
3925 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);
3927 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
3930 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */