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 program 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.use_color_management = c_options->thumbnails.use_color_management;
302 options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
303 options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
304 // options->thumbnails.use_ft_metadata_small = c_options->thumbnails.use_ft_metadata_small;
305 options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
306 options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
307 options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
308 options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
309 options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
310 options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
312 options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
313 options->file_sort.natural = c_options->file_sort.natural;
314 options->file_filter.disable = c_options->file_filter.disable;
316 config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, NULL);
317 sidecar_ext_parse(options->sidecar.ext);
319 options->slideshow.random = c_options->slideshow.random;
320 options->slideshow.repeat = c_options->slideshow.repeat;
321 options->slideshow.delay = c_options->slideshow.delay;
323 options->mousewheel_scrolls = c_options->mousewheel_scrolls;
324 options->image_lm_click_nav = c_options->image_lm_click_nav;
325 options->image_l_click_video = c_options->image_l_click_video;
326 options->image_l_click_video_editor = c_options->image_l_click_video_editor;
328 options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
330 options->image.tile_cache_max = c_options->image.tile_cache_max;
331 options->image.image_cache_max = c_options->image.image_cache_max;
333 options->image.zoom_quality = c_options->image.zoom_quality;
335 options->image.zoom_increment = c_options->image.zoom_increment;
337 options->image.enable_read_ahead = c_options->image.enable_read_ahead;
340 if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
341 || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
342 || !gdk_color_equal(&options->image.border_color, &c_options->image.border_color))
344 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
345 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
346 options->image.border_color = c_options->image.border_color;
347 layout_colors_update();
348 view_window_colors_update();
351 options->image.alpha_color_1 = c_options->image.alpha_color_1;
352 options->image.alpha_color_2 = c_options->image.alpha_color_2;
354 options->fullscreen.screen = c_options->fullscreen.screen;
355 options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
356 options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
357 options->fullscreen.above = c_options->fullscreen.above;
358 if (c_options->image_overlay.template_string)
359 set_image_overlay_template_string(&options->image_overlay.template_string,
360 c_options->image_overlay.template_string);
361 if (c_options->image_overlay.font)
362 set_image_overlay_font_string(&options->image_overlay.font,
363 c_options->image_overlay.font);
364 options->image_overlay.text_red = c_options->image_overlay.text_red;
365 options->image_overlay.text_green = c_options->image_overlay.text_green;
366 options->image_overlay.text_blue = c_options->image_overlay.text_blue;
367 options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
368 options->image_overlay.background_red = c_options->image_overlay.background_red;
369 options->image_overlay.background_green = c_options->image_overlay.background_green;
370 options->image_overlay.background_blue = c_options->image_overlay.background_blue;
371 options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
372 options->update_on_time_change = c_options->update_on_time_change;
373 options->image.exif_proof_rotate_enable = c_options->image.exif_proof_rotate_enable;
375 options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
376 options->rot_invariant_sim = c_options->rot_invariant_sim;
378 options->tree_descend_subdirs = c_options->tree_descend_subdirs;
380 options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
382 options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
383 options->dnd_icon_size = c_options->dnd_icon_size;
384 options->clipboard_selection = c_options->clipboard_selection;
385 options->dnd_default_action = c_options->dnd_default_action;
387 options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
388 options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
389 options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
390 options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
391 options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
392 options->metadata.confirm_write = c_options->metadata.confirm_write;
393 options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
394 options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
395 options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
396 options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
397 options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
398 options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
399 options->metadata.write_orientation = c_options->metadata.write_orientation;
400 options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
401 (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
402 (c_options->stereo.tmp.flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
403 (c_options->stereo.tmp.mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
404 (c_options->stereo.tmp.flip_left ? PR_STEREO_FLIP_LEFT : 0) |
405 (c_options->stereo.tmp.swap ? PR_STEREO_SWAP : 0) |
406 (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
407 options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
408 (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
409 (c_options->stereo.tmp.fs_flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
410 (c_options->stereo.tmp.fs_mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
411 (c_options->stereo.tmp.fs_flip_left ? PR_STEREO_FLIP_LEFT : 0) |
412 (c_options->stereo.tmp.fs_swap ? PR_STEREO_SWAP : 0) |
413 (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
414 options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
415 options->stereo.fixed_w = c_options->stereo.fixed_w;
416 options->stereo.fixed_h = c_options->stereo.fixed_h;
417 options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
418 options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
419 options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
420 options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
422 options->info_keywords.height = c_options->info_keywords.height;
423 options->info_title.height = c_options->info_title.height;
424 options->info_comment.height = c_options->info_comment.height;
425 options->info_rating.height = c_options->info_rating.height;
427 options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
428 options->expand_menu_toolbar = c_options->expand_menu_toolbar;
430 options->marks_save = c_options->marks_save;
431 options->with_rename = c_options->with_rename;
432 options->collections_on_top = c_options->collections_on_top;
433 options->hide_window_in_fullscreen = c_options->hide_window_in_fullscreen;
434 config_entry_to_option(help_search_engine_entry, &options->help_search_engine, NULL);
436 options->read_metadata_in_idle = c_options->read_metadata_in_idle;
438 options->star_rating.star = c_options->star_rating.star;
439 options->star_rating.rejected = c_options->star_rating.rejected;
441 set_debug_level(debug_c);
445 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
447 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
448 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
450 config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
451 options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
452 if (options->color_profile.render_intent != c_options->color_profile.render_intent)
454 options->color_profile.render_intent = c_options->color_profile.render_intent;
459 options->mouse_button_8 = c_options->mouse_button_8;
460 options->mouse_button_9 = c_options->mouse_button_9;
462 options->override_disable_gpu = c_options->override_disable_gpu;
464 config_tab_keywords_save();
466 image_options_sync();
471 layout_refresh(NULL);
474 if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, NULL);
476 toolbar_apply(TOOLBAR_MAIN);
477 toolbar_apply(TOOLBAR_STATUS);
481 *-----------------------------------------------------------------------------
482 * config window main button callbacks (private)
483 *-----------------------------------------------------------------------------
486 static void config_window_close_cb(GtkWidget *widget, gpointer data)
488 gtk_widget_destroy(configwindow);
493 static void config_window_help_cb(GtkWidget *widget, gpointer data)
495 GtkWidget *notebook = data;
498 static gchar *html_section[] =
500 "GuideOptionsGeneral.html",
501 "GuideOptionsImage.html",
502 "GuideOptionsOSD.html",
503 "GuideOptionsWindow.html",
504 "GuideOptionsKeyboard.html",
505 "GuideOptionsFiltering.html",
506 "GuideOptionsMetadata.html",
507 "GuideOptionsKeywords.html",
508 "GuideOptionsColor.html",
509 "GuideOptionsStereo.html",
510 "GuideOptionsBehavior.html",
511 "GuideOptionsToolbar.html",
512 "GuideOptionsToolbar.html"
515 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
516 help_window_show(html_section[i]);
519 static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpointer data)
521 config_window_close_cb(NULL, NULL);
525 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
528 lw = layout_window_list->data;
530 config_window_apply();
531 layout_util_sync(lw);
532 save_options(options);
533 config_window_close_cb(NULL, NULL);
537 *-----------------------------------------------------------------------------
538 * config window setup (private)
539 *-----------------------------------------------------------------------------
542 static void quality_menu_cb(GtkWidget *combo, gpointer data)
546 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
550 *option = GDK_INTERP_NEAREST;
553 *option = GDK_INTERP_TILES;
556 *option = GDK_INTERP_BILINEAR;
561 static void dnd_default_action_selection_menu_cb(GtkWidget *combo, gpointer data)
565 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
569 *option = DND_ACTION_ASK;
572 *option = DND_ACTION_COPY;
575 *option = DND_ACTION_MOVE;
579 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
583 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
586 *option = CLIPBOARD_PRIMARY;
589 *option = CLIPBOARD_CLIPBOARD;
592 *option = CLIPBOARD_BOTH;
595 *option = CLIPBOARD_BOTH;
599 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
600 guint option, guint *option_c)
607 pref_table_label(table, column, row, text, 0.0);
609 combo = gtk_combo_box_text_new();
611 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
612 if (option == GDK_INTERP_NEAREST) current = 0;
613 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
614 if (option == GDK_INTERP_TILES) current = 1;
615 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear (best, but slowest)"));
616 if (option == GDK_INTERP_BILINEAR) current = 2;
618 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
620 g_signal_connect(G_OBJECT(combo), "changed",
621 G_CALLBACK(quality_menu_cb), option_c);
623 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
624 gtk_widget_show(combo);
627 static void add_dnd_default_action_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, DnDAction option, DnDAction *option_c)
634 pref_table_label(table, column, row, text, 0.0);
636 combo = gtk_combo_box_text_new();
638 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Ask"));
639 if (option == DND_ACTION_ASK) current = 0;
640 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Copy"));
641 if (option == DND_ACTION_COPY) current = 1;
642 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Move"));
643 if (option == DND_ACTION_MOVE) current = 2;
645 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
647 g_signal_connect(G_OBJECT(combo), "changed",
648 G_CALLBACK(dnd_default_action_selection_menu_cb), option_c);
650 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
651 gtk_widget_show(combo);
654 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
655 gint option, gint *option_c)
662 pref_table_label(table, column, row, text, 0.0);
664 combo = gtk_combo_box_text_new();
666 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Primary"));
667 if (option == CLIPBOARD_PRIMARY) current = 0;
668 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Clipboard"));
669 if (option == CLIPBOARD_CLIPBOARD) current = 1;
670 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Both"));
671 if (option == CLIPBOARD_BOTH) current = 2;
673 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
675 g_signal_connect(G_OBJECT(combo), "changed",
676 G_CALLBACK(clipboard_selection_menu_cb), option_c);
678 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
679 gtk_widget_show(combo);
682 typedef struct _UseableMouseItems UseableMouseItems;
683 struct _UseableMouseItems
685 gchar *name; /* GtkActionEntry terminology */
690 static const UseableMouseItems useable_mouse_items[] = {
692 {"FirstImage", N_("First Image"), GTK_STOCK_GOTO_TOP},
693 {"PrevImage", N_("Previous Image"), GTK_STOCK_GO_UP},
694 {"NextImage", N_("Next Image"), GTK_STOCK_GO_DOWN},
695 {"LastImage", N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
696 {"Back", N_("Back"), GTK_STOCK_GO_BACK},
697 {"Forward", N_("Forward"), GTK_STOCK_GO_FORWARD},
698 {"Home", N_("Home"), GTK_STOCK_HOME},
699 {"Up", N_("Up"), GTK_STOCK_GO_UP},
700 {"FirstPage", N_("First page"), GTK_STOCK_MEDIA_PREVIOUS},
701 {"LastPage", N_("Last Page"), GTK_STOCK_MEDIA_NEXT},
702 {"NextPage", N_("Next page"), GTK_STOCK_MEDIA_FORWARD},
703 {"PrevPage", N_("Previous Page"), GTK_STOCK_MEDIA_REWIND},
704 {"NewWindow", N_("New _window"), GTK_STOCK_NEW},
705 {"NewCollection", N_("New collection"), GTK_STOCK_INDEX},
706 {"OpenCollection", N_("Open collection"), GTK_STOCK_OPEN},
707 {"Search", N_("Search"), GTK_STOCK_FIND},
708 {"FindDupes", N_("Find duplicates"), GTK_STOCK_FIND},
709 {"NewFolder", N_("New folder"),GTK_STOCK_DIRECTORY},
710 {"Copy", N_("Copy"), GTK_STOCK_COPY},
711 {"Move", N_("Move"), PIXBUF_INLINE_ICON_MOVE},
712 {"Rename", N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
713 {"Delete", N_("Delete"), GTK_STOCK_DELETE},
714 {"CloseWindow", N_("Close Window"), GTK_STOCK_CLOSE},
715 {"PanView", N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
716 {"SelectAll", N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
717 {"SelectNone", N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
718 {"SelectInvert", N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
719 {"ShowFileFilter", N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
720 {"RectangularSelection", N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
721 {"Print", N_("Print"), GTK_STOCK_PRINT},
722 {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
723 {"LayoutConfig", N_("Configure this window"), GTK_STOCK_PREFERENCES},
724 {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
725 {"RotateCW", N_("Rotate clockwise 90°"), PIXBUF_INLINE_ICON_CW},
726 {"RotateCCW", N_("Rotate counterclockwise 90°"), PIXBUF_INLINE_ICON_CCW},
727 {"Rotate180", N_("Rotate 180°"), PIXBUF_INLINE_ICON_180},
728 {"Mirror", N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
729 {"Flip", N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
730 {"AlterNone", N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
731 {"ZoomIn", N_("Zoom in"), GTK_STOCK_ZOOM_IN},
732 {"ZoomOut", N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
733 {"Zoom100", N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
734 {"ZoomFit", N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
735 {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
736 {"ZoomFillVert", N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
737 {"Zoom200", N_("Zoom 2:1"), GTK_STOCK_FILE},
738 {"Zoom300", N_("Zoom 3:1"), GTK_STOCK_FILE},
739 {"Zoom400", N_("Zoom 4:1"), GTK_STOCK_FILE},
740 {"Zoom50", N_("Zoom 1:2"), GTK_STOCK_FILE},
741 {"Zoom33", N_("Zoom1:3"), GTK_STOCK_FILE},
742 {"Zoom25", N_("Zoom 1:4"), GTK_STOCK_FILE},
743 {"ConnectZoomIn", N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
744 {"SplitPaneSync", N_("Split Pane Sync"), PIXBUF_INLINE_SPLIT_PANE_SYNC},
745 {"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
746 {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
747 {"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
748 {"SlideShowPause", N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
749 {"SlideShowFaster", N_("Slideshow Faster"), GTK_STOCK_FILE},
750 {"SlideShowSlower", N_("Slideshow Slower"), GTK_STOCK_FILE},
751 {"Refresh", N_("Refresh"), GTK_STOCK_REFRESH},
752 {"HelpContents", N_("Help"), GTK_STOCK_HELP},
753 {"ExifWin", N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
754 {"Thumbnails", N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
755 {"ShowMarks", N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
756 {"ImageGuidelines", N_("Show guidelines"), PIXBUF_INLINE_ICON_GUIDELINES},
757 {"DrawRectangle", N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
758 {"FloatTools", N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
759 {"SBar", N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
760 {"SBarSort", N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
761 {"Quit", N_("Quit"), GTK_STOCK_QUIT},
765 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
767 gchar **option = data;
770 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
772 const UseableMouseItems *list = useable_mouse_items;
776 if (g_strcmp0(list->label, label) == 0)
784 *option = g_strdup(list->name);
788 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
789 gchar *option, gchar **option_c)
797 pref_table_label(table, column, row, text, 0.0);
799 combo = gtk_combo_box_text_new();
801 const UseableMouseItems *list = useable_mouse_items;
805 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
806 if (g_strcmp0(list->name, option) == 0)
814 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
816 g_signal_connect(G_OBJECT(combo), "changed",
817 G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
819 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
820 gtk_widget_show(combo);
823 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
827 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
830 if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
832 c_options->thumbnails.max_width = thumb_size_list[n].w;
833 c_options->thumbnails.max_height = thumb_size_list[n].h;
837 c_options->thumbnails.max_width = options->thumbnails.max_width;
838 c_options->thumbnails.max_height = options->thumbnails.max_height;
842 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
848 c_options->thumbnails.max_width = options->thumbnails.max_width;
849 c_options->thumbnails.max_height = options->thumbnails.max_height;
851 pref_table_label(table, column, row, text, 0.0);
853 combo = gtk_combo_box_text_new();
856 for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
861 w = thumb_size_list[i].w;
862 h = thumb_size_list[i].h;
864 buf = g_strdup_printf("%d x %d", w, h);
865 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
868 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
875 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
876 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
882 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
883 g_signal_connect(G_OBJECT(combo), "changed",
884 G_CALLBACK(thumb_size_menu_cb), NULL);
886 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
887 gtk_widget_show(combo);
890 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
894 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
898 *option = PR_STEREO_NONE;
901 *option = PR_STEREO_ANAGLYPH_RC;
904 *option = PR_STEREO_ANAGLYPH_GM;
907 *option = PR_STEREO_ANAGLYPH_YB;
910 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
913 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
916 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
919 *option = PR_STEREO_ANAGLYPH_DB_RC;
922 *option = PR_STEREO_ANAGLYPH_DB_GM;
925 *option = PR_STEREO_ANAGLYPH_DB_YB;
928 *option = PR_STEREO_HORIZ;
931 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
934 *option = PR_STEREO_VERT;
937 *option = PR_STEREO_VERT | PR_STEREO_HALF;
940 *option = PR_STEREO_FIXED;
945 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
946 gint option, gint *option_c, gboolean add_fixed)
953 pref_table_label(table, column, row, text, 0.0);
955 combo = gtk_combo_box_text_new();
957 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
959 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
960 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
961 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
962 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
963 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
964 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
965 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
966 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
967 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
968 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
969 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
970 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
971 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
972 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
973 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
974 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
975 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
976 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
978 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
979 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
980 if (option & PR_STEREO_HORIZ)
983 if (option & PR_STEREO_HALF) current = 11;
986 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
987 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
988 if (option & PR_STEREO_VERT)
991 if (option & PR_STEREO_HALF) current = 13;
996 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
997 if (option & PR_STEREO_FIXED) current = 14;
1000 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1002 g_signal_connect(G_OBJECT(combo), "changed",
1003 G_CALLBACK(stereo_mode_menu_cb), option_c);
1005 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1006 gtk_widget_show(combo);
1009 static void video_menu_cb(GtkWidget *combo, gpointer data)
1011 gchar **option = data;
1013 EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
1017 static void video_menu_populate(gpointer data, gpointer user_data)
1019 GtkWidget *combo = user_data;
1020 EditorDescription *ed = data;
1022 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1025 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1026 gchar *option, gchar **option_c)
1030 /* use lists since they are sorted */
1031 GList *eds = editor_list_get();
1035 pref_table_label(table, column, row, text, 0.0);
1037 combo = gtk_combo_box_text_new();
1038 g_list_foreach(eds,video_menu_populate,(gpointer)combo);
1039 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1041 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1043 g_signal_connect(G_OBJECT(combo), "changed",
1044 G_CALLBACK(video_menu_cb), option_c);
1046 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1047 gtk_widget_show(combo);
1050 static void filter_store_populate(void)
1054 if (!filter_store) return;
1056 gtk_list_store_clear(filter_store);
1058 work = filter_get_list();
1067 gtk_list_store_append(filter_store, &iter);
1068 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1072 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1073 gchar *new_text, gpointer data)
1075 GtkWidget *model = data;
1076 FilterEntry *fe = data;
1080 if (!new_text || strlen(new_text) < 1) return;
1082 tpath = gtk_tree_path_new_from_string(path_str);
1083 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1084 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1086 g_free(fe->extensions);
1087 fe->extensions = g_strdup(new_text);
1089 gtk_tree_path_free(tpath);
1093 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1094 gchar *new_text, gpointer data)
1096 GtkWidget *model = data;
1097 FilterEntry *fe = data;
1102 if (!new_text || !new_text[0]) return;
1104 tpath = gtk_tree_path_new_from_string(path_str);
1105 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1106 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1108 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1110 if (strcmp(new_text, _(format_class_list[i])) == 0)
1117 gtk_tree_path_free(tpath);
1121 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1122 gchar *new_text, gpointer data)
1124 GtkWidget *model = data;
1129 if (!new_text || !new_text[0]) return;
1131 tpath = gtk_tree_path_new_from_string(path_str);
1132 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1133 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1135 g_free(fe->description);
1136 fe->description = g_strdup(new_text);
1138 gtk_tree_path_free(tpath);
1141 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
1142 gchar *path_str, gpointer data)
1144 GtkWidget *model = data;
1149 tpath = gtk_tree_path_new_from_string(path_str);
1150 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1151 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1153 fe->enabled = !fe->enabled;
1155 gtk_tree_path_free(tpath);
1159 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
1160 gchar *path_str, gpointer data)
1162 GtkWidget *model = data;
1167 tpath = gtk_tree_path_new_from_string(path_str);
1168 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1169 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1171 fe->writable = !fe->writable;
1172 if (fe->writable) fe->allow_sidecar = FALSE;
1174 gtk_tree_path_free(tpath);
1178 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
1179 gchar *path_str, gpointer data)
1181 GtkWidget *model = data;
1186 tpath = gtk_tree_path_new_from_string(path_str);
1187 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1188 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1190 fe->allow_sidecar = !fe->allow_sidecar;
1191 if (fe->allow_sidecar) fe->writable = FALSE;
1193 gtk_tree_path_free(tpath);
1197 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1198 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1202 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1204 switch (GPOINTER_TO_INT(data))
1207 g_object_set(GTK_CELL_RENDERER(cell),
1208 "active", fe->enabled, NULL);
1211 g_object_set(GTK_CELL_RENDERER(cell),
1212 "text", fe->extensions, NULL);
1214 case FE_DESCRIPTION:
1215 g_object_set(GTK_CELL_RENDERER(cell),
1216 "text", fe->description, NULL);
1219 g_object_set(GTK_CELL_RENDERER(cell),
1220 "text", _(format_class_list[fe->file_class]), NULL);
1223 g_object_set(GTK_CELL_RENDERER(cell),
1224 "active", fe->writable, NULL);
1226 case FE_ALLOW_SIDECAR:
1227 g_object_set(GTK_CELL_RENDERER(cell),
1228 "active", fe->allow_sidecar, NULL);
1233 static gboolean filter_add_scroll(gpointer data)
1237 GtkCellRenderer *cell;
1238 GtkTreeViewColumn *column;
1241 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1242 path = gtk_tree_path_new_from_indices(rows-1, -1);
1244 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1246 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1247 cell = g_list_last(list_cells)->data;
1249 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1250 path, column, FALSE, 0.0, 0.0 );
1251 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1252 path, column, cell, TRUE);
1254 gtk_tree_path_free(path);
1255 g_list_free(list_cells);
1260 static void filter_add_cb(GtkWidget *widget, gpointer data)
1262 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1263 filter_store_populate();
1265 g_idle_add((GSourceFunc)filter_add_scroll, data);
1268 static void filter_remove_cb(GtkWidget *widget, gpointer data)
1270 GtkWidget *filter_view = data;
1271 GtkTreeSelection *selection;
1275 if (!filter_store) return;
1276 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1277 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1278 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1281 filter_remove_entry(fe);
1283 filter_store_populate();
1286 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1290 GtkTreeViewColumn *column;
1292 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1293 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1294 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1296 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1300 gtk_tree_path_free(path);
1305 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
1308 filter_add_defaults();
1310 filter_store_populate();
1312 g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1315 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1317 /* no op, only so cancel button appears */
1320 static void filter_default_cb(GtkWidget *widget, gpointer data)
1324 gd = generic_dialog_new(_("Reset filters"),
1325 "reset_filter", widget, TRUE,
1326 dummy_cancel_cb, data);
1327 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1328 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1329 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1330 gtk_widget_show(gd->dialog);
1333 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1335 GtkWidget *frame = data;
1337 gtk_widget_set_sensitive(frame,
1338 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1341 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
1343 layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1346 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
1348 file_util_trash_clear();
1351 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
1355 gd = generic_dialog_new(_("Clear trash"),
1356 "clear_trash", widget, TRUE,
1357 dummy_cancel_cb, NULL);
1358 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1359 _("This will remove the trash contents."), FALSE);
1360 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1361 entry = gtk_entry_new();
1362 gtk_widget_set_can_focus(entry, FALSE);
1363 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1364 if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1365 gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1366 gtk_widget_show(entry);
1367 gtk_widget_show(gd->dialog);
1370 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
1372 GtkWidget *pTextView;
1373 GtkTextBuffer *pTextBuffer;
1377 pTextView = GTK_WIDGET(data);
1379 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1380 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1381 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1383 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1384 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1387 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
1389 GtkTextView *text_view = data;
1390 GtkTextBuffer *buffer;
1392 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1393 if (!configwindow) return;
1395 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1396 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1399 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1403 gd = generic_dialog_new(_("Reset image overlay template string"),
1404 "reset_image_overlay_template_string", widget, TRUE,
1405 dummy_cancel_cb, data);
1406 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1407 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1408 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1409 gtk_widget_show(gd->dialog);
1412 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
1414 help_window_show("GuideOptionsOSD.html");
1417 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer data)
1419 #if GTK_CHECK_VERSION(3,4,0)
1422 PangoFontDescription *font_desc;
1424 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1425 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1427 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1429 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1430 font = pango_font_description_to_string(font_desc);
1431 g_free(c_options->image_overlay.font);
1432 c_options->image_overlay.font = g_strdup(font);
1436 gtk_widget_destroy(dialog);
1440 font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
1441 c_options->image_overlay.font = g_strdup(font);
1445 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer data)
1448 #if GTK_CHECK_VERSION(3,4,0)
1451 dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1452 colour.red = options->image_overlay.text_red;
1453 colour.green = options->image_overlay.text_green;
1454 colour.blue = options->image_overlay.text_blue;
1455 colour.alpha = options->image_overlay.text_alpha;
1456 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1457 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1459 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1461 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1462 c_options->image_overlay.text_red = colour.red*255;
1463 c_options->image_overlay.text_green = colour.green*255;
1464 c_options->image_overlay.text_blue = colour.blue*255;
1465 c_options->image_overlay.text_alpha = colour.alpha*255;
1467 gtk_widget_destroy(dialog);
1470 GtkColorSelection *colorsel;
1472 dialog = gtk_color_selection_dialog_new("Image Overlay Text Colour");
1473 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1474 colour.red = options->image_overlay.text_red*257;
1475 colour.green = options->image_overlay.text_green*257;
1476 colour.blue = options->image_overlay.text_blue*257;
1477 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1478 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1479 gtk_color_selection_set_current_color(colorsel, &colour);
1480 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.text_alpha*257);
1482 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1484 gtk_color_selection_get_current_color(colorsel, &colour);
1485 c_options->image_overlay.text_red = colour.red/257;
1486 c_options->image_overlay.text_green = colour.green/257;
1487 c_options->image_overlay.text_blue = colour.blue/257;
1488 c_options->image_overlay.text_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1490 gtk_widget_destroy (dialog);
1495 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer data)
1498 #if GTK_CHECK_VERSION(3,4,0)
1501 dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1502 colour.red = options->image_overlay.background_red;
1503 colour.green = options->image_overlay.background_green;
1504 colour.blue = options->image_overlay.background_blue;
1505 colour.alpha = options->image_overlay.background_alpha;
1506 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1507 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1509 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1511 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1512 c_options->image_overlay.background_red = colour.red*255;
1513 c_options->image_overlay.background_green = colour.green*255;
1514 c_options->image_overlay.background_blue = colour.blue*255;
1515 c_options->image_overlay.background_alpha = colour.alpha*255;
1517 gtk_widget_destroy(dialog);
1520 GtkColorSelection *colorsel;
1522 dialog = gtk_color_selection_dialog_new("Image Overlay Background Colour");
1523 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1524 colour.red = options->image_overlay.background_red*257;
1525 colour.green = options->image_overlay.background_green*257;
1526 colour.blue = options->image_overlay.background_blue*257;
1527 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1528 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1529 gtk_color_selection_set_current_color(colorsel, &colour);
1530 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.background_alpha*257);
1532 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1534 gtk_color_selection_get_current_color(colorsel, &colour);
1535 c_options->image_overlay.background_red = colour.red/257;
1536 c_options->image_overlay.background_green = colour.green/257;
1537 c_options->image_overlay.background_blue = colour.blue/257;
1538 c_options->image_overlay.background_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1540 gtk_widget_destroy(dialog);
1544 static void accel_store_populate(void)
1547 GList *groups, *actions;
1549 const gchar *accel_path;
1553 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1555 gtk_tree_store_clear(accel_store);
1556 lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
1558 g_assert(lw && lw->ui_manager);
1559 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1562 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1565 action = GTK_ACTION(actions->data);
1566 accel_path = gtk_action_get_accel_path(action);
1567 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1569 gchar *label, *label2, *tooltip, *accel;
1570 g_object_get(action,
1571 "tooltip", &tooltip,
1575 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1581 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1585 gtk_tree_store_append(accel_store, &iter, NULL);
1586 gtk_tree_store_set(accel_store, &iter,
1589 AE_TOOLTIP, tooltip ? tooltip : "",
1590 AE_ACCEL, accel_path,
1598 actions = actions->next;
1601 groups = groups->next;
1605 static void accel_store_cleared_cb(GtkCellRendererAccel *accel, gchar *path_string, gpointer user_data)
1610 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1612 gchar *accel1 = data;
1617 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1619 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1620 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1622 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1624 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1625 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1634 static void accel_store_edited_cb(GtkCellRendererAccel *accel, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode, gpointer user_data)
1636 GtkTreeModel *model = (GtkTreeModel *)accel_store;
1640 GtkAccelKey old_key, key;
1641 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1643 gtk_tree_model_get_iter(model, &iter, path);
1644 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1646 /* test if the accelerator can be stored without conflicts*/
1647 gtk_accel_map_lookup_entry(accel_path, &old_key);
1649 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1650 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1651 gtk_accel_map_lookup_entry(accel_path, &key);
1653 /* restore the original for now, the key will be really changed when the changes are confirmed */
1654 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1656 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1657 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1659 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1660 gtk_tree_path_free(path);
1664 static gboolean accel_default_scroll(GtkTreeView *data)
1668 GtkTreeViewColumn *column;
1670 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1671 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1672 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1674 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1678 gtk_tree_path_free(path);
1683 static void accel_default_cb(GtkWidget *widget, gpointer data)
1685 accel_store_populate();
1687 g_idle_add((GSourceFunc)accel_default_scroll, data);
1690 void accel_remove_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1692 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1695 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1698 gchar *accel_path, *accel;
1700 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1701 gtk_accel_map_lookup_entry(accel_path, &key);
1702 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1704 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1706 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1711 static void accel_reset_cb(GtkWidget *widget, gpointer data)
1713 GtkTreeSelection *selection;
1715 if (!accel_store) return;
1716 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1717 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1722 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1726 GtkWidget *scrolled;
1727 GtkWidget *viewport;
1729 scrolled = gtk_scrolled_window_new(NULL, NULL);
1730 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1731 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1732 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1733 label = gtk_label_new(title);
1734 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1735 gtk_widget_show(scrolled);
1737 viewport = gtk_viewport_new(NULL, NULL);
1738 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1739 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1740 gtk_widget_show(viewport);
1742 vbox = gtk_vbox_new(FALSE, 0);
1743 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1744 gtk_widget_show(vbox);
1749 static void cache_standard_cb(GtkWidget *widget, gpointer data)
1751 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1753 c_options->thumbnails.spec_standard =TRUE;
1754 c_options->thumbnails.cache_into_dirs = FALSE;
1758 static void cache_geeqie_cb(GtkWidget *widget, gpointer data)
1760 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1762 c_options->thumbnails.spec_standard =FALSE;
1763 c_options->thumbnails.cache_into_dirs = FALSE;
1767 static void cache_local_cb(GtkWidget *widget, gpointer data)
1769 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1771 c_options->thumbnails.cache_into_dirs = TRUE;
1772 c_options->thumbnails.spec_standard =FALSE;
1776 static void help_search_engine_entry_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1777 GdkEvent *event, gpointer userdata)
1779 if (pos == GTK_ENTRY_ICON_PRIMARY)
1781 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1785 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1789 static void star_rating_star_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1790 GdkEvent *event, gpointer userdata)
1792 gchar *rating_symbol;
1794 if (pos == GTK_ENTRY_ICON_PRIMARY)
1796 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1797 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1798 g_free(rating_symbol);
1802 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1803 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1804 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1808 static void star_rating_rejected_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1809 GdkEvent *event, gpointer userdata)
1811 gchar *rating_symbol;
1813 if (pos == GTK_ENTRY_ICON_PRIMARY)
1815 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1816 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1817 g_free(rating_symbol);
1821 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1822 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1823 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1827 static guint star_rating_symbol_test(GtkWidget *widget, gpointer data)
1829 GtkContainer *hbox = data;
1830 GString *str = g_string_new(NULL);
1831 GtkEntry *hex_code_entry;
1832 gchar *hex_code_full;
1835 guint64 hex_value = 0;
1837 list = gtk_container_get_children(hbox);
1839 hex_code_entry = g_list_nth_data(list, 2);
1840 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1842 hex_code = g_strsplit(hex_code_full, "+", 2);
1843 if (hex_code[0] && hex_code[1])
1845 hex_value = strtoull(hex_code[1], NULL, 16);
1847 if (!hex_value || hex_value > 0x10FFFF)
1849 hex_value = 0x003F; // Unicode 'Question Mark'
1851 str = g_string_append_unichar(str, (gunichar)hex_value);
1852 gtk_label_set_text(g_list_nth_data(list, 1), str->str);
1854 g_strfreev(hex_code);
1855 g_string_free(str, TRUE);
1856 g_free(hex_code_full);
1861 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1863 guint64 star_symbol;
1865 star_symbol = star_rating_symbol_test(widget, data);
1866 c_options->star_rating.star = star_symbol;
1869 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1871 guint64 rejected_symbol;
1873 rejected_symbol = star_rating_symbol_test(widget, data);
1874 c_options->star_rating.rejected = rejected_symbol;
1877 /* general options tab */
1878 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1879 typedef struct _TZData TZData;
1883 GCancellable *cancellable;
1885 GtkWidget *progress;
1887 GFile *timezone_database_gq;
1888 gchar *timezone_database_user;
1891 static void config_tab_general(GtkWidget *notebook)
1896 GtkWidget *group_frame;
1897 GtkWidget *subgroup;
1899 GtkWidget *ct_button;
1902 gint hours, minutes, remainder;
1904 GtkWidget *star_rating_entry;
1906 gchar *rating_symbol;
1909 GNetworkMonitor *net_mon;
1910 GSocketConnectable *geeqie_org;
1911 gboolean internet_available;
1914 vbox = scrolled_notebook_page(notebook, _("General"));
1916 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1918 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1919 add_thumb_size_menu(table, 0, 0, _("Size:"));
1920 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1922 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1923 pref_label_new(hbox, _("Custom size: "));
1924 pref_spin_new_int(hbox, _("Width:"), NULL, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
1925 pref_spin_new_int(hbox, _("Height:"), NULL, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
1927 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
1928 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1930 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1931 pref_checkbox_link_sensitivity(ct_button, subgroup);
1933 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
1934 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
1935 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
1936 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1937 button = pref_radiobutton_new(group_frame, NULL, get_thumbnails_cache_dir(),
1938 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1939 G_CALLBACK(cache_geeqie_cb), NULL);
1941 group_frame = pref_frame_new(subgroup, TRUE,
1942 _("Store thumbnails local to image folder (non-standard)"),
1943 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1944 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
1945 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
1946 G_CALLBACK(cache_local_cb), NULL);
1948 group_frame = pref_frame_new(subgroup, TRUE,
1949 _("Use standard thumbnail style and cache, shared with other applications"),
1950 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1951 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
1952 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1953 G_CALLBACK(cache_standard_cb), NULL);
1955 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
1956 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
1958 pref_checkbox_new_int(group, _("Thumbnail color management"),
1959 options->thumbnails.use_color_management, &c_options->thumbnails.use_color_management);
1961 spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
1963 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
1964 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
1966 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
1967 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
1968 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
1970 // pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
1971 // options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
1974 pref_spacer(group, PREF_PAD_GROUP);
1976 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
1978 c_options->star_rating.star = options->star_rating.star;
1979 c_options->star_rating.rejected = options->star_rating.rejected;
1981 str = g_string_new(NULL);
1982 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1983 pref_label_new(hbox, "Star character: ");
1984 str = g_string_append_unichar(str, options->star_rating.star);
1985 pref_label_new(hbox, g_strdup(str->str));
1986 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
1987 star_rating_entry = gtk_entry_new();
1988 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
1989 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
1990 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
1991 gtk_widget_show(star_rating_entry);
1992 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
1993 G_CALLBACK(star_rating_star_test_cb), hbox);
1994 gtk_widget_set_tooltip_text(button, _("Display selected character"));
1995 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1996 gtk_widget_show(button);
1997 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."));
1998 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
1999 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2000 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2001 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2002 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2003 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2004 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2005 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2006 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2007 G_CALLBACK(star_rating_star_icon_cb),
2010 g_string_free(str, TRUE);
2011 g_free(rating_symbol);
2013 str = g_string_new(NULL);
2014 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2015 pref_label_new(hbox, "Rejected character: ");
2016 str = g_string_append_unichar(str, options->star_rating.rejected);
2017 pref_label_new(hbox, g_strdup(str->str));
2018 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2019 star_rating_entry = gtk_entry_new();
2020 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2021 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2022 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2023 gtk_widget_show(star_rating_entry);
2024 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2025 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2026 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2027 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2028 gtk_widget_show(button);
2029 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."));
2030 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2031 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2032 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2033 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2034 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2035 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2036 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2037 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2038 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2039 G_CALLBACK(star_rating_rejected_icon_cb),
2042 g_string_free(str, TRUE);
2043 g_free(rating_symbol);
2045 pref_spacer(group, PREF_PAD_GROUP);
2047 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2049 c_options->slideshow.delay = options->slideshow.delay;
2050 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2051 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2052 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2053 seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2054 SLIDESHOW_SUBSECOND_PRECISION;
2056 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2058 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2060 options->slideshow.delay ? hours : 0.0,
2061 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2062 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2063 spin = pref_spin_new(hbox, ":" , NULL,
2065 options->slideshow.delay ? minutes: 0.0,
2066 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2067 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2068 spin = pref_spin_new(hbox, ":", NULL,
2069 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2070 options->slideshow.delay ? seconds : 10.0,
2071 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2072 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2074 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2075 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2077 pref_spacer(group, PREF_PAD_GROUP);
2079 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2081 pref_spin_new_int(group, _("Decoded image cache size (MiB):"), NULL,
2082 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2083 pref_checkbox_new_int(group, _("Preload next image"),
2084 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2086 pref_checkbox_new_int(group, _("Refresh on file change"),
2087 options->update_on_time_change, &c_options->update_on_time_change);
2090 pref_spacer(group, PREF_PAD_GROUP);
2092 group = pref_group_new(vbox, FALSE, _("Expand menu and toolbar"), GTK_ORIENTATION_VERTICAL);
2094 pref_checkbox_new_int(group, _("Expand menu and toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2095 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2096 gtk_widget_set_tooltip_text(group, _("Expand the menu and toolbar to the full width of the window"));
2098 pref_spacer(group, PREF_PAD_GROUP);
2100 group = pref_group_new(vbox, FALSE, _("Info sidebar heights"), GTK_ORIENTATION_VERTICAL);
2101 pref_label_new(group, _("NOTE! Geeqie must be restarted for changes to take effect"));
2102 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2103 pref_spin_new_int(hbox, _("Keywords:"), NULL,
2105 options->info_keywords.height, &c_options->info_keywords.height);
2106 pref_spin_new_int(hbox, _("Title:"), NULL,
2108 options->info_title.height, &c_options->info_title.height);
2109 pref_spin_new_int(hbox, _("Comment:"), NULL,
2111 options->info_comment.height, &c_options->info_comment.height);
2112 pref_spin_new_int(hbox, _("Rating:"), NULL,
2114 options->info_rating.height, &c_options->info_rating.height);
2116 pref_spacer(group, PREF_PAD_GROUP);
2118 group = pref_group_new(vbox, FALSE, _("Show predefined keyword tree"), GTK_ORIENTATION_VERTICAL);
2120 pref_checkbox_new_int(group, _("Show predefined keyword tree (NOTE! Geeqie must be restarted for change to take effect)"),
2121 options->show_predefined_keyword_tree, &c_options->show_predefined_keyword_tree);
2123 pref_spacer(group, PREF_PAD_GROUP);
2125 net_mon = g_network_monitor_get_default();
2126 geeqie_org = g_network_address_parse_uri(GQ_WEBSITE, 80, NULL);
2127 internet_available = g_network_monitor_can_reach(net_mon, geeqie_org, NULL, NULL);
2128 g_object_unref(geeqie_org);
2130 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2131 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2133 if (!internet_available)
2135 gtk_widget_set_sensitive(group, FALSE);
2138 tz = g_new0(TZData, 1);
2140 path = path_from_utf8(TIMEZONE_DATABASE);
2141 basename = g_path_get_basename(path);
2142 tz->timezone_database_user = g_build_filename(get_rc_dir(), basename, NULL);
2146 if (isfile(tz->timezone_database_user))
2148 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2152 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2155 if (!internet_available)
2157 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"));
2161 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"));
2163 gtk_widget_show(button);
2165 pref_spacer(group, PREF_PAD_GROUP);
2167 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2169 help_search_engine_entry = gtk_entry_new();
2170 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2171 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2172 gtk_widget_show(help_search_engine_entry);
2174 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"));
2176 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2177 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2178 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2179 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2180 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2181 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2182 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2183 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2184 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2185 G_CALLBACK(help_search_engine_entry_icon_cb),
2186 help_search_engine_entry);
2190 static void config_tab_image(GtkWidget *notebook)
2195 GtkWidget *ct_button;
2196 GtkWidget *enlargement_button;
2199 GtkWidget *two_pass;
2201 GtkWidget *gpu_accel;
2204 vbox = scrolled_notebook_page(notebook, _("Image"));
2206 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2208 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2209 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2210 if (options->image.use_clutter_renderer && !options->disable_gpu)
2212 gtk_widget_set_sensitive(table, FALSE);
2216 gpu_accel = pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library (Requires restart)"),
2217 options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2218 if (options->disable_gpu && !options->override_disable_gpu)
2220 gtk_widget_set_sensitive(gpu_accel, FALSE);
2224 two_pass = pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2225 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2226 if (options->image.use_clutter_renderer && !options->disable_gpu)
2228 gtk_widget_set_sensitive(two_pass, FALSE);
2231 c_options->image.zoom_increment = options->image.zoom_increment;
2232 spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2233 0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2234 G_CALLBACK(zoom_increment_cb), NULL);
2235 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2237 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2239 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2240 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2241 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2242 spin = pref_spin_new_int(hbox, NULL, NULL,
2244 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2245 pref_checkbox_link_sensitivity(enlargement_button, spin);
2246 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."));
2248 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2249 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2250 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2251 spin = pref_spin_new_int(hbox, NULL, NULL,
2253 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2254 pref_checkbox_link_sensitivity(ct_button, spin);
2255 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."));
2257 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2259 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2260 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2262 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2263 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2265 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2266 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2268 c_options->image.border_color = options->image.border_color;
2270 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2271 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2273 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2274 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2276 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2277 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2279 group = pref_group_new(vbox, FALSE, _("Convenience"), GTK_ORIENTATION_VERTICAL);
2281 pref_checkbox_new_int(group, _("Auto rotate proofs using Exif information"),
2282 options->image.exif_proof_rotate_enable, &c_options->image.exif_proof_rotate_enable);
2286 static void config_tab_windows(GtkWidget *notebook)
2292 GtkWidget *ct_button;
2295 vbox = scrolled_notebook_page(notebook, _("Windows"));
2297 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2299 ct_button = pref_checkbox_new_int(group, _("Remember window positions"),
2300 options->save_window_positions, &c_options->save_window_positions);
2302 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2303 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2304 pref_checkbox_link_sensitivity(ct_button, button);
2306 button = pref_checkbox_new_int(group, _("Remember window workspace"),
2307 options->save_window_workspace, &c_options->save_window_workspace);
2308 pref_checkbox_link_sensitivity(ct_button, button);
2310 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2311 options->tools_restore_state, &c_options->tools_restore_state);
2313 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2314 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2316 pref_checkbox_new_int(group, _("Show window IDs"),
2317 options->show_window_ids, &c_options->show_window_ids);
2319 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2321 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2322 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2324 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2325 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2326 options->image.limit_window_size, &c_options->image.limit_window_size);
2327 spin = pref_spin_new_int(hbox, NULL, NULL,
2329 options->image.max_window_size, &c_options->image.max_window_size);
2330 pref_checkbox_link_sensitivity(ct_button, spin);
2332 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2334 c_options->fullscreen.screen = options->fullscreen.screen;
2335 c_options->fullscreen.above = options->fullscreen.above;
2336 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2337 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2338 gtk_widget_show(hbox);
2340 pref_checkbox_new_int(group, _("Smooth image flip"),
2341 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2342 pref_checkbox_new_int(group, _("Disable screen saver"),
2343 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2346 #define PRE_FORMATTED_COLUMNS 5
2347 static void config_tab_osd(GtkWidget *notebook)
2353 GtkWidget *image_overlay_template_view;
2354 GtkWidget *scrolled;
2355 GtkWidget *scrolled_pre_formatted;
2356 GtkTextBuffer *buffer;
2358 GtkWidget *subgroup;
2360 vbox = scrolled_notebook_page(notebook, _("OSD"));
2362 image_overlay_template_view = gtk_text_view_new();
2364 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2366 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2368 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2369 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2370 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2371 gtk_widget_show(scrolled_pre_formatted);
2372 gtk_widget_show(subgroup);
2374 pref_line(group, PREF_PAD_GAP);
2376 pref_label_new(group, _("Image overlay template"));
2378 scrolled = gtk_scrolled_window_new(NULL, NULL);
2379 gtk_widget_set_size_request(scrolled, 200, 150);
2380 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2381 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2382 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2383 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2384 gtk_widget_show(scrolled);
2386 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2387 _("Extensive formatting options are shown in the Help file"));
2389 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2390 gtk_widget_show(image_overlay_template_view);
2392 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2394 #if GTK_CHECK_VERSION(3,4,0)
2395 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2396 G_CALLBACK(image_overlay_set_font_cb), notebook);
2398 button = gtk_font_button_new();
2399 gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
2400 gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
2401 g_signal_connect(G_OBJECT(button), "font-set",
2402 G_CALLBACK(image_overlay_set_font_cb),NULL);
2404 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2405 gtk_widget_show(button);
2407 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2408 G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2409 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2410 gtk_widget_show(button);
2412 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2413 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2414 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2415 gtk_widget_show(button);
2416 image_overlay_set_text_colours();
2418 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2419 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2420 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2421 gtk_widget_show(button);
2423 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2424 G_CALLBACK(image_overlay_help_cb), NULL);
2425 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2426 gtk_widget_show(button);
2428 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2429 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2430 g_signal_connect(G_OBJECT(buffer), "changed",
2431 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2433 pref_line(group, PREF_PAD_GAP);
2435 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2436 hbox = gtk_hbox_new(FALSE, 0);
2437 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2438 gtk_widget_show(hbox);
2439 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2440 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2441 gtk_widget_show(label);
2442 pref_spacer(group,TRUE);
2444 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2445 hbox = gtk_hbox_new(FALSE, 0);
2446 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2447 gtk_widget_show(hbox);
2448 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2449 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2450 gtk_widget_show(label);
2451 pref_spacer(group,TRUE);
2453 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2454 hbox = gtk_hbox_new(FALSE, 0);
2455 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2456 gtk_widget_show(hbox);
2457 label = gtk_label_new(_("%path:39%"));
2458 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2459 gtk_widget_show(label);
2460 pref_spacer(group,TRUE);
2462 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2463 hbox = gtk_hbox_new(FALSE, 0);
2464 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2465 gtk_widget_show(hbox);
2466 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%"));
2467 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2468 gtk_widget_show(label);
2469 pref_spacer(group,TRUE);
2471 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2472 hbox = gtk_hbox_new(FALSE, 0);
2473 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2474 gtk_widget_show(hbox);
2475 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2476 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2477 gtk_widget_show(label);
2480 static GtkTreeModel *create_class_model(void)
2482 GtkListStore *model;
2486 /* create list store */
2487 model = gtk_list_store_new(1, G_TYPE_STRING);
2488 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2490 gtk_list_store_append(model, &iter);
2491 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2493 return GTK_TREE_MODEL (model);
2498 static void config_tab_files(GtkWidget *notebook)
2505 GtkWidget *ct_button;
2506 GtkWidget *scrolled;
2507 GtkWidget *filter_view;
2508 GtkCellRenderer *renderer;
2509 GtkTreeSelection *selection;
2510 GtkTreeViewColumn *column;
2512 vbox = scrolled_notebook_page(notebook, _("Files"));
2514 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2516 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2517 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2518 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2519 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2520 pref_checkbox_new_int(group, _("Case sensitive sort"),
2521 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2522 pref_checkbox_new_int(group, _("Natural sort order"),
2523 options->file_sort.natural, &c_options->file_sort.natural);
2524 pref_checkbox_new_int(group, _("Disable file extension checks"),
2525 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2527 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2528 options->file_filter.disable, &c_options->file_filter.disable);
2531 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2533 sidecar_ext_entry = gtk_entry_new();
2534 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2535 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2536 gtk_widget_show(sidecar_ext_entry);
2538 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2540 frame = pref_group_parent(group);
2541 g_signal_connect(G_OBJECT(ct_button), "toggled",
2542 G_CALLBACK(filter_disable_cb), frame);
2543 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2545 scrolled = gtk_scrolled_window_new(NULL, NULL);
2546 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2547 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2548 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2549 gtk_widget_show(scrolled);
2551 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2552 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2553 g_object_unref(filter_store);
2554 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2555 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2557 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2559 column = gtk_tree_view_column_new();
2560 gtk_tree_view_column_set_title(column, _("Filter"));
2561 gtk_tree_view_column_set_resizable(column, TRUE);
2563 renderer = gtk_cell_renderer_toggle_new();
2564 g_signal_connect(G_OBJECT(renderer), "toggled",
2565 G_CALLBACK(filter_store_enable_cb), filter_store);
2566 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2567 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2568 GINT_TO_POINTER(FE_ENABLE), NULL);
2570 renderer = gtk_cell_renderer_text_new();
2571 g_signal_connect(G_OBJECT(renderer), "edited",
2572 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2573 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2574 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2575 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2576 GINT_TO_POINTER(FE_EXTENSION), NULL);
2577 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2579 column = gtk_tree_view_column_new();
2580 gtk_tree_view_column_set_title(column, _("Description"));
2581 gtk_tree_view_column_set_resizable(column, TRUE);
2582 gtk_tree_view_column_set_fixed_width(column, 200);
2583 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2585 renderer = gtk_cell_renderer_text_new();
2586 g_signal_connect(G_OBJECT(renderer), "edited",
2587 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2588 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2589 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2590 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2591 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2592 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2594 column = gtk_tree_view_column_new();
2595 gtk_tree_view_column_set_title(column, _("Class"));
2596 gtk_tree_view_column_set_resizable(column, TRUE);
2597 renderer = gtk_cell_renderer_combo_new();
2598 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2599 "model", create_class_model(),
2604 g_signal_connect(G_OBJECT(renderer), "edited",
2605 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2606 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2607 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2608 GINT_TO_POINTER(FE_CLASS), NULL);
2609 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2611 column = gtk_tree_view_column_new();
2612 gtk_tree_view_column_set_title(column, _("Writable"));
2613 gtk_tree_view_column_set_resizable(column, FALSE);
2614 renderer = gtk_cell_renderer_toggle_new();
2615 g_signal_connect(G_OBJECT(renderer), "toggled",
2616 G_CALLBACK(filter_store_writable_cb), filter_store);
2617 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2618 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2619 GINT_TO_POINTER(FE_WRITABLE), NULL);
2620 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2622 column = gtk_tree_view_column_new();
2623 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2624 gtk_tree_view_column_set_resizable(column, FALSE);
2625 renderer = gtk_cell_renderer_toggle_new();
2626 g_signal_connect(G_OBJECT(renderer), "toggled",
2627 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2628 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2629 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2630 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2631 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2634 filter_store_populate();
2635 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2636 gtk_widget_show(filter_view);
2638 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2640 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2641 G_CALLBACK(filter_default_cb), filter_view);
2642 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2643 gtk_widget_show(button);
2645 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2646 G_CALLBACK(filter_remove_cb), filter_view);
2647 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2648 gtk_widget_show(button);
2650 button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2651 G_CALLBACK(filter_add_cb), filter_view);
2652 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2653 gtk_widget_show(button);
2657 static void config_tab_metadata(GtkWidget *notebook)
2662 GtkWidget *ct_button;
2666 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2669 group = pref_group_new(vbox, FALSE, _("Metadata writing process"), GTK_ORIENTATION_VERTICAL);
2671 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2673 label = pref_label_new(group, _("Metadata are written in the following order. The process ends after first success."));
2674 #if GTK_CHECK_VERSION(3,16,0)
2675 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2676 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2678 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2681 ct_button = pref_checkbox_new_int(group, _("1) Save metadata in image files, or sidecar files, according to the XMP standard"),
2682 options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2684 gtk_widget_set_sensitive(ct_button, FALSE);
2687 pref_checkbox_new_int(group, _("2) Save metadata in '.metadata' folder, local to image folder (non-standard)"),
2688 options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2690 text = g_strdup_printf(_("3) Save metadata in Geeqie private directory '%s'"), get_metadata_cache_dir());
2691 label = pref_label_new(group, text);
2692 #if GTK_CHECK_VERSION(3,16,0)
2693 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2694 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2696 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2698 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2701 group = pref_group_new(vbox, FALSE, _("Step 1: Write to image files"), GTK_ORIENTATION_VERTICAL);
2703 gtk_widget_set_sensitive(group, FALSE);
2706 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2707 pref_checkbox_link_sensitivity(ct_button, hbox);
2709 pref_checkbox_new_int(hbox, _("Store metadata also in legacy IPTC tags (converted according to IPTC4XMP standard)"),
2710 options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2712 pref_checkbox_new_int(hbox, _("Warn if the image files are unwritable"),
2713 options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2715 pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
2716 options->metadata.confirm_write, &c_options->metadata.confirm_write);
2718 pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
2719 options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2721 group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
2723 gtk_widget_set_sensitive(group, FALSE);
2726 pref_checkbox_new_int(group, _("Use GQview legacy metadata format (supports only keywords and comments) instead of XMP"),
2727 options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2730 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2731 pref_checkbox_new_int(group, _("Write the same description tags (keywords, comment, etc.) to all grouped sidecars"),
2732 options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2734 pref_checkbox_new_int(group, _("Allow keywords to differ only in case"),
2735 options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2737 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"),
2738 options->metadata.write_orientation, &c_options->metadata.write_orientation);
2740 gtk_widget_set_sensitive(ct_button, FALSE);
2743 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2745 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"),
2746 options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2748 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2749 pref_checkbox_link_sensitivity(ct_button, hbox);
2751 pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1,
2752 options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2754 pref_checkbox_new_int(group, _("Write metadata on image change"),
2755 options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2757 pref_checkbox_new_int(group, _("Write metadata on directory change"),
2758 options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2760 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2762 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"),
2763 options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2764 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");
2769 typedef struct _KeywordFindData KeywordFindData;
2770 struct _KeywordFindData
2777 GtkWidget *button_close;
2778 GtkWidget *button_stop;
2779 GtkWidget *button_start;
2780 GtkWidget *progress;
2788 guint idle_id; /* event source id */
2791 #define KEYWORD_DIALOG_WIDTH 400
2793 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
2795 GList *list_d = NULL;
2796 GList *list_f = NULL;
2800 filelist_read(dir_fd, &list_f, &list_d);
2804 filelist_read(dir_fd, &list_f, NULL);
2807 list_f = filelist_filter(list_f, FALSE);
2808 list_d = filelist_filter(list_d, TRUE);
2810 kfd->list = g_list_concat(list_f, kfd->list);
2811 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
2814 static void keywords_find_reset(KeywordFindData *kfd)
2816 filelist_free(kfd->list);
2819 filelist_free(kfd->list_dir);
2820 kfd->list_dir = NULL;
2823 static void keywords_find_close_cb(GenericDialog *fd, gpointer data)
2825 KeywordFindData *kfd = data;
2827 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
2829 keywords_find_reset(kfd);
2830 generic_dialog_close(kfd->gd);
2834 static void keywords_find_finish(KeywordFindData *kfd)
2836 keywords_find_reset(kfd);
2838 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
2839 spinner_set_interval(kfd->spinner, -1);
2841 gtk_widget_set_sensitive(kfd->group, TRUE);
2842 gtk_widget_set_sensitive(kfd->button_start, TRUE);
2843 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2844 gtk_widget_set_sensitive(kfd->button_close, TRUE);
2847 static void keywords_find_stop_cb(GenericDialog *fd, gpointer data)
2849 KeywordFindData *kfd = data;
2851 g_idle_remove_by_data(kfd);
2853 keywords_find_finish(kfd);
2856 static gboolean keywords_find_file(gpointer data)
2858 KeywordFindData *kfd = data;
2860 GtkTextBuffer *buffer;
2868 fd = kfd->list->data;
2869 kfd->list = g_list_remove(kfd->list, fd);
2871 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
2872 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2876 gtk_text_buffer_get_end_iter(buffer, &iter);
2877 tmp = g_strconcat(keywords->data, "\n", NULL);
2878 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
2880 keywords = keywords->next;
2883 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
2884 file_data_unref(fd);
2885 string_list_free(keywords);
2889 else if (kfd->list_dir)
2893 fd = kfd->list_dir->data;
2894 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
2896 keywords_find_folder(kfd, fd);
2898 file_data_unref(fd);
2903 keywords_find_finish(kfd);
2908 static void keywords_find_start_cb(GenericDialog *fd, gpointer data)
2910 KeywordFindData *kfd = data;
2913 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
2915 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
2916 parse_out_relatives(path);
2920 warning_dialog(_("Invalid folder"),
2921 _("The specified folder can not be found."),
2922 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
2928 gtk_widget_set_sensitive(kfd->group, FALSE);
2929 gtk_widget_set_sensitive(kfd->button_start, FALSE);
2930 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
2931 gtk_widget_set_sensitive(kfd->button_close, FALSE);
2932 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
2934 dir_fd = file_data_new_dir(path);
2935 keywords_find_folder(kfd, dir_fd);
2936 file_data_unref(dir_fd);
2937 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
2943 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
2945 KeywordFindData *kfd;
2949 kfd = g_new0(KeywordFindData, 1);
2951 kfd->gd = generic_dialog_new(_("Search for keywords"),
2952 "search_for_keywords",
2955 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
2956 kfd->gd->cancel_cb = keywords_find_close_cb;
2957 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
2958 keywords_find_close_cb, FALSE);
2959 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
2960 keywords_find_start_cb, FALSE);
2961 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
2962 keywords_find_stop_cb, FALSE);
2963 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2965 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
2967 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
2968 pref_spacer(hbox, PREF_PAD_INDENT);
2969 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2971 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2972 pref_label_new(hbox, _("Folder:"));
2974 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
2975 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
2976 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
2977 gtk_widget_show(label);
2979 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
2981 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
2982 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2984 kfd->progress = gtk_entry_new();
2985 gtk_widget_set_can_focus(kfd->progress, FALSE);
2986 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
2987 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
2988 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
2989 gtk_widget_show(kfd->progress);
2991 kfd->spinner = spinner_new(NULL, -1);
2992 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
2993 gtk_widget_show(kfd->spinner);
2997 gtk_widget_show(kfd->gd->dialog);
3000 static void keywords_find_cb(GtkWidget *widget, gpointer data)
3002 const gchar *path = layout_get_path(NULL);
3004 if (!path || !*path) path = homedir();
3005 keywords_find_dialog(widget, path);
3008 static void config_tab_keywords_save()
3010 GtkTextIter start, end;
3011 GtkTextBuffer *buffer;
3012 GList *kw_list = NULL;
3018 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3019 gtk_text_buffer_get_bounds(buffer, &start, &end);
3021 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3023 kw_split = strtok(buffer_text, "\n");
3024 while (kw_split != NULL)
3030 if (g_strcmp0(work->data, kw_split) == 0)
3039 kw_list = g_list_append(kw_list, g_strdup(kw_split));
3041 kw_split = strtok(NULL, "\n");
3044 keyword_list_set(kw_list);
3046 string_list_free(kw_list);
3047 g_free(buffer_text);
3050 static void config_tab_keywords(GtkWidget *notebook)
3056 GtkWidget *scrolled;
3058 GtkTextBuffer *buffer;
3061 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3063 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3065 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3067 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
3068 G_CALLBACK(keywords_find_cb), keyword_text);
3069 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
3072 keyword_text = gtk_text_view_new();
3073 gtk_widget_set_size_request(keyword_text, 20, 20);
3074 scrolled = gtk_scrolled_window_new(NULL, NULL);
3075 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3076 gtk_widget_show(scrolled);
3078 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
3079 gtk_widget_show(keyword_text);
3081 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3083 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3084 gtk_text_buffer_create_tag(buffer, "monospace",
3085 "family", "monospace", NULL);
3087 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3088 gtk_text_buffer_get_start_iter(buffer, &iter);
3089 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3092 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3094 GList *kwl = keyword_list_get();
3095 kwl = g_list_first(kwl);
3098 gtk_text_buffer_get_end_iter (buffer, &iter);
3099 tmp = g_strconcat(kwl->data, "\n", NULL);
3100 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3105 gtk_text_buffer_set_modified(buffer, FALSE);
3112 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3114 gint *option = data;
3116 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3120 *option = INTENT_PERCEPTUAL;
3123 *option = INTENT_RELATIVE_COLORIMETRIC;
3126 *option = INTENT_SATURATION;
3129 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3134 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3135 gint option, gint *option_c)
3142 pref_table_label(table, column, row, text, 0.0);
3144 combo = gtk_combo_box_text_new();
3146 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3147 if (option == INTENT_PERCEPTUAL) current = 0;
3148 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3149 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3150 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3151 if (option == INTENT_SATURATION) current = 2;
3152 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3153 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3155 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3157 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3159 g_signal_connect(G_OBJECT(combo), "changed",
3160 G_CALLBACK(intent_menu_cb), option_c);
3162 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
3163 gtk_widget_show(combo);
3167 static void config_tab_color(GtkWidget *notebook)
3176 vbox = scrolled_notebook_page(notebook, _("Color management"));
3178 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3180 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3183 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3184 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3186 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3187 pref_label_bold(label, TRUE, FALSE);
3189 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3190 pref_label_bold(label, TRUE, FALSE);
3192 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3193 pref_label_bold(label, TRUE, FALSE);
3195 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3200 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3201 pref_table_label(table, 0, i + 1, buf, 1.0);
3204 entry = gtk_entry_new();
3205 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3206 if (options->color_profile.input_name[i])
3208 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3210 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3211 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3212 gtk_widget_show(entry);
3213 color_profile_input_name_entry[i] = entry;
3215 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3216 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3217 gtk_widget_set_size_request(entry, 160, -1);
3218 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3219 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3220 gtk_widget_show(tabcomp);
3221 color_profile_input_file_entry[i] = entry;
3224 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3226 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3228 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3229 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3231 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3233 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3234 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3235 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3236 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3237 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3239 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3241 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3243 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3245 gtk_widget_show(tabcomp);
3248 /* advanced entry tab */
3249 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer data)
3251 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3253 c_options->file_ops.use_system_trash = FALSE;
3254 c_options->file_ops.no_trash = FALSE;
3258 static void use_system_trash_cb(GtkWidget *widget, gpointer data)
3260 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3262 c_options->file_ops.use_system_trash = TRUE;
3263 c_options->file_ops.no_trash = FALSE;
3267 static void use_no_cache_cb(GtkWidget *widget, gpointer data)
3269 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3271 c_options->file_ops.no_trash = TRUE;
3275 static void config_tab_behavior(GtkWidget *notebook)
3282 GtkWidget *ct_button;
3286 GtkWidget *with_rename;
3287 GtkWidget *collections_on_top;
3288 GtkWidget *hide_window_in_fullscreen;
3289 GtkWidget *checkbox;
3291 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3293 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3295 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3296 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3297 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3298 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3299 pref_checkbox_new_int(group, _("Enable Delete key"),
3300 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3302 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3303 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3305 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3306 pref_checkbox_link_sensitivity(ct_button, hbox);
3308 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3309 pref_label_new(hbox, _("Folder:"));
3311 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3312 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3313 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3314 gtk_widget_show(tabcomp);
3316 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3317 pref_checkbox_link_sensitivity(ct_button, hbox);
3319 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3320 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MiB"),
3321 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3322 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3323 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3324 G_CALLBACK(safe_delete_view_cb), NULL);
3325 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3326 gtk_widget_show(button);
3328 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3329 G_CALLBACK(safe_delete_clear_cb), NULL);
3330 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3331 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3332 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3334 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3335 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3337 gtk_widget_show(button);
3339 pref_spacer(group, PREF_PAD_GROUP);
3342 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3344 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3345 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3347 pref_checkbox_new_int(group, _("In place renaming"),
3348 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3350 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3351 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3353 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3354 options->marks_save, &c_options->marks_save);
3355 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3357 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3358 options->with_rename, &c_options->with_rename);
3359 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3361 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3362 options->collections_on_top, &c_options->collections_on_top);
3363 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3365 hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3366 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3367 gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice");
3369 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3370 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3372 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3373 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3375 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3376 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3378 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3379 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3381 pref_spacer(group, PREF_PAD_GROUP);
3383 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3385 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3386 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3387 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3388 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3389 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3390 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3391 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3392 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3393 pref_checkbox_new_int(group, _("Play video by left click on image"),
3394 options->image_l_click_video, &c_options->image_l_click_video);
3395 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3396 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3398 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3399 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3400 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3401 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3402 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3404 pref_spacer(group, PREF_PAD_GROUP);
3406 group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3408 checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3409 options->override_disable_gpu, &c_options->override_disable_gpu);
3410 gtk_widget_set_tooltip_text(checkbox, "Contact the developers for usage");
3413 pref_spacer(group, PREF_PAD_GROUP);
3415 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3417 pref_spin_new_int(group, _("Debug level:"), NULL,
3418 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3420 pref_checkbox_new_int(group, _("Timer data"),
3421 options->log_window.timer_data, &c_options->log_window.timer_data);
3423 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3424 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3428 /* accelerators tab */
3429 static void config_tab_accelerators(GtkWidget *notebook)
3435 GtkWidget *scrolled;
3436 GtkWidget *accel_view;
3437 GtkCellRenderer *renderer;
3438 GtkTreeSelection *selection;
3439 GtkTreeViewColumn *column;
3441 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3443 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3445 scrolled = gtk_scrolled_window_new(NULL, NULL);
3446 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3447 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3448 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3449 gtk_widget_show(scrolled);
3451 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3453 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3454 g_object_unref(accel_store);
3455 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3456 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3458 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3460 renderer = gtk_cell_renderer_text_new();
3462 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3467 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3468 gtk_tree_view_column_set_resizable(column, TRUE);
3469 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3472 renderer = gtk_cell_renderer_accel_new();
3473 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3474 G_CALLBACK(accel_store_cleared_cb), accel_store);
3475 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3476 G_CALLBACK(accel_store_edited_cb), accel_store);
3479 g_object_set (renderer,
3481 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3484 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3489 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3490 gtk_tree_view_column_set_resizable(column, TRUE);
3491 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3493 renderer = gtk_cell_renderer_text_new();
3495 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3500 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3501 gtk_tree_view_column_set_resizable(column, TRUE);
3502 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3504 renderer = gtk_cell_renderer_text_new();
3506 column = gtk_tree_view_column_new_with_attributes("Accel",
3511 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3512 gtk_tree_view_column_set_resizable(column, TRUE);
3513 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3515 accel_store_populate();
3516 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3517 gtk_widget_show(accel_view);
3519 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3521 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3522 G_CALLBACK(accel_default_cb), accel_view);
3523 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3524 gtk_widget_show(button);
3526 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3527 G_CALLBACK(accel_reset_cb), accel_view);
3528 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3529 gtk_widget_show(button);
3532 /* toolbar main tab */
3533 static void config_tab_toolbar_main(GtkWidget *notebook)
3536 GtkWidget *toolbardata;
3539 lw = layout_window_list->data;
3541 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3543 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3544 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3545 gtk_widget_show(vbox);
3548 /* toolbar status tab */
3549 static void config_tab_toolbar_status(GtkWidget *notebook)
3552 GtkWidget *toolbardata;
3555 lw = layout_window_list->data;
3557 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3559 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3560 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3561 gtk_widget_show(vbox);
3565 static void config_tab_stereo(GtkWidget *notebook)
3573 GtkWidget *fs_button;
3574 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3576 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3578 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3579 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3581 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3582 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3583 pref_checkbox_new_int(box, _("Mirror left image"),
3584 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3585 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3586 pref_checkbox_new_int(box, _("Flip left image"),
3587 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3588 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3589 pref_checkbox_new_int(box, _("Mirror right image"),
3590 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3591 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3592 pref_checkbox_new_int(box, _("Flip right image"),
3593 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3594 pref_checkbox_new_int(group, _("Swap left and right images"),
3595 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3596 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3597 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3599 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3600 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3601 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3602 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3603 pref_checkbox_link_sensitivity(fs_button, box2);
3604 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3605 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3606 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3607 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3608 pref_checkbox_new_int(box, _("Mirror left image"),
3609 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3610 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3611 pref_checkbox_new_int(box, _("Flip left image"),
3612 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3613 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3614 pref_checkbox_new_int(box, _("Mirror right image"),
3615 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3616 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3617 pref_checkbox_new_int(box, _("Flip right image"),
3618 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3619 pref_checkbox_new_int(box2, _("Swap left and right images"),
3620 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3621 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3622 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3624 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3625 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3626 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3627 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3628 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
3629 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3630 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
3631 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3632 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
3633 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3634 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
3635 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3636 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
3637 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3641 /* Main preferences window */
3642 static void config_window_create(void)
3644 GtkWidget *win_vbox;
3646 GtkWidget *notebook;
3648 GtkWidget *ct_button;
3650 if (!c_options) c_options = init_options(NULL);
3652 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3653 DEBUG_NAME(configwindow);
3654 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3655 g_signal_connect(G_OBJECT(configwindow), "delete_event",
3656 G_CALLBACK(config_window_delete), NULL);
3657 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
3658 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
3659 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
3661 win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
3662 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
3663 gtk_widget_show(win_vbox);
3665 notebook = gtk_notebook_new();
3666 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
3667 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
3668 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
3670 config_tab_general(notebook);
3671 config_tab_image(notebook);
3672 config_tab_osd(notebook);
3673 config_tab_windows(notebook);
3674 config_tab_accelerators(notebook);
3675 config_tab_files(notebook);
3676 config_tab_metadata(notebook);
3677 config_tab_keywords(notebook);
3678 config_tab_color(notebook);
3679 config_tab_stereo(notebook);
3680 config_tab_behavior(notebook);
3681 config_tab_toolbar_main(notebook);
3682 config_tab_toolbar_status(notebook);
3684 hbox = gtk_hbutton_box_new();
3685 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
3686 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
3687 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
3688 gtk_widget_show(hbox);
3690 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
3691 G_CALLBACK(config_window_help_cb), notebook);
3692 gtk_container_add(GTK_CONTAINER(hbox), button);
3693 gtk_widget_set_can_default(button, TRUE);
3694 gtk_widget_show(button);
3696 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
3697 G_CALLBACK(config_window_ok_cb), NULL);
3698 gtk_container_add(GTK_CONTAINER(hbox), button);
3699 gtk_widget_set_can_default(button, TRUE);
3700 gtk_widget_grab_default(button);
3701 gtk_widget_show(button);
3705 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
3706 G_CALLBACK(config_window_close_cb), NULL);
3707 gtk_container_add(GTK_CONTAINER(hbox), button);
3708 gtk_widget_set_can_default(button, TRUE);
3709 gtk_widget_show(button);
3711 if (!generic_dialog_get_alternative_button_order(configwindow))
3713 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
3716 gtk_widget_show(notebook);
3718 gtk_widget_show(configwindow);
3722 *-----------------------------------------------------------------------------
3723 * config window show (public)
3724 *-----------------------------------------------------------------------------
3727 void show_config_window(void)
3731 gtk_window_present(GTK_WINDOW(configwindow));
3735 config_window_create();
3744 void show_about_window(LayoutWindow *lw)
3746 GdkPixbuf *pixbuf_logo;
3747 GdkPixbuf *pixbuf_icon;
3748 gchar *authors[1000];
3753 gchar *timezone_path;
3757 #define LINE_LENGTH 1000
3758 gchar line[LINE_LENGTH];
3760 copyright = g_string_new(NULL);
3761 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");
3763 path = path_from_utf8(TIMEZONE_DATABASE);
3764 basename = g_path_get_basename(path);
3765 timezone_path = g_build_filename(get_rc_dir(), basename, NULL);
3766 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
3768 cd = ZDOpenDatabase(timezone_path);
3771 copyright = g_string_append(copyright, ZDGetNotice(cd));
3772 ZDCloseDatabase(cd);
3776 g_free(timezone_path);
3780 path = g_build_filename(GQ_HELPDIR, "AUTHORS", NULL);
3781 fp = fopen(path, "r");
3784 while(fgets(line, LINE_LENGTH, fp))
3786 /* get rid of ending \n from fgets */
3787 line[strlen(line) - 1] = '\0';
3788 authors[i_authors] = g_strdup(line);
3791 authors[i_authors] = NULL;
3796 comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
3797 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
3799 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
3800 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
3801 gtk_show_about_dialog(GTK_WINDOW(lw->window),
3802 "title", _("About Geeqie"),
3804 "program-name", GQ_APPNAME,
3806 "logo", pixbuf_logo,
3807 "icon", pixbuf_icon,
3808 "website", GQ_WEBSITE,
3809 "website-label", "Website",
3810 "comments", comment,
3812 "translator-credits", _("translator-credits"),
3813 "wrap-license", TRUE,
3814 "license", copyright->str,
3817 g_string_free(copyright, TRUE);
3820 while(n < i_authors)
3830 static void image_overlay_set_text_colours()
3832 c_options->image_overlay.text_red = options->image_overlay.text_red;
3833 c_options->image_overlay.text_green = options->image_overlay.text_green;
3834 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
3835 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
3836 c_options->image_overlay.background_red = options->image_overlay.background_red;
3837 c_options->image_overlay.background_green = options->image_overlay.background_green;
3838 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
3839 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
3843 *-----------------------------------------------------------------------------
3844 * timezone database routines
3845 *-----------------------------------------------------------------------------
3848 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
3850 GError *error = NULL;
3852 gchar *tmp_filename;
3854 if (!g_cancellable_is_cancelled(tz->cancellable))
3856 generic_dialog_close(tz->gd);
3860 if (g_file_copy_finish(G_FILE(source_object), res, &error))
3862 tmp_filename = g_file_get_parse_name(tz->tmp_g_file);
3863 move_file(tmp_filename, tz->timezone_database_user);
3864 g_free(tmp_filename);
3868 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3871 g_file_delete(tz->tmp_g_file, NULL, &error);
3872 g_object_unref(tz->tmp_g_file);
3873 tz->tmp_g_file = NULL;
3874 g_object_unref(tz->cancellable);
3875 g_object_unref(tz->timezone_database_gq);
3878 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
3882 if (!g_cancellable_is_cancelled(tz->cancellable))
3884 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
3888 static void timezone_cancel_button_cb(GenericDialog *gd, gpointer data)
3892 g_cancellable_cancel(tz->cancellable);
3895 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
3898 GError *error = NULL;
3899 GFileIOStream *io_stream;
3906 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
3910 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3911 log_printf("Error: Download timezone database failed:\n%s", error->message);
3912 g_error_free(error);
3913 g_object_unref(tz->tmp_g_file);
3917 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE);
3919 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
3921 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
3923 tz->progress = gtk_progress_bar_new();
3924 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
3925 gtk_widget_show(tz->progress);
3927 gtk_widget_show(tz->gd->dialog);
3928 tz->cancellable = g_cancellable_new();
3929 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);
3931 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
3934 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */