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;
381 options->circular_selection_lists = c_options->circular_selection_lists;
383 options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
384 options->dnd_icon_size = c_options->dnd_icon_size;
385 options->clipboard_selection = c_options->clipboard_selection;
386 options->dnd_default_action = c_options->dnd_default_action;
388 options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
389 options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
390 options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
391 options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
392 options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
393 options->metadata.confirm_write = c_options->metadata.confirm_write;
394 options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
395 options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
396 options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
397 options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
398 options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
399 options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
400 options->metadata.write_orientation = c_options->metadata.write_orientation;
401 options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
402 (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
403 (c_options->stereo.tmp.flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
404 (c_options->stereo.tmp.mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
405 (c_options->stereo.tmp.flip_left ? PR_STEREO_FLIP_LEFT : 0) |
406 (c_options->stereo.tmp.swap ? PR_STEREO_SWAP : 0) |
407 (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
408 options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
409 (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
410 (c_options->stereo.tmp.fs_flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
411 (c_options->stereo.tmp.fs_mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
412 (c_options->stereo.tmp.fs_flip_left ? PR_STEREO_FLIP_LEFT : 0) |
413 (c_options->stereo.tmp.fs_swap ? PR_STEREO_SWAP : 0) |
414 (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
415 options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
416 options->stereo.fixed_w = c_options->stereo.fixed_w;
417 options->stereo.fixed_h = c_options->stereo.fixed_h;
418 options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
419 options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
420 options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
421 options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
423 options->info_keywords.height = c_options->info_keywords.height;
424 options->info_title.height = c_options->info_title.height;
425 options->info_comment.height = c_options->info_comment.height;
426 options->info_rating.height = c_options->info_rating.height;
428 options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
429 options->expand_menu_toolbar = c_options->expand_menu_toolbar;
431 options->marks_save = c_options->marks_save;
432 options->with_rename = c_options->with_rename;
433 options->collections_on_top = c_options->collections_on_top;
434 options->hide_window_in_fullscreen = c_options->hide_window_in_fullscreen;
435 config_entry_to_option(help_search_engine_entry, &options->help_search_engine, NULL);
437 options->read_metadata_in_idle = c_options->read_metadata_in_idle;
439 options->star_rating.star = c_options->star_rating.star;
440 options->star_rating.rejected = c_options->star_rating.rejected;
442 set_debug_level(debug_c);
446 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
448 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
449 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
451 config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
452 options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
453 if (options->color_profile.render_intent != c_options->color_profile.render_intent)
455 options->color_profile.render_intent = c_options->color_profile.render_intent;
460 options->mouse_button_8 = c_options->mouse_button_8;
461 options->mouse_button_9 = c_options->mouse_button_9;
463 options->override_disable_gpu = c_options->override_disable_gpu;
465 config_tab_keywords_save();
467 image_options_sync();
472 layout_refresh(NULL);
475 if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, NULL);
477 toolbar_apply(TOOLBAR_MAIN);
478 toolbar_apply(TOOLBAR_STATUS);
482 *-----------------------------------------------------------------------------
483 * config window main button callbacks (private)
484 *-----------------------------------------------------------------------------
487 static void config_window_close_cb(GtkWidget *widget, gpointer data)
489 gtk_widget_destroy(configwindow);
494 static void config_window_help_cb(GtkWidget *widget, gpointer data)
496 GtkWidget *notebook = data;
499 static gchar *html_section[] =
501 "GuideOptionsGeneral.html",
502 "GuideOptionsImage.html",
503 "GuideOptionsOSD.html",
504 "GuideOptionsWindow.html",
505 "GuideOptionsKeyboard.html",
506 "GuideOptionsFiltering.html",
507 "GuideOptionsMetadata.html",
508 "GuideOptionsKeywords.html",
509 "GuideOptionsColor.html",
510 "GuideOptionsStereo.html",
511 "GuideOptionsBehavior.html",
512 "GuideOptionsToolbar.html",
513 "GuideOptionsToolbar.html"
516 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
517 help_window_show(html_section[i]);
520 static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpointer data)
522 config_window_close_cb(NULL, NULL);
526 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
529 lw = layout_window_list->data;
531 config_window_apply();
532 layout_util_sync(lw);
533 save_options(options);
534 config_window_close_cb(NULL, NULL);
538 *-----------------------------------------------------------------------------
539 * config window setup (private)
540 *-----------------------------------------------------------------------------
543 static void quality_menu_cb(GtkWidget *combo, gpointer data)
547 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
551 *option = GDK_INTERP_NEAREST;
554 *option = GDK_INTERP_TILES;
557 *option = GDK_INTERP_BILINEAR;
562 static void dnd_default_action_selection_menu_cb(GtkWidget *combo, gpointer data)
566 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
570 *option = DND_ACTION_ASK;
573 *option = DND_ACTION_COPY;
576 *option = DND_ACTION_MOVE;
580 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
584 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
587 *option = CLIPBOARD_PRIMARY;
590 *option = CLIPBOARD_CLIPBOARD;
593 *option = CLIPBOARD_BOTH;
596 *option = CLIPBOARD_BOTH;
600 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
601 guint option, guint *option_c)
608 pref_table_label(table, column, row, text, 0.0);
610 combo = gtk_combo_box_text_new();
612 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
613 if (option == GDK_INTERP_NEAREST) current = 0;
614 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
615 if (option == GDK_INTERP_TILES) current = 1;
616 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear (best, but slowest)"));
617 if (option == GDK_INTERP_BILINEAR) current = 2;
619 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
621 g_signal_connect(G_OBJECT(combo), "changed",
622 G_CALLBACK(quality_menu_cb), option_c);
624 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
625 gtk_widget_show(combo);
628 static void add_dnd_default_action_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, DnDAction option, DnDAction *option_c)
635 pref_table_label(table, column, row, text, 0.0);
637 combo = gtk_combo_box_text_new();
639 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Ask"));
640 if (option == DND_ACTION_ASK) current = 0;
641 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Copy"));
642 if (option == DND_ACTION_COPY) current = 1;
643 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Move"));
644 if (option == DND_ACTION_MOVE) current = 2;
646 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
648 g_signal_connect(G_OBJECT(combo), "changed",
649 G_CALLBACK(dnd_default_action_selection_menu_cb), option_c);
651 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
652 gtk_widget_show(combo);
655 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
656 gint option, gint *option_c)
663 pref_table_label(table, column, row, text, 0.0);
665 combo = gtk_combo_box_text_new();
667 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Primary"));
668 if (option == CLIPBOARD_PRIMARY) current = 0;
669 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Clipboard"));
670 if (option == CLIPBOARD_CLIPBOARD) current = 1;
671 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Both"));
672 if (option == CLIPBOARD_BOTH) current = 2;
674 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
676 g_signal_connect(G_OBJECT(combo), "changed",
677 G_CALLBACK(clipboard_selection_menu_cb), option_c);
679 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
680 gtk_widget_show(combo);
683 typedef struct _UseableMouseItems UseableMouseItems;
684 struct _UseableMouseItems
686 gchar *name; /* GtkActionEntry terminology */
691 static const UseableMouseItems useable_mouse_items[] = {
693 {"FirstImage", N_("First Image"), GTK_STOCK_GOTO_TOP},
694 {"PrevImage", N_("Previous Image"), GTK_STOCK_GO_UP},
695 {"NextImage", N_("Next Image"), GTK_STOCK_GO_DOWN},
696 {"LastImage", N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
697 {"Back", N_("Back"), GTK_STOCK_GO_BACK},
698 {"Forward", N_("Forward"), GTK_STOCK_GO_FORWARD},
699 {"Home", N_("Home"), GTK_STOCK_HOME},
700 {"Up", N_("Up"), GTK_STOCK_GO_UP},
701 {"FirstPage", N_("First page"), GTK_STOCK_MEDIA_PREVIOUS},
702 {"LastPage", N_("Last Page"), GTK_STOCK_MEDIA_NEXT},
703 {"NextPage", N_("Next page"), GTK_STOCK_MEDIA_FORWARD},
704 {"PrevPage", N_("Previous Page"), GTK_STOCK_MEDIA_REWIND},
705 {"NewWindow", N_("New _window"), GTK_STOCK_NEW},
706 {"NewCollection", N_("New collection"), GTK_STOCK_INDEX},
707 {"OpenCollection", N_("Open collection"), GTK_STOCK_OPEN},
708 {"Search", N_("Search"), GTK_STOCK_FIND},
709 {"FindDupes", N_("Find duplicates"), GTK_STOCK_FIND},
710 {"NewFolder", N_("New folder"),GTK_STOCK_DIRECTORY},
711 {"Copy", N_("Copy"), GTK_STOCK_COPY},
712 {"Move", N_("Move"), PIXBUF_INLINE_ICON_MOVE},
713 {"Rename", N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
714 {"Delete", N_("Delete"), GTK_STOCK_DELETE},
715 {"CloseWindow", N_("Close Window"), GTK_STOCK_CLOSE},
716 {"PanView", N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
717 {"SelectAll", N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
718 {"SelectNone", N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
719 {"SelectInvert", N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
720 {"ShowFileFilter", N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
721 {"RectangularSelection", N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
722 {"Print", N_("Print"), GTK_STOCK_PRINT},
723 {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
724 {"LayoutConfig", N_("Configure this window"), GTK_STOCK_PREFERENCES},
725 {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
726 {"RotateCW", N_("Rotate clockwise 90°"), PIXBUF_INLINE_ICON_CW},
727 {"RotateCCW", N_("Rotate counterclockwise 90°"), PIXBUF_INLINE_ICON_CCW},
728 {"Rotate180", N_("Rotate 180°"), PIXBUF_INLINE_ICON_180},
729 {"Mirror", N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
730 {"Flip", N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
731 {"AlterNone", N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
732 {"ZoomIn", N_("Zoom in"), GTK_STOCK_ZOOM_IN},
733 {"ZoomOut", N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
734 {"Zoom100", N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
735 {"ZoomFit", N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
736 {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
737 {"ZoomFillVert", N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
738 {"Zoom200", N_("Zoom 2:1"), GTK_STOCK_FILE},
739 {"Zoom300", N_("Zoom 3:1"), GTK_STOCK_FILE},
740 {"Zoom400", N_("Zoom 4:1"), GTK_STOCK_FILE},
741 {"Zoom50", N_("Zoom 1:2"), GTK_STOCK_FILE},
742 {"Zoom33", N_("Zoom1:3"), GTK_STOCK_FILE},
743 {"Zoom25", N_("Zoom 1:4"), GTK_STOCK_FILE},
744 {"ConnectZoomIn", N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
745 {"SplitPaneSync", N_("Split Pane Sync"), PIXBUF_INLINE_SPLIT_PANE_SYNC},
746 {"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
747 {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
748 {"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
749 {"SlideShowPause", N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
750 {"SlideShowFaster", N_("Slideshow Faster"), GTK_STOCK_FILE},
751 {"SlideShowSlower", N_("Slideshow Slower"), GTK_STOCK_FILE},
752 {"Refresh", N_("Refresh"), GTK_STOCK_REFRESH},
753 {"HelpContents", N_("Help"), GTK_STOCK_HELP},
754 {"ExifWin", N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
755 {"Thumbnails", N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
756 {"ShowMarks", N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
757 {"ImageGuidelines", N_("Show guidelines"), PIXBUF_INLINE_ICON_GUIDELINES},
758 {"DrawRectangle", N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
759 {"FloatTools", N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
760 {"SBar", N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
761 {"SBarSort", N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
762 {"Quit", N_("Quit"), GTK_STOCK_QUIT},
766 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
768 gchar **option = data;
771 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
773 const UseableMouseItems *list = useable_mouse_items;
777 if (g_strcmp0(list->label, label) == 0)
785 *option = g_strdup(list->name);
789 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
790 gchar *option, gchar **option_c)
798 pref_table_label(table, column, row, text, 0.0);
800 combo = gtk_combo_box_text_new();
802 const UseableMouseItems *list = useable_mouse_items;
806 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
807 if (g_strcmp0(list->name, option) == 0)
815 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
817 g_signal_connect(G_OBJECT(combo), "changed",
818 G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
820 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
821 gtk_widget_show(combo);
824 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
828 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
831 if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
833 c_options->thumbnails.max_width = thumb_size_list[n].w;
834 c_options->thumbnails.max_height = thumb_size_list[n].h;
838 c_options->thumbnails.max_width = options->thumbnails.max_width;
839 c_options->thumbnails.max_height = options->thumbnails.max_height;
843 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
849 c_options->thumbnails.max_width = options->thumbnails.max_width;
850 c_options->thumbnails.max_height = options->thumbnails.max_height;
852 pref_table_label(table, column, row, text, 0.0);
854 combo = gtk_combo_box_text_new();
857 for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
862 w = thumb_size_list[i].w;
863 h = thumb_size_list[i].h;
865 buf = g_strdup_printf("%d x %d", w, h);
866 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
869 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
876 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
877 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
883 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
884 g_signal_connect(G_OBJECT(combo), "changed",
885 G_CALLBACK(thumb_size_menu_cb), NULL);
887 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
888 gtk_widget_show(combo);
891 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
895 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
899 *option = PR_STEREO_NONE;
902 *option = PR_STEREO_ANAGLYPH_RC;
905 *option = PR_STEREO_ANAGLYPH_GM;
908 *option = PR_STEREO_ANAGLYPH_YB;
911 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
914 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
917 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
920 *option = PR_STEREO_ANAGLYPH_DB_RC;
923 *option = PR_STEREO_ANAGLYPH_DB_GM;
926 *option = PR_STEREO_ANAGLYPH_DB_YB;
929 *option = PR_STEREO_HORIZ;
932 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
935 *option = PR_STEREO_VERT;
938 *option = PR_STEREO_VERT | PR_STEREO_HALF;
941 *option = PR_STEREO_FIXED;
946 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
947 gint option, gint *option_c, gboolean add_fixed)
954 pref_table_label(table, column, row, text, 0.0);
956 combo = gtk_combo_box_text_new();
958 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
960 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
961 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
962 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
963 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
964 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
965 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
966 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
967 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
968 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
969 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
970 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
971 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
972 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
973 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
974 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
975 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
976 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
977 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
979 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
980 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
981 if (option & PR_STEREO_HORIZ)
984 if (option & PR_STEREO_HALF) current = 11;
987 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
988 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
989 if (option & PR_STEREO_VERT)
992 if (option & PR_STEREO_HALF) current = 13;
997 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
998 if (option & PR_STEREO_FIXED) current = 14;
1001 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1003 g_signal_connect(G_OBJECT(combo), "changed",
1004 G_CALLBACK(stereo_mode_menu_cb), option_c);
1006 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1007 gtk_widget_show(combo);
1010 static void video_menu_cb(GtkWidget *combo, gpointer data)
1012 gchar **option = data;
1014 EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
1018 static void video_menu_populate(gpointer data, gpointer user_data)
1020 GtkWidget *combo = user_data;
1021 EditorDescription *ed = data;
1023 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1026 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1027 gchar *option, gchar **option_c)
1031 /* use lists since they are sorted */
1032 GList *eds = editor_list_get();
1036 pref_table_label(table, column, row, text, 0.0);
1038 combo = gtk_combo_box_text_new();
1039 g_list_foreach(eds,video_menu_populate,(gpointer)combo);
1040 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1042 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1044 g_signal_connect(G_OBJECT(combo), "changed",
1045 G_CALLBACK(video_menu_cb), option_c);
1047 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1048 gtk_widget_show(combo);
1051 static void filter_store_populate(void)
1055 if (!filter_store) return;
1057 gtk_list_store_clear(filter_store);
1059 work = filter_get_list();
1068 gtk_list_store_append(filter_store, &iter);
1069 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1073 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1074 gchar *new_text, gpointer data)
1076 GtkWidget *model = data;
1077 FilterEntry *fe = data;
1081 if (!new_text || strlen(new_text) < 1) return;
1083 tpath = gtk_tree_path_new_from_string(path_str);
1084 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1085 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1087 g_free(fe->extensions);
1088 fe->extensions = g_strdup(new_text);
1090 gtk_tree_path_free(tpath);
1094 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1095 gchar *new_text, gpointer data)
1097 GtkWidget *model = data;
1098 FilterEntry *fe = data;
1103 if (!new_text || !new_text[0]) return;
1105 tpath = gtk_tree_path_new_from_string(path_str);
1106 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1107 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1109 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1111 if (strcmp(new_text, _(format_class_list[i])) == 0)
1118 gtk_tree_path_free(tpath);
1122 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1123 gchar *new_text, gpointer data)
1125 GtkWidget *model = data;
1130 if (!new_text || !new_text[0]) return;
1132 tpath = gtk_tree_path_new_from_string(path_str);
1133 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1134 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1136 g_free(fe->description);
1137 fe->description = g_strdup(new_text);
1139 gtk_tree_path_free(tpath);
1142 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
1143 gchar *path_str, gpointer data)
1145 GtkWidget *model = data;
1150 tpath = gtk_tree_path_new_from_string(path_str);
1151 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1152 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1154 fe->enabled = !fe->enabled;
1156 gtk_tree_path_free(tpath);
1160 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
1161 gchar *path_str, gpointer data)
1163 GtkWidget *model = data;
1168 tpath = gtk_tree_path_new_from_string(path_str);
1169 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1170 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1172 fe->writable = !fe->writable;
1173 if (fe->writable) fe->allow_sidecar = FALSE;
1175 gtk_tree_path_free(tpath);
1179 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
1180 gchar *path_str, gpointer data)
1182 GtkWidget *model = data;
1187 tpath = gtk_tree_path_new_from_string(path_str);
1188 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1189 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1191 fe->allow_sidecar = !fe->allow_sidecar;
1192 if (fe->allow_sidecar) fe->writable = FALSE;
1194 gtk_tree_path_free(tpath);
1198 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1199 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1203 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1205 switch (GPOINTER_TO_INT(data))
1208 g_object_set(GTK_CELL_RENDERER(cell),
1209 "active", fe->enabled, NULL);
1212 g_object_set(GTK_CELL_RENDERER(cell),
1213 "text", fe->extensions, NULL);
1215 case FE_DESCRIPTION:
1216 g_object_set(GTK_CELL_RENDERER(cell),
1217 "text", fe->description, NULL);
1220 g_object_set(GTK_CELL_RENDERER(cell),
1221 "text", _(format_class_list[fe->file_class]), NULL);
1224 g_object_set(GTK_CELL_RENDERER(cell),
1225 "active", fe->writable, NULL);
1227 case FE_ALLOW_SIDECAR:
1228 g_object_set(GTK_CELL_RENDERER(cell),
1229 "active", fe->allow_sidecar, NULL);
1234 static gboolean filter_add_scroll(gpointer data)
1238 GtkCellRenderer *cell;
1239 GtkTreeViewColumn *column;
1242 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1243 path = gtk_tree_path_new_from_indices(rows-1, -1);
1245 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1247 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1248 cell = g_list_last(list_cells)->data;
1250 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1251 path, column, FALSE, 0.0, 0.0 );
1252 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1253 path, column, cell, TRUE);
1255 gtk_tree_path_free(path);
1256 g_list_free(list_cells);
1261 static void filter_add_cb(GtkWidget *widget, gpointer data)
1263 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1264 filter_store_populate();
1266 g_idle_add((GSourceFunc)filter_add_scroll, data);
1269 static void filter_remove_cb(GtkWidget *widget, gpointer data)
1271 GtkWidget *filter_view = data;
1272 GtkTreeSelection *selection;
1276 if (!filter_store) return;
1277 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1278 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1279 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1282 filter_remove_entry(fe);
1284 filter_store_populate();
1287 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1291 GtkTreeViewColumn *column;
1293 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1294 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1295 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1297 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1301 gtk_tree_path_free(path);
1306 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
1309 filter_add_defaults();
1311 filter_store_populate();
1313 g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1316 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1318 /* no op, only so cancel button appears */
1321 static void filter_default_cb(GtkWidget *widget, gpointer data)
1325 gd = generic_dialog_new(_("Reset filters"),
1326 "reset_filter", widget, TRUE,
1327 dummy_cancel_cb, data);
1328 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1329 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1330 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1331 gtk_widget_show(gd->dialog);
1334 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1336 GtkWidget *frame = data;
1338 gtk_widget_set_sensitive(frame,
1339 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1342 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
1344 layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1347 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
1349 file_util_trash_clear();
1352 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
1356 gd = generic_dialog_new(_("Clear trash"),
1357 "clear_trash", widget, TRUE,
1358 dummy_cancel_cb, NULL);
1359 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1360 _("This will remove the trash contents."), FALSE);
1361 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1362 entry = gtk_entry_new();
1363 gtk_widget_set_can_focus(entry, FALSE);
1364 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1365 if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1366 gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1367 gtk_widget_show(entry);
1368 gtk_widget_show(gd->dialog);
1371 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
1373 GtkWidget *pTextView;
1374 GtkTextBuffer *pTextBuffer;
1378 pTextView = GTK_WIDGET(data);
1380 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1381 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1382 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1384 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1385 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1388 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
1390 GtkTextView *text_view = data;
1391 GtkTextBuffer *buffer;
1393 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1394 if (!configwindow) return;
1396 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1397 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1400 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1404 gd = generic_dialog_new(_("Reset image overlay template string"),
1405 "reset_image_overlay_template_string", widget, TRUE,
1406 dummy_cancel_cb, data);
1407 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1408 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1409 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1410 gtk_widget_show(gd->dialog);
1413 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
1415 help_window_show("GuideOptionsOSD.html");
1418 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer data)
1420 #if GTK_CHECK_VERSION(3,4,0)
1423 PangoFontDescription *font_desc;
1425 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1426 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1428 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1430 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1431 font = pango_font_description_to_string(font_desc);
1432 g_free(c_options->image_overlay.font);
1433 c_options->image_overlay.font = g_strdup(font);
1437 gtk_widget_destroy(dialog);
1441 font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
1442 c_options->image_overlay.font = g_strdup(font);
1446 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer data)
1449 #if GTK_CHECK_VERSION(3,4,0)
1452 dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1453 colour.red = options->image_overlay.text_red;
1454 colour.green = options->image_overlay.text_green;
1455 colour.blue = options->image_overlay.text_blue;
1456 colour.alpha = options->image_overlay.text_alpha;
1457 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1458 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1460 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1462 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1463 c_options->image_overlay.text_red = colour.red*255;
1464 c_options->image_overlay.text_green = colour.green*255;
1465 c_options->image_overlay.text_blue = colour.blue*255;
1466 c_options->image_overlay.text_alpha = colour.alpha*255;
1468 gtk_widget_destroy(dialog);
1471 GtkColorSelection *colorsel;
1473 dialog = gtk_color_selection_dialog_new("Image Overlay Text Colour");
1474 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1475 colour.red = options->image_overlay.text_red*257;
1476 colour.green = options->image_overlay.text_green*257;
1477 colour.blue = options->image_overlay.text_blue*257;
1478 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1479 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1480 gtk_color_selection_set_current_color(colorsel, &colour);
1481 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.text_alpha*257);
1483 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1485 gtk_color_selection_get_current_color(colorsel, &colour);
1486 c_options->image_overlay.text_red = colour.red/257;
1487 c_options->image_overlay.text_green = colour.green/257;
1488 c_options->image_overlay.text_blue = colour.blue/257;
1489 c_options->image_overlay.text_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1491 gtk_widget_destroy (dialog);
1496 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer data)
1499 #if GTK_CHECK_VERSION(3,4,0)
1502 dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1503 colour.red = options->image_overlay.background_red;
1504 colour.green = options->image_overlay.background_green;
1505 colour.blue = options->image_overlay.background_blue;
1506 colour.alpha = options->image_overlay.background_alpha;
1507 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1508 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1510 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1512 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1513 c_options->image_overlay.background_red = colour.red*255;
1514 c_options->image_overlay.background_green = colour.green*255;
1515 c_options->image_overlay.background_blue = colour.blue*255;
1516 c_options->image_overlay.background_alpha = colour.alpha*255;
1518 gtk_widget_destroy(dialog);
1521 GtkColorSelection *colorsel;
1523 dialog = gtk_color_selection_dialog_new("Image Overlay Background Colour");
1524 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1525 colour.red = options->image_overlay.background_red*257;
1526 colour.green = options->image_overlay.background_green*257;
1527 colour.blue = options->image_overlay.background_blue*257;
1528 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1529 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1530 gtk_color_selection_set_current_color(colorsel, &colour);
1531 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.background_alpha*257);
1533 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1535 gtk_color_selection_get_current_color(colorsel, &colour);
1536 c_options->image_overlay.background_red = colour.red/257;
1537 c_options->image_overlay.background_green = colour.green/257;
1538 c_options->image_overlay.background_blue = colour.blue/257;
1539 c_options->image_overlay.background_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1541 gtk_widget_destroy(dialog);
1545 static void accel_store_populate(void)
1548 GList *groups, *actions;
1550 const gchar *accel_path;
1554 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1556 gtk_tree_store_clear(accel_store);
1557 lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
1559 g_assert(lw && lw->ui_manager);
1560 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1563 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1566 action = GTK_ACTION(actions->data);
1567 accel_path = gtk_action_get_accel_path(action);
1568 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1570 gchar *label, *label2, *tooltip, *accel;
1571 g_object_get(action,
1572 "tooltip", &tooltip,
1576 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1582 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1586 gtk_tree_store_append(accel_store, &iter, NULL);
1587 gtk_tree_store_set(accel_store, &iter,
1590 AE_TOOLTIP, tooltip ? tooltip : "",
1591 AE_ACCEL, accel_path,
1599 actions = actions->next;
1602 groups = groups->next;
1606 static void accel_store_cleared_cb(GtkCellRendererAccel *accel, gchar *path_string, gpointer user_data)
1611 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1613 gchar *accel1 = data;
1618 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1620 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1621 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1623 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1625 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1626 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1635 static void accel_store_edited_cb(GtkCellRendererAccel *accel, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode, gpointer user_data)
1637 GtkTreeModel *model = (GtkTreeModel *)accel_store;
1641 GtkAccelKey old_key, key;
1642 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1644 gtk_tree_model_get_iter(model, &iter, path);
1645 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1647 /* test if the accelerator can be stored without conflicts*/
1648 gtk_accel_map_lookup_entry(accel_path, &old_key);
1650 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1651 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1652 gtk_accel_map_lookup_entry(accel_path, &key);
1654 /* restore the original for now, the key will be really changed when the changes are confirmed */
1655 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1657 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1658 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1660 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1661 gtk_tree_path_free(path);
1665 static gboolean accel_default_scroll(GtkTreeView *data)
1669 GtkTreeViewColumn *column;
1671 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1672 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1673 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1675 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1679 gtk_tree_path_free(path);
1684 static void accel_default_cb(GtkWidget *widget, gpointer data)
1686 accel_store_populate();
1688 g_idle_add((GSourceFunc)accel_default_scroll, data);
1691 void accel_remove_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1693 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1696 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1699 gchar *accel_path, *accel;
1701 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1702 gtk_accel_map_lookup_entry(accel_path, &key);
1703 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1705 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1707 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1712 static void accel_reset_cb(GtkWidget *widget, gpointer data)
1714 GtkTreeSelection *selection;
1716 if (!accel_store) return;
1717 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1718 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1723 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1727 GtkWidget *scrolled;
1728 GtkWidget *viewport;
1730 scrolled = gtk_scrolled_window_new(NULL, NULL);
1731 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1732 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1733 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1734 label = gtk_label_new(title);
1735 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1736 gtk_widget_show(scrolled);
1738 viewport = gtk_viewport_new(NULL, NULL);
1739 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1740 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1741 gtk_widget_show(viewport);
1743 vbox = gtk_vbox_new(FALSE, 0);
1744 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1745 gtk_widget_show(vbox);
1750 static void cache_standard_cb(GtkWidget *widget, gpointer data)
1752 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1754 c_options->thumbnails.spec_standard =TRUE;
1755 c_options->thumbnails.cache_into_dirs = FALSE;
1759 static void cache_geeqie_cb(GtkWidget *widget, gpointer data)
1761 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1763 c_options->thumbnails.spec_standard =FALSE;
1764 c_options->thumbnails.cache_into_dirs = FALSE;
1768 static void cache_local_cb(GtkWidget *widget, gpointer data)
1770 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1772 c_options->thumbnails.cache_into_dirs = TRUE;
1773 c_options->thumbnails.spec_standard =FALSE;
1777 static void help_search_engine_entry_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1778 GdkEvent *event, gpointer userdata)
1780 if (pos == GTK_ENTRY_ICON_PRIMARY)
1782 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1786 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1790 static void star_rating_star_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1791 GdkEvent *event, gpointer userdata)
1793 gchar *rating_symbol;
1795 if (pos == GTK_ENTRY_ICON_PRIMARY)
1797 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1798 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1799 g_free(rating_symbol);
1803 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1804 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1805 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1809 static void star_rating_rejected_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1810 GdkEvent *event, gpointer userdata)
1812 gchar *rating_symbol;
1814 if (pos == GTK_ENTRY_ICON_PRIMARY)
1816 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1817 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1818 g_free(rating_symbol);
1822 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1823 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1824 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1828 static guint star_rating_symbol_test(GtkWidget *widget, gpointer data)
1830 GtkContainer *hbox = data;
1831 GString *str = g_string_new(NULL);
1832 GtkEntry *hex_code_entry;
1833 gchar *hex_code_full;
1836 guint64 hex_value = 0;
1838 list = gtk_container_get_children(hbox);
1840 hex_code_entry = g_list_nth_data(list, 2);
1841 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1843 hex_code = g_strsplit(hex_code_full, "+", 2);
1844 if (hex_code[0] && hex_code[1])
1846 hex_value = strtoull(hex_code[1], NULL, 16);
1848 if (!hex_value || hex_value > 0x10FFFF)
1850 hex_value = 0x003F; // Unicode 'Question Mark'
1852 str = g_string_append_unichar(str, (gunichar)hex_value);
1853 gtk_label_set_text(g_list_nth_data(list, 1), str->str);
1855 g_strfreev(hex_code);
1856 g_string_free(str, TRUE);
1857 g_free(hex_code_full);
1862 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1864 guint64 star_symbol;
1866 star_symbol = star_rating_symbol_test(widget, data);
1867 c_options->star_rating.star = star_symbol;
1870 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1872 guint64 rejected_symbol;
1874 rejected_symbol = star_rating_symbol_test(widget, data);
1875 c_options->star_rating.rejected = rejected_symbol;
1878 /* general options tab */
1879 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1880 typedef struct _TZData TZData;
1884 GCancellable *cancellable;
1886 GtkWidget *progress;
1888 GFile *timezone_database_gq;
1889 gchar *timezone_database_user;
1892 static void config_tab_general(GtkWidget *notebook)
1897 GtkWidget *group_frame;
1898 GtkWidget *subgroup;
1900 GtkWidget *ct_button;
1903 gint hours, minutes, remainder;
1905 GtkWidget *star_rating_entry;
1907 gchar *rating_symbol;
1910 GNetworkMonitor *net_mon;
1911 GSocketConnectable *geeqie_org;
1912 gboolean internet_available;
1915 vbox = scrolled_notebook_page(notebook, _("General"));
1917 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1919 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1920 add_thumb_size_menu(table, 0, 0, _("Size:"));
1921 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1923 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1924 pref_label_new(hbox, _("Custom size: "));
1925 pref_spin_new_int(hbox, _("Width:"), NULL, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
1926 pref_spin_new_int(hbox, _("Height:"), NULL, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
1928 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
1929 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1931 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1932 pref_checkbox_link_sensitivity(ct_button, subgroup);
1934 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
1935 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
1936 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
1937 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1938 button = pref_radiobutton_new(group_frame, NULL, get_thumbnails_cache_dir(),
1939 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1940 G_CALLBACK(cache_geeqie_cb), NULL);
1942 group_frame = pref_frame_new(subgroup, TRUE,
1943 _("Store thumbnails local to image folder (non-standard)"),
1944 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1945 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
1946 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
1947 G_CALLBACK(cache_local_cb), NULL);
1949 group_frame = pref_frame_new(subgroup, TRUE,
1950 _("Use standard thumbnail style and cache, shared with other applications"),
1951 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1952 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
1953 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1954 G_CALLBACK(cache_standard_cb), NULL);
1956 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
1957 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
1959 pref_checkbox_new_int(group, _("Thumbnail color management"),
1960 options->thumbnails.use_color_management, &c_options->thumbnails.use_color_management);
1962 spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
1964 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
1965 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
1967 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
1968 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
1969 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
1971 // pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
1972 // options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
1975 pref_spacer(group, PREF_PAD_GROUP);
1977 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
1979 c_options->star_rating.star = options->star_rating.star;
1980 c_options->star_rating.rejected = options->star_rating.rejected;
1982 str = g_string_new(NULL);
1983 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1984 pref_label_new(hbox, _("Star character: "));
1985 str = g_string_append_unichar(str, options->star_rating.star);
1986 pref_label_new(hbox, g_strdup(str->str));
1987 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
1988 star_rating_entry = gtk_entry_new();
1989 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
1990 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
1991 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
1992 gtk_widget_show(star_rating_entry);
1993 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
1994 G_CALLBACK(star_rating_star_test_cb), hbox);
1995 gtk_widget_set_tooltip_text(button, _("Display selected character"));
1996 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1997 gtk_widget_show(button);
1998 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."));
1999 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2000 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2001 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2002 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2003 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2004 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2005 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2006 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2007 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2008 G_CALLBACK(star_rating_star_icon_cb),
2011 g_string_free(str, TRUE);
2012 g_free(rating_symbol);
2014 str = g_string_new(NULL);
2015 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2016 pref_label_new(hbox, _("Rejected character: "));
2017 str = g_string_append_unichar(str, options->star_rating.rejected);
2018 pref_label_new(hbox, g_strdup(str->str));
2019 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2020 star_rating_entry = gtk_entry_new();
2021 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2022 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2023 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2024 gtk_widget_show(star_rating_entry);
2025 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2026 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2027 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2028 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2029 gtk_widget_show(button);
2030 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."));
2031 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2032 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2033 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2034 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2035 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2036 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2037 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2038 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2039 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2040 G_CALLBACK(star_rating_rejected_icon_cb),
2043 g_string_free(str, TRUE);
2044 g_free(rating_symbol);
2046 pref_spacer(group, PREF_PAD_GROUP);
2048 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2050 c_options->slideshow.delay = options->slideshow.delay;
2051 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2052 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2053 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2054 seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2055 SLIDESHOW_SUBSECOND_PRECISION;
2057 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2059 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2061 options->slideshow.delay ? hours : 0.0,
2062 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2063 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2064 spin = pref_spin_new(hbox, ":" , NULL,
2066 options->slideshow.delay ? minutes: 0.0,
2067 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2068 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2069 spin = pref_spin_new(hbox, ":", NULL,
2070 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2071 options->slideshow.delay ? seconds : 10.0,
2072 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2073 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2075 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2076 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2078 pref_spacer(group, PREF_PAD_GROUP);
2080 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2082 pref_spin_new_int(group, _("Decoded image cache size (MiB):"), NULL,
2083 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2084 pref_checkbox_new_int(group, _("Preload next image"),
2085 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2087 pref_checkbox_new_int(group, _("Refresh on file change"),
2088 options->update_on_time_change, &c_options->update_on_time_change);
2091 pref_spacer(group, PREF_PAD_GROUP);
2093 group = pref_group_new(vbox, FALSE, _("Expand menu and toolbar"), GTK_ORIENTATION_VERTICAL);
2095 pref_checkbox_new_int(group, _("Expand menu and toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2096 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2097 gtk_widget_set_tooltip_text(group, _("Expand the menu and toolbar to the full width of the window"));
2099 pref_spacer(group, PREF_PAD_GROUP);
2101 group = pref_group_new(vbox, FALSE, _("Info sidebar heights"), GTK_ORIENTATION_VERTICAL);
2102 pref_label_new(group, _("NOTE! Geeqie must be restarted for changes to take effect"));
2103 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2104 pref_spin_new_int(hbox, _("Keywords:"), NULL,
2106 options->info_keywords.height, &c_options->info_keywords.height);
2107 pref_spin_new_int(hbox, _("Title:"), NULL,
2109 options->info_title.height, &c_options->info_title.height);
2110 pref_spin_new_int(hbox, _("Comment:"), NULL,
2112 options->info_comment.height, &c_options->info_comment.height);
2113 pref_spin_new_int(hbox, _("Rating:"), NULL,
2115 options->info_rating.height, &c_options->info_rating.height);
2117 pref_spacer(group, PREF_PAD_GROUP);
2119 group = pref_group_new(vbox, FALSE, _("Show predefined keyword tree"), GTK_ORIENTATION_VERTICAL);
2121 pref_checkbox_new_int(group, _("Show predefined keyword tree (NOTE! Geeqie must be restarted for change to take effect)"),
2122 options->show_predefined_keyword_tree, &c_options->show_predefined_keyword_tree);
2124 pref_spacer(group, PREF_PAD_GROUP);
2126 net_mon = g_network_monitor_get_default();
2127 geeqie_org = g_network_address_parse_uri(GQ_WEBSITE, 80, NULL);
2128 internet_available = g_network_monitor_can_reach(net_mon, geeqie_org, NULL, NULL);
2129 g_object_unref(geeqie_org);
2131 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2132 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2134 if (!internet_available)
2136 gtk_widget_set_sensitive(group, FALSE);
2139 tz = g_new0(TZData, 1);
2141 path = path_from_utf8(TIMEZONE_DATABASE);
2142 basename = g_path_get_basename(path);
2143 tz->timezone_database_user = g_build_filename(get_rc_dir(), basename, NULL);
2147 if (isfile(tz->timezone_database_user))
2149 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2153 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2156 if (!internet_available)
2158 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"));
2162 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"));
2164 gtk_widget_show(button);
2166 pref_spacer(group, PREF_PAD_GROUP);
2168 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2170 help_search_engine_entry = gtk_entry_new();
2171 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2172 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2173 gtk_widget_show(help_search_engine_entry);
2175 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"));
2177 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2178 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2179 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2180 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2181 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2182 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2183 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2184 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2185 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2186 G_CALLBACK(help_search_engine_entry_icon_cb),
2187 help_search_engine_entry);
2191 static void config_tab_image(GtkWidget *notebook)
2196 GtkWidget *ct_button;
2197 GtkWidget *enlargement_button;
2200 GtkWidget *two_pass;
2202 GtkWidget *gpu_accel;
2205 vbox = scrolled_notebook_page(notebook, _("Image"));
2207 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2209 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2210 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2211 if (options->image.use_clutter_renderer && !options->disable_gpu)
2213 gtk_widget_set_sensitive(table, FALSE);
2217 gpu_accel = pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library (Requires restart)"),
2218 options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2219 if (options->disable_gpu && !options->override_disable_gpu)
2221 gtk_widget_set_sensitive(gpu_accel, FALSE);
2225 two_pass = pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2226 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2227 if (options->image.use_clutter_renderer && !options->disable_gpu)
2229 gtk_widget_set_sensitive(two_pass, FALSE);
2232 c_options->image.zoom_increment = options->image.zoom_increment;
2233 spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2234 0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2235 G_CALLBACK(zoom_increment_cb), NULL);
2236 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2238 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2240 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2241 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2242 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2243 spin = pref_spin_new_int(hbox, NULL, NULL,
2245 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2246 pref_checkbox_link_sensitivity(enlargement_button, spin);
2247 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."));
2249 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2250 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2251 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2252 spin = pref_spin_new_int(hbox, NULL, NULL,
2254 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2255 pref_checkbox_link_sensitivity(ct_button, spin);
2256 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."));
2258 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2260 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2261 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2263 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2264 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2266 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2267 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2269 c_options->image.border_color = options->image.border_color;
2271 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2272 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2274 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2275 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2277 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2278 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2280 group = pref_group_new(vbox, FALSE, _("Convenience"), GTK_ORIENTATION_VERTICAL);
2282 pref_checkbox_new_int(group, _("Auto rotate proofs using Exif information"),
2283 options->image.exif_proof_rotate_enable, &c_options->image.exif_proof_rotate_enable);
2287 static void config_tab_windows(GtkWidget *notebook)
2293 GtkWidget *ct_button;
2296 vbox = scrolled_notebook_page(notebook, _("Windows"));
2298 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2300 ct_button = pref_checkbox_new_int(group, _("Remember window positions"),
2301 options->save_window_positions, &c_options->save_window_positions);
2303 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2304 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2305 pref_checkbox_link_sensitivity(ct_button, button);
2307 button = pref_checkbox_new_int(group, _("Remember window workspace"),
2308 options->save_window_workspace, &c_options->save_window_workspace);
2309 pref_checkbox_link_sensitivity(ct_button, button);
2311 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2312 options->tools_restore_state, &c_options->tools_restore_state);
2314 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2315 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2317 pref_checkbox_new_int(group, _("Show window IDs"),
2318 options->show_window_ids, &c_options->show_window_ids);
2320 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2322 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2323 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2325 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2326 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2327 options->image.limit_window_size, &c_options->image.limit_window_size);
2328 spin = pref_spin_new_int(hbox, NULL, NULL,
2330 options->image.max_window_size, &c_options->image.max_window_size);
2331 pref_checkbox_link_sensitivity(ct_button, spin);
2333 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2335 c_options->fullscreen.screen = options->fullscreen.screen;
2336 c_options->fullscreen.above = options->fullscreen.above;
2337 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2338 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2339 gtk_widget_show(hbox);
2341 pref_checkbox_new_int(group, _("Smooth image flip"),
2342 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2343 pref_checkbox_new_int(group, _("Disable screen saver"),
2344 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2347 #define PRE_FORMATTED_COLUMNS 5
2348 static void config_tab_osd(GtkWidget *notebook)
2354 GtkWidget *image_overlay_template_view;
2355 GtkWidget *scrolled;
2356 GtkWidget *scrolled_pre_formatted;
2357 GtkTextBuffer *buffer;
2359 GtkWidget *subgroup;
2361 vbox = scrolled_notebook_page(notebook, _("OSD"));
2363 image_overlay_template_view = gtk_text_view_new();
2365 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2367 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2369 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2370 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2371 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2372 gtk_widget_show(scrolled_pre_formatted);
2373 gtk_widget_show(subgroup);
2375 pref_line(group, PREF_PAD_GAP);
2377 pref_label_new(group, _("Image overlay template"));
2379 scrolled = gtk_scrolled_window_new(NULL, NULL);
2380 gtk_widget_set_size_request(scrolled, 200, 150);
2381 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2382 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2383 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2384 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2385 gtk_widget_show(scrolled);
2387 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2388 _("Extensive formatting options are shown in the Help file"));
2390 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2391 gtk_widget_show(image_overlay_template_view);
2393 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2395 #if GTK_CHECK_VERSION(3,4,0)
2396 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2397 G_CALLBACK(image_overlay_set_font_cb), notebook);
2399 button = gtk_font_button_new();
2400 gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
2401 gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
2402 g_signal_connect(G_OBJECT(button), "font-set",
2403 G_CALLBACK(image_overlay_set_font_cb),NULL);
2405 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2406 gtk_widget_show(button);
2408 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2409 G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2410 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2411 gtk_widget_show(button);
2413 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2414 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2415 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2416 gtk_widget_show(button);
2417 image_overlay_set_text_colours();
2419 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2420 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2421 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2422 gtk_widget_show(button);
2424 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2425 G_CALLBACK(image_overlay_help_cb), NULL);
2426 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2427 gtk_widget_show(button);
2429 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2430 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2431 g_signal_connect(G_OBJECT(buffer), "changed",
2432 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2434 pref_line(group, PREF_PAD_GAP);
2436 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2437 hbox = gtk_hbox_new(FALSE, 0);
2438 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2439 gtk_widget_show(hbox);
2440 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2441 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2442 gtk_widget_show(label);
2443 pref_spacer(group,TRUE);
2445 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2446 hbox = gtk_hbox_new(FALSE, 0);
2447 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2448 gtk_widget_show(hbox);
2449 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2450 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2451 gtk_widget_show(label);
2452 pref_spacer(group,TRUE);
2454 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2455 hbox = gtk_hbox_new(FALSE, 0);
2456 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2457 gtk_widget_show(hbox);
2458 label = gtk_label_new(_("%path:39%"));
2459 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2460 gtk_widget_show(label);
2461 pref_spacer(group,TRUE);
2463 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2464 hbox = gtk_hbox_new(FALSE, 0);
2465 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2466 gtk_widget_show(hbox);
2467 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%"));
2468 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2469 gtk_widget_show(label);
2470 pref_spacer(group,TRUE);
2472 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2473 hbox = gtk_hbox_new(FALSE, 0);
2474 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2475 gtk_widget_show(hbox);
2476 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2477 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2478 gtk_widget_show(label);
2481 static GtkTreeModel *create_class_model(void)
2483 GtkListStore *model;
2487 /* create list store */
2488 model = gtk_list_store_new(1, G_TYPE_STRING);
2489 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2491 gtk_list_store_append(model, &iter);
2492 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2494 return GTK_TREE_MODEL (model);
2499 static void config_tab_files(GtkWidget *notebook)
2506 GtkWidget *ct_button;
2507 GtkWidget *scrolled;
2508 GtkWidget *filter_view;
2509 GtkCellRenderer *renderer;
2510 GtkTreeSelection *selection;
2511 GtkTreeViewColumn *column;
2513 vbox = scrolled_notebook_page(notebook, _("Files"));
2515 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2517 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2518 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2519 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2520 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2521 pref_checkbox_new_int(group, _("Case sensitive sort"),
2522 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2523 pref_checkbox_new_int(group, _("Natural sort order"),
2524 options->file_sort.natural, &c_options->file_sort.natural);
2525 pref_checkbox_new_int(group, _("Disable file extension checks"),
2526 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2528 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2529 options->file_filter.disable, &c_options->file_filter.disable);
2532 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2534 sidecar_ext_entry = gtk_entry_new();
2535 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2536 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2537 gtk_widget_show(sidecar_ext_entry);
2539 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2541 frame = pref_group_parent(group);
2542 g_signal_connect(G_OBJECT(ct_button), "toggled",
2543 G_CALLBACK(filter_disable_cb), frame);
2544 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2546 scrolled = gtk_scrolled_window_new(NULL, NULL);
2547 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2548 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2549 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2550 gtk_widget_show(scrolled);
2552 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2553 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2554 g_object_unref(filter_store);
2555 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2556 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2558 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2560 column = gtk_tree_view_column_new();
2561 gtk_tree_view_column_set_title(column, _("Filter"));
2562 gtk_tree_view_column_set_resizable(column, TRUE);
2564 renderer = gtk_cell_renderer_toggle_new();
2565 g_signal_connect(G_OBJECT(renderer), "toggled",
2566 G_CALLBACK(filter_store_enable_cb), filter_store);
2567 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2568 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2569 GINT_TO_POINTER(FE_ENABLE), NULL);
2571 renderer = gtk_cell_renderer_text_new();
2572 g_signal_connect(G_OBJECT(renderer), "edited",
2573 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2574 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2575 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2576 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2577 GINT_TO_POINTER(FE_EXTENSION), NULL);
2578 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2580 column = gtk_tree_view_column_new();
2581 gtk_tree_view_column_set_title(column, _("Description"));
2582 gtk_tree_view_column_set_resizable(column, TRUE);
2583 gtk_tree_view_column_set_fixed_width(column, 200);
2584 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2586 renderer = gtk_cell_renderer_text_new();
2587 g_signal_connect(G_OBJECT(renderer), "edited",
2588 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2589 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2590 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2591 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2592 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2593 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2595 column = gtk_tree_view_column_new();
2596 gtk_tree_view_column_set_title(column, _("Class"));
2597 gtk_tree_view_column_set_resizable(column, TRUE);
2598 renderer = gtk_cell_renderer_combo_new();
2599 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2600 "model", create_class_model(),
2605 g_signal_connect(G_OBJECT(renderer), "edited",
2606 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2607 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2608 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2609 GINT_TO_POINTER(FE_CLASS), NULL);
2610 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2612 column = gtk_tree_view_column_new();
2613 gtk_tree_view_column_set_title(column, _("Writable"));
2614 gtk_tree_view_column_set_resizable(column, FALSE);
2615 renderer = gtk_cell_renderer_toggle_new();
2616 g_signal_connect(G_OBJECT(renderer), "toggled",
2617 G_CALLBACK(filter_store_writable_cb), filter_store);
2618 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2619 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2620 GINT_TO_POINTER(FE_WRITABLE), NULL);
2621 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2623 column = gtk_tree_view_column_new();
2624 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2625 gtk_tree_view_column_set_resizable(column, FALSE);
2626 renderer = gtk_cell_renderer_toggle_new();
2627 g_signal_connect(G_OBJECT(renderer), "toggled",
2628 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2629 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2630 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2631 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2632 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2635 filter_store_populate();
2636 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2637 gtk_widget_show(filter_view);
2639 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2641 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2642 G_CALLBACK(filter_default_cb), filter_view);
2643 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2644 gtk_widget_show(button);
2646 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2647 G_CALLBACK(filter_remove_cb), filter_view);
2648 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2649 gtk_widget_show(button);
2651 button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2652 G_CALLBACK(filter_add_cb), filter_view);
2653 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2654 gtk_widget_show(button);
2658 static void config_tab_metadata(GtkWidget *notebook)
2663 GtkWidget *ct_button;
2667 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2670 group = pref_group_new(vbox, FALSE, _("Metadata writing process"), GTK_ORIENTATION_VERTICAL);
2672 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2674 label = pref_label_new(group, _("Metadata are written in the following order. The process ends after first success."));
2675 #if GTK_CHECK_VERSION(3,16,0)
2676 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2677 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2679 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2682 ct_button = pref_checkbox_new_int(group, _("1) Save metadata in image files, or sidecar files, according to the XMP standard"),
2683 options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2685 gtk_widget_set_sensitive(ct_button, FALSE);
2688 pref_checkbox_new_int(group, _("2) Save metadata in '.metadata' folder, local to image folder (non-standard)"),
2689 options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2691 text = g_strdup_printf(_("3) Save metadata in Geeqie private directory '%s'"), get_metadata_cache_dir());
2692 label = pref_label_new(group, text);
2693 #if GTK_CHECK_VERSION(3,16,0)
2694 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2695 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2697 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2699 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2702 group = pref_group_new(vbox, FALSE, _("Step 1: Write to image files"), GTK_ORIENTATION_VERTICAL);
2704 gtk_widget_set_sensitive(group, FALSE);
2707 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2708 pref_checkbox_link_sensitivity(ct_button, hbox);
2710 pref_checkbox_new_int(hbox, _("Store metadata also in legacy IPTC tags (converted according to IPTC4XMP standard)"),
2711 options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2713 pref_checkbox_new_int(hbox, _("Warn if the image files are unwritable"),
2714 options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2716 pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
2717 options->metadata.confirm_write, &c_options->metadata.confirm_write);
2719 pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
2720 options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2722 group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
2724 gtk_widget_set_sensitive(group, FALSE);
2727 pref_checkbox_new_int(group, _("Use GQview legacy metadata format (supports only keywords and comments) instead of XMP"),
2728 options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2731 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2732 pref_checkbox_new_int(group, _("Write the same description tags (keywords, comment, etc.) to all grouped sidecars"),
2733 options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2735 pref_checkbox_new_int(group, _("Allow keywords to differ only in case"),
2736 options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2738 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"),
2739 options->metadata.write_orientation, &c_options->metadata.write_orientation);
2741 gtk_widget_set_sensitive(ct_button, FALSE);
2744 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2746 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"),
2747 options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2749 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2750 pref_checkbox_link_sensitivity(ct_button, hbox);
2752 pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1,
2753 options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2755 pref_checkbox_new_int(group, _("Write metadata on image change"),
2756 options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2758 pref_checkbox_new_int(group, _("Write metadata on directory change"),
2759 options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2761 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2763 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"),
2764 options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2765 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");
2770 typedef struct _KeywordFindData KeywordFindData;
2771 struct _KeywordFindData
2778 GtkWidget *button_close;
2779 GtkWidget *button_stop;
2780 GtkWidget *button_start;
2781 GtkWidget *progress;
2789 guint idle_id; /* event source id */
2792 #define KEYWORD_DIALOG_WIDTH 400
2794 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
2796 GList *list_d = NULL;
2797 GList *list_f = NULL;
2801 filelist_read(dir_fd, &list_f, &list_d);
2805 filelist_read(dir_fd, &list_f, NULL);
2808 list_f = filelist_filter(list_f, FALSE);
2809 list_d = filelist_filter(list_d, TRUE);
2811 kfd->list = g_list_concat(list_f, kfd->list);
2812 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
2815 static void keywords_find_reset(KeywordFindData *kfd)
2817 filelist_free(kfd->list);
2820 filelist_free(kfd->list_dir);
2821 kfd->list_dir = NULL;
2824 static void keywords_find_close_cb(GenericDialog *fd, gpointer data)
2826 KeywordFindData *kfd = data;
2828 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
2830 keywords_find_reset(kfd);
2831 generic_dialog_close(kfd->gd);
2835 static void keywords_find_finish(KeywordFindData *kfd)
2837 keywords_find_reset(kfd);
2839 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
2840 spinner_set_interval(kfd->spinner, -1);
2842 gtk_widget_set_sensitive(kfd->group, TRUE);
2843 gtk_widget_set_sensitive(kfd->button_start, TRUE);
2844 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2845 gtk_widget_set_sensitive(kfd->button_close, TRUE);
2848 static void keywords_find_stop_cb(GenericDialog *fd, gpointer data)
2850 KeywordFindData *kfd = data;
2852 g_idle_remove_by_data(kfd);
2854 keywords_find_finish(kfd);
2857 static gboolean keywords_find_file(gpointer data)
2859 KeywordFindData *kfd = data;
2861 GtkTextBuffer *buffer;
2869 fd = kfd->list->data;
2870 kfd->list = g_list_remove(kfd->list, fd);
2872 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
2873 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2877 gtk_text_buffer_get_end_iter(buffer, &iter);
2878 tmp = g_strconcat(keywords->data, "\n", NULL);
2879 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
2881 keywords = keywords->next;
2884 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
2885 file_data_unref(fd);
2886 string_list_free(keywords);
2890 else if (kfd->list_dir)
2894 fd = kfd->list_dir->data;
2895 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
2897 keywords_find_folder(kfd, fd);
2899 file_data_unref(fd);
2904 keywords_find_finish(kfd);
2909 static void keywords_find_start_cb(GenericDialog *fd, gpointer data)
2911 KeywordFindData *kfd = data;
2914 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
2916 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
2917 parse_out_relatives(path);
2921 warning_dialog(_("Invalid folder"),
2922 _("The specified folder can not be found."),
2923 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
2929 gtk_widget_set_sensitive(kfd->group, FALSE);
2930 gtk_widget_set_sensitive(kfd->button_start, FALSE);
2931 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
2932 gtk_widget_set_sensitive(kfd->button_close, FALSE);
2933 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
2935 dir_fd = file_data_new_dir(path);
2936 keywords_find_folder(kfd, dir_fd);
2937 file_data_unref(dir_fd);
2938 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
2944 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
2946 KeywordFindData *kfd;
2950 kfd = g_new0(KeywordFindData, 1);
2952 kfd->gd = generic_dialog_new(_("Search for keywords"),
2953 "search_for_keywords",
2956 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
2957 kfd->gd->cancel_cb = keywords_find_close_cb;
2958 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
2959 keywords_find_close_cb, FALSE);
2960 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
2961 keywords_find_start_cb, FALSE);
2962 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
2963 keywords_find_stop_cb, FALSE);
2964 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2966 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
2968 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
2969 pref_spacer(hbox, PREF_PAD_INDENT);
2970 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2972 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2973 pref_label_new(hbox, _("Folder:"));
2975 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
2976 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
2977 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
2978 gtk_widget_show(label);
2980 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
2982 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
2983 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2985 kfd->progress = gtk_entry_new();
2986 gtk_widget_set_can_focus(kfd->progress, FALSE);
2987 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
2988 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
2989 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
2990 gtk_widget_show(kfd->progress);
2992 kfd->spinner = spinner_new(NULL, -1);
2993 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
2994 gtk_widget_show(kfd->spinner);
2998 gtk_widget_show(kfd->gd->dialog);
3001 static void keywords_find_cb(GtkWidget *widget, gpointer data)
3003 const gchar *path = layout_get_path(NULL);
3005 if (!path || !*path) path = homedir();
3006 keywords_find_dialog(widget, path);
3009 static void config_tab_keywords_save()
3011 GtkTextIter start, end;
3012 GtkTextBuffer *buffer;
3013 GList *kw_list = NULL;
3019 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3020 gtk_text_buffer_get_bounds(buffer, &start, &end);
3022 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3024 kw_split = strtok(buffer_text, "\n");
3025 while (kw_split != NULL)
3031 if (g_strcmp0(work->data, kw_split) == 0)
3040 kw_list = g_list_append(kw_list, g_strdup(kw_split));
3042 kw_split = strtok(NULL, "\n");
3045 keyword_list_set(kw_list);
3047 string_list_free(kw_list);
3048 g_free(buffer_text);
3051 static void config_tab_keywords(GtkWidget *notebook)
3057 GtkWidget *scrolled;
3059 GtkTextBuffer *buffer;
3062 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3064 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3066 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3068 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
3069 G_CALLBACK(keywords_find_cb), keyword_text);
3070 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
3073 keyword_text = gtk_text_view_new();
3074 gtk_widget_set_size_request(keyword_text, 20, 20);
3075 scrolled = gtk_scrolled_window_new(NULL, NULL);
3076 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3077 gtk_widget_show(scrolled);
3079 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
3080 gtk_widget_show(keyword_text);
3082 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3084 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3085 gtk_text_buffer_create_tag(buffer, "monospace",
3086 "family", "monospace", NULL);
3088 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3089 gtk_text_buffer_get_start_iter(buffer, &iter);
3090 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3093 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3095 GList *kwl = keyword_list_get();
3096 kwl = g_list_first(kwl);
3099 gtk_text_buffer_get_end_iter (buffer, &iter);
3100 tmp = g_strconcat(kwl->data, "\n", NULL);
3101 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3106 gtk_text_buffer_set_modified(buffer, FALSE);
3113 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3115 gint *option = data;
3117 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3121 *option = INTENT_PERCEPTUAL;
3124 *option = INTENT_RELATIVE_COLORIMETRIC;
3127 *option = INTENT_SATURATION;
3130 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3135 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3136 gint option, gint *option_c)
3143 pref_table_label(table, column, row, text, 0.0);
3145 combo = gtk_combo_box_text_new();
3147 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3148 if (option == INTENT_PERCEPTUAL) current = 0;
3149 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3150 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3151 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3152 if (option == INTENT_SATURATION) current = 2;
3153 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3154 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3156 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3158 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3160 g_signal_connect(G_OBJECT(combo), "changed",
3161 G_CALLBACK(intent_menu_cb), option_c);
3163 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
3164 gtk_widget_show(combo);
3168 static void config_tab_color(GtkWidget *notebook)
3177 vbox = scrolled_notebook_page(notebook, _("Color management"));
3179 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3181 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3184 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3185 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3187 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3188 pref_label_bold(label, TRUE, FALSE);
3190 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3191 pref_label_bold(label, TRUE, FALSE);
3193 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3194 pref_label_bold(label, TRUE, FALSE);
3196 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3201 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3202 pref_table_label(table, 0, i + 1, buf, 1.0);
3205 entry = gtk_entry_new();
3206 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3207 if (options->color_profile.input_name[i])
3209 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3211 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3212 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3213 gtk_widget_show(entry);
3214 color_profile_input_name_entry[i] = entry;
3216 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3217 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3218 gtk_widget_set_size_request(entry, 160, -1);
3219 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3220 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3221 gtk_widget_show(tabcomp);
3222 color_profile_input_file_entry[i] = entry;
3225 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3227 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3229 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3230 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3232 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3234 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3235 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3236 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3237 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3238 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3240 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3242 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3244 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3246 gtk_widget_show(tabcomp);
3249 /* advanced entry tab */
3250 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer data)
3252 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3254 c_options->file_ops.use_system_trash = FALSE;
3255 c_options->file_ops.no_trash = FALSE;
3259 static void use_system_trash_cb(GtkWidget *widget, gpointer data)
3261 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3263 c_options->file_ops.use_system_trash = TRUE;
3264 c_options->file_ops.no_trash = FALSE;
3268 static void use_no_cache_cb(GtkWidget *widget, gpointer data)
3270 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3272 c_options->file_ops.no_trash = TRUE;
3276 static void config_tab_behavior(GtkWidget *notebook)
3283 GtkWidget *ct_button;
3287 GtkWidget *with_rename;
3288 GtkWidget *collections_on_top;
3289 GtkWidget *hide_window_in_fullscreen;
3290 GtkWidget *checkbox;
3293 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3295 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3297 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3298 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3299 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3300 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3301 pref_checkbox_new_int(group, _("Enable Delete key"),
3302 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3304 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3305 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3307 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3308 pref_checkbox_link_sensitivity(ct_button, hbox);
3310 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3311 pref_label_new(hbox, _("Folder:"));
3313 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3314 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3315 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3316 gtk_widget_show(tabcomp);
3318 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3319 pref_checkbox_link_sensitivity(ct_button, hbox);
3321 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3322 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MiB"),
3323 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3324 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3325 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3326 G_CALLBACK(safe_delete_view_cb), NULL);
3327 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3328 gtk_widget_show(button);
3330 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3331 G_CALLBACK(safe_delete_clear_cb), NULL);
3332 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3333 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3334 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3336 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3337 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3339 gtk_widget_show(button);
3341 pref_spacer(group, PREF_PAD_GROUP);
3344 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3346 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3347 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3349 pref_checkbox_new_int(group, _("In place renaming"),
3350 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3352 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3353 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3355 tmp = pref_checkbox_new_int(group, _("Circular selection lists"),
3356 options->circular_selection_lists, &c_options->circular_selection_lists);
3357 gtk_widget_set_tooltip_text(tmp, _("Traverse selection lists in a circular manner"));
3359 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3360 options->marks_save, &c_options->marks_save);
3361 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3363 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3364 options->with_rename, &c_options->with_rename);
3365 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3367 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3368 options->collections_on_top, &c_options->collections_on_top);
3369 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3371 hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3372 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3373 gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice");
3375 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3376 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3378 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3379 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3381 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3382 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3384 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3385 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3387 pref_spacer(group, PREF_PAD_GROUP);
3389 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3391 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3392 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3393 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3394 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3395 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3396 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3397 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3398 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3399 pref_checkbox_new_int(group, _("Play video by left click on image"),
3400 options->image_l_click_video, &c_options->image_l_click_video);
3401 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3402 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3404 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3405 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3406 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3407 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3408 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3410 pref_spacer(group, PREF_PAD_GROUP);
3412 group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3414 checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3415 options->override_disable_gpu, &c_options->override_disable_gpu);
3416 gtk_widget_set_tooltip_text(checkbox, "Contact the developers for usage");
3419 pref_spacer(group, PREF_PAD_GROUP);
3421 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3423 pref_spin_new_int(group, _("Debug level:"), NULL,
3424 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3426 pref_checkbox_new_int(group, _("Timer data"),
3427 options->log_window.timer_data, &c_options->log_window.timer_data);
3429 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3430 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3434 /* accelerators tab */
3435 static void config_tab_accelerators(GtkWidget *notebook)
3441 GtkWidget *scrolled;
3442 GtkWidget *accel_view;
3443 GtkCellRenderer *renderer;
3444 GtkTreeSelection *selection;
3445 GtkTreeViewColumn *column;
3447 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3449 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3451 scrolled = gtk_scrolled_window_new(NULL, NULL);
3452 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3453 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3454 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3455 gtk_widget_show(scrolled);
3457 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3459 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3460 g_object_unref(accel_store);
3461 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3462 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3464 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3466 renderer = gtk_cell_renderer_text_new();
3468 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3473 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3474 gtk_tree_view_column_set_resizable(column, TRUE);
3475 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3478 renderer = gtk_cell_renderer_accel_new();
3479 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3480 G_CALLBACK(accel_store_cleared_cb), accel_store);
3481 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3482 G_CALLBACK(accel_store_edited_cb), accel_store);
3485 g_object_set (renderer,
3487 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3490 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3495 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3496 gtk_tree_view_column_set_resizable(column, TRUE);
3497 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3499 renderer = gtk_cell_renderer_text_new();
3501 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3506 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3507 gtk_tree_view_column_set_resizable(column, TRUE);
3508 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3510 renderer = gtk_cell_renderer_text_new();
3512 column = gtk_tree_view_column_new_with_attributes("Accel",
3517 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3518 gtk_tree_view_column_set_resizable(column, TRUE);
3519 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3521 accel_store_populate();
3522 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3523 gtk_widget_show(accel_view);
3525 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3527 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3528 G_CALLBACK(accel_default_cb), accel_view);
3529 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3530 gtk_widget_show(button);
3532 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3533 G_CALLBACK(accel_reset_cb), accel_view);
3534 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3535 gtk_widget_show(button);
3538 /* toolbar main tab */
3539 static void config_tab_toolbar_main(GtkWidget *notebook)
3542 GtkWidget *toolbardata;
3545 lw = layout_window_list->data;
3547 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3549 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3550 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3551 gtk_widget_show(vbox);
3554 /* toolbar status tab */
3555 static void config_tab_toolbar_status(GtkWidget *notebook)
3558 GtkWidget *toolbardata;
3561 lw = layout_window_list->data;
3563 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3565 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3566 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3567 gtk_widget_show(vbox);
3571 static void config_tab_stereo(GtkWidget *notebook)
3579 GtkWidget *fs_button;
3580 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3582 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3584 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3585 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3587 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3588 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3589 pref_checkbox_new_int(box, _("Mirror left image"),
3590 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3591 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3592 pref_checkbox_new_int(box, _("Flip left image"),
3593 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3594 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3595 pref_checkbox_new_int(box, _("Mirror right image"),
3596 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3597 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3598 pref_checkbox_new_int(box, _("Flip right image"),
3599 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3600 pref_checkbox_new_int(group, _("Swap left and right images"),
3601 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3602 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3603 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3605 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3606 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3607 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3608 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3609 pref_checkbox_link_sensitivity(fs_button, box2);
3610 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3611 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3612 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3613 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3614 pref_checkbox_new_int(box, _("Mirror left image"),
3615 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3616 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3617 pref_checkbox_new_int(box, _("Flip left image"),
3618 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3619 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3620 pref_checkbox_new_int(box, _("Mirror right image"),
3621 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3622 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3623 pref_checkbox_new_int(box, _("Flip right image"),
3624 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3625 pref_checkbox_new_int(box2, _("Swap left and right images"),
3626 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3627 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3628 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3630 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3631 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3632 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3633 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3634 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
3635 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3636 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
3637 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3638 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
3639 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3640 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
3641 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3642 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
3643 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3647 /* Main preferences window */
3648 static void config_window_create(void)
3650 GtkWidget *win_vbox;
3652 GtkWidget *notebook;
3654 GtkWidget *ct_button;
3656 if (!c_options) c_options = init_options(NULL);
3658 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3659 DEBUG_NAME(configwindow);
3660 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3661 g_signal_connect(G_OBJECT(configwindow), "delete_event",
3662 G_CALLBACK(config_window_delete), NULL);
3663 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
3664 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
3665 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
3667 win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
3668 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
3669 gtk_widget_show(win_vbox);
3671 notebook = gtk_notebook_new();
3672 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
3673 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
3674 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
3676 config_tab_general(notebook);
3677 config_tab_image(notebook);
3678 config_tab_osd(notebook);
3679 config_tab_windows(notebook);
3680 config_tab_accelerators(notebook);
3681 config_tab_files(notebook);
3682 config_tab_metadata(notebook);
3683 config_tab_keywords(notebook);
3684 config_tab_color(notebook);
3685 config_tab_stereo(notebook);
3686 config_tab_behavior(notebook);
3687 config_tab_toolbar_main(notebook);
3688 config_tab_toolbar_status(notebook);
3690 hbox = gtk_hbutton_box_new();
3691 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
3692 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
3693 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
3694 gtk_widget_show(hbox);
3696 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
3697 G_CALLBACK(config_window_help_cb), notebook);
3698 gtk_container_add(GTK_CONTAINER(hbox), button);
3699 gtk_widget_set_can_default(button, TRUE);
3700 gtk_widget_show(button);
3702 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
3703 G_CALLBACK(config_window_ok_cb), NULL);
3704 gtk_container_add(GTK_CONTAINER(hbox), button);
3705 gtk_widget_set_can_default(button, TRUE);
3706 gtk_widget_grab_default(button);
3707 gtk_widget_show(button);
3711 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
3712 G_CALLBACK(config_window_close_cb), NULL);
3713 gtk_container_add(GTK_CONTAINER(hbox), button);
3714 gtk_widget_set_can_default(button, TRUE);
3715 gtk_widget_show(button);
3717 if (!generic_dialog_get_alternative_button_order(configwindow))
3719 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
3722 gtk_widget_show(notebook);
3724 gtk_widget_show(configwindow);
3728 *-----------------------------------------------------------------------------
3729 * config window show (public)
3730 *-----------------------------------------------------------------------------
3733 void show_config_window(void)
3737 gtk_window_present(GTK_WINDOW(configwindow));
3741 config_window_create();
3750 void show_about_window(LayoutWindow *lw)
3752 GdkPixbuf *pixbuf_logo;
3753 GdkPixbuf *pixbuf_icon;
3754 gchar *authors[1000];
3759 gchar *timezone_path;
3763 #define LINE_LENGTH 1000
3764 gchar line[LINE_LENGTH];
3766 copyright = g_string_new(NULL);
3767 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");
3769 path = path_from_utf8(TIMEZONE_DATABASE);
3770 basename = g_path_get_basename(path);
3771 timezone_path = g_build_filename(get_rc_dir(), basename, NULL);
3772 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
3774 cd = ZDOpenDatabase(timezone_path);
3777 copyright = g_string_append(copyright, ZDGetNotice(cd));
3778 ZDCloseDatabase(cd);
3782 g_free(timezone_path);
3786 path = g_build_filename(GQ_HELPDIR, "AUTHORS", NULL);
3787 fp = fopen(path, "r");
3790 while(fgets(line, LINE_LENGTH, fp))
3792 /* get rid of ending \n from fgets */
3793 line[strlen(line) - 1] = '\0';
3794 authors[i_authors] = g_strdup(line);
3797 authors[i_authors] = NULL;
3802 comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
3803 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
3805 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
3806 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
3807 gtk_show_about_dialog(GTK_WINDOW(lw->window),
3808 "title", _("About Geeqie"),
3810 "program-name", GQ_APPNAME,
3812 "logo", pixbuf_logo,
3813 "icon", pixbuf_icon,
3814 "website", GQ_WEBSITE,
3815 "website-label", "Website",
3816 "comments", comment,
3818 "translator-credits", _("translator-credits"),
3819 "wrap-license", TRUE,
3820 "license", copyright->str,
3823 g_string_free(copyright, TRUE);
3826 while(n < i_authors)
3836 static void image_overlay_set_text_colours()
3838 c_options->image_overlay.text_red = options->image_overlay.text_red;
3839 c_options->image_overlay.text_green = options->image_overlay.text_green;
3840 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
3841 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
3842 c_options->image_overlay.background_red = options->image_overlay.background_red;
3843 c_options->image_overlay.background_green = options->image_overlay.background_green;
3844 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
3845 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
3849 *-----------------------------------------------------------------------------
3850 * timezone database routines
3851 *-----------------------------------------------------------------------------
3854 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
3856 GError *error = NULL;
3858 gchar *tmp_filename;
3860 if (!g_cancellable_is_cancelled(tz->cancellable))
3862 generic_dialog_close(tz->gd);
3866 if (g_file_copy_finish(G_FILE(source_object), res, &error))
3868 tmp_filename = g_file_get_parse_name(tz->tmp_g_file);
3869 move_file(tmp_filename, tz->timezone_database_user);
3870 g_free(tmp_filename);
3874 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3877 g_file_delete(tz->tmp_g_file, NULL, &error);
3878 g_object_unref(tz->tmp_g_file);
3879 tz->tmp_g_file = NULL;
3880 g_object_unref(tz->cancellable);
3881 g_object_unref(tz->timezone_database_gq);
3884 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
3888 if (!g_cancellable_is_cancelled(tz->cancellable))
3890 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
3894 static void timezone_cancel_button_cb(GenericDialog *gd, gpointer data)
3898 g_cancellable_cancel(tz->cancellable);
3901 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
3904 GError *error = NULL;
3905 GFileIOStream *io_stream;
3912 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
3916 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
3917 log_printf("Error: Download timezone database failed:\n%s", error->message);
3918 g_error_free(error);
3919 g_object_unref(tz->tmp_g_file);
3923 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE);
3925 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
3927 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
3929 tz->progress = gtk_progress_bar_new();
3930 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
3931 gtk_widget_show(tz->progress);
3933 gtk_widget_show(tz->gd->dialog);
3934 tz->cancellable = g_cancellable_new();
3935 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);
3937 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
3940 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */