2 * Copyright (C) 2006 John Ellis
3 * Copyright (C) 2008 - 2016 The Geeqie Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "preferences.h"
26 #include "bar_keywords.h"
28 #include "cache_maint.h"
33 #include "filefilter.h"
34 #include "fullscreen.h"
36 #include "image-overlay.h"
37 #include "color-man.h"
39 #include "layout_config.h"
40 #include "layout_util.h"
44 #include "pixbuf_util.h"
46 #include "slideshow.h"
50 #include "ui_fileops.h"
52 #include "ui_spinner.h"
53 #include "ui_tabcomp.h"
54 #include "ui_utildlg.h"
56 #include "zonedetect.h"
66 #define EDITOR_NAME_MAX_LENGTH 32
67 #define EDITOR_COMMAND_MAX_LENGTH 1024
69 static void image_overlay_set_text_colours();
71 GtkWidget *keyword_text;
72 static void config_tab_keywords_save();
74 typedef struct _ThumbSize ThumbSize;
81 static ThumbSize thumb_size_list[] =
115 gchar *format_class_list[] = {
125 /* config memory values */
126 static ConfOptions *c_options = NULL;
133 static GtkWidget *configwindow = NULL;
134 static GtkListStore *filter_store = NULL;
135 static GtkTreeStore *accel_store = NULL;
137 static GtkWidget *safe_delete_path_entry;
139 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
140 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
141 static GtkWidget *color_profile_screen_file_entry;
142 static GtkWidget *external_preview_select_entry;
143 static GtkWidget *external_preview_extract_entry;
145 static GtkWidget *sidecar_ext_entry;
146 static GtkWidget *help_search_engine_entry;
149 #define CONFIG_WINDOW_DEF_WIDTH 700
150 #define CONFIG_WINDOW_DEF_HEIGHT 600
153 *-----------------------------------------------------------------------------
154 * option widget callbacks (private)
155 *-----------------------------------------------------------------------------
158 static void zoom_increment_cb(GtkWidget *spin, gpointer data)
160 c_options->image.zoom_increment = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
163 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer data)
165 gint mins_secs_tenths, delay;
167 mins_secs_tenths = c_options->slideshow.delay %
168 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
170 delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
171 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
174 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
175 SLIDESHOW_SUBSECOND_PRECISION;
178 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer data)
180 gint hours, secs_tenths, delay;
182 hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
183 secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
185 delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
186 (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
187 (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
189 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
190 SLIDESHOW_SUBSECOND_PRECISION;
193 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer data)
195 gint hours_mins, delay;
197 hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
199 delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
200 (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
201 (gdouble)(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
203 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
204 SLIDESHOW_SUBSECOND_PRECISION;
208 *-----------------------------------------------------------------------------
209 * sync program to config window routine (private)
210 *-----------------------------------------------------------------------------
213 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
219 buf = gtk_entry_get_text(GTK_ENTRY(entry));
220 if (buf && strlen(buf) > 0)
225 *option = g_strdup(buf);
230 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
232 gchar *accel_path, *accel;
234 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
236 if (accel_path && accel_path[0])
239 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
240 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
250 static void config_window_apply(void)
252 gboolean refresh = FALSE;
257 config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
259 if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
260 if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
261 if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
262 if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
263 if (options->file_sort.natural != c_options->file_sort.natural) refresh = TRUE;
264 if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
265 if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
267 options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
268 options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
269 options->file_ops.confirm_move_to_trash = c_options->file_ops.confirm_move_to_trash;
270 options->file_ops.use_system_trash = c_options->file_ops.use_system_trash;
271 options->file_ops.no_trash = c_options->file_ops.no_trash;
272 options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
273 options->tools_restore_state = c_options->tools_restore_state;
274 options->save_window_positions = c_options->save_window_positions;
275 options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
276 options->save_window_workspace = c_options->save_window_workspace;
277 options->save_dialog_window_positions = c_options->save_dialog_window_positions;
278 options->show_window_ids = c_options->show_window_ids;
279 options->image.scroll_reset_method = c_options->image.scroll_reset_method;
280 options->image.zoom_2pass = c_options->image.zoom_2pass;
281 options->image.fit_window_to_image = c_options->image.fit_window_to_image;
282 options->image.limit_window_size = c_options->image.limit_window_size;
283 options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
284 options->image.max_window_size = c_options->image.max_window_size;
285 options->image.limit_autofit_size = c_options->image.limit_autofit_size;
286 options->image.max_autofit_size = c_options->image.max_autofit_size;
287 options->image.max_enlargement_size = c_options->image.max_enlargement_size;
288 options->image.use_clutter_renderer = c_options->image.use_clutter_renderer;
289 options->image.tile_size = c_options->image.tile_size;
290 options->progressive_key_scrolling = c_options->progressive_key_scrolling;
291 options->keyboard_scroll_step = c_options->keyboard_scroll_step;
293 if (options->thumbnails.max_width != c_options->thumbnails.max_width
294 || options->thumbnails.max_height != c_options->thumbnails.max_height
295 || options->thumbnails.quality != c_options->thumbnails.quality)
297 thumb_format_changed = TRUE;
299 options->thumbnails.max_width = c_options->thumbnails.max_width;
300 options->thumbnails.max_height = c_options->thumbnails.max_height;
301 options->thumbnails.quality = c_options->thumbnails.quality;
303 options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
304 options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
305 options->thumbnails.use_exif = c_options->thumbnails.use_exif;
306 options->thumbnails.use_color_management = c_options->thumbnails.use_color_management;
307 options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
308 options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
309 // options->thumbnails.use_ft_metadata_small = c_options->thumbnails.use_ft_metadata_small;
310 options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
311 options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
312 options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
313 options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
314 options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
315 options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
317 options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
318 options->file_sort.natural = c_options->file_sort.natural;
319 options->file_filter.disable = c_options->file_filter.disable;
321 config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, NULL);
322 sidecar_ext_parse(options->sidecar.ext);
324 options->slideshow.random = c_options->slideshow.random;
325 options->slideshow.repeat = c_options->slideshow.repeat;
326 options->slideshow.delay = c_options->slideshow.delay;
328 options->mousewheel_scrolls = c_options->mousewheel_scrolls;
329 options->image_lm_click_nav = c_options->image_lm_click_nav;
330 options->image_l_click_video = c_options->image_l_click_video;
331 options->image_l_click_video_editor = c_options->image_l_click_video_editor;
333 options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
335 options->image.tile_cache_max = c_options->image.tile_cache_max;
336 options->image.image_cache_max = c_options->image.image_cache_max;
338 options->image.zoom_quality = c_options->image.zoom_quality;
340 options->image.zoom_increment = c_options->image.zoom_increment;
342 options->image.enable_read_ahead = c_options->image.enable_read_ahead;
345 if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
346 || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
347 || !gdk_color_equal(&options->image.border_color, &c_options->image.border_color))
349 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
350 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
351 options->image.border_color = c_options->image.border_color;
352 layout_colors_update();
353 view_window_colors_update();
356 options->image.alpha_color_1 = c_options->image.alpha_color_1;
357 options->image.alpha_color_2 = c_options->image.alpha_color_2;
359 options->fullscreen.screen = c_options->fullscreen.screen;
360 options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
361 options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
362 options->fullscreen.above = c_options->fullscreen.above;
363 if (c_options->image_overlay.template_string)
364 set_image_overlay_template_string(&options->image_overlay.template_string,
365 c_options->image_overlay.template_string);
366 if (c_options->image_overlay.font)
367 set_image_overlay_font_string(&options->image_overlay.font,
368 c_options->image_overlay.font);
369 options->image_overlay.text_red = c_options->image_overlay.text_red;
370 options->image_overlay.text_green = c_options->image_overlay.text_green;
371 options->image_overlay.text_blue = c_options->image_overlay.text_blue;
372 options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
373 options->image_overlay.background_red = c_options->image_overlay.background_red;
374 options->image_overlay.background_green = c_options->image_overlay.background_green;
375 options->image_overlay.background_blue = c_options->image_overlay.background_blue;
376 options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
377 options->update_on_time_change = c_options->update_on_time_change;
378 options->image.exif_proof_rotate_enable = c_options->image.exif_proof_rotate_enable;
380 options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
381 options->rot_invariant_sim = c_options->rot_invariant_sim;
383 options->tree_descend_subdirs = c_options->tree_descend_subdirs;
385 options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
386 options->circular_selection_lists = c_options->circular_selection_lists;
388 options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
389 options->dnd_icon_size = c_options->dnd_icon_size;
390 options->clipboard_selection = c_options->clipboard_selection;
391 options->dnd_default_action = c_options->dnd_default_action;
393 options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
394 options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
395 options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
396 options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
397 options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
398 options->metadata.confirm_write = c_options->metadata.confirm_write;
399 options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
400 options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
401 options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
402 options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
403 options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
404 options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
405 options->metadata.write_orientation = c_options->metadata.write_orientation;
406 options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
407 (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
408 (c_options->stereo.tmp.flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
409 (c_options->stereo.tmp.mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
410 (c_options->stereo.tmp.flip_left ? PR_STEREO_FLIP_LEFT : 0) |
411 (c_options->stereo.tmp.swap ? PR_STEREO_SWAP : 0) |
412 (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
413 options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
414 (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
415 (c_options->stereo.tmp.fs_flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
416 (c_options->stereo.tmp.fs_mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
417 (c_options->stereo.tmp.fs_flip_left ? PR_STEREO_FLIP_LEFT : 0) |
418 (c_options->stereo.tmp.fs_swap ? PR_STEREO_SWAP : 0) |
419 (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
420 options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
421 options->stereo.fixed_w = c_options->stereo.fixed_w;
422 options->stereo.fixed_h = c_options->stereo.fixed_h;
423 options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
424 options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
425 options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
426 options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
428 options->info_keywords.height = c_options->info_keywords.height;
429 options->info_title.height = c_options->info_title.height;
430 options->info_comment.height = c_options->info_comment.height;
431 options->info_rating.height = c_options->info_rating.height;
433 options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
434 options->expand_menu_toolbar = c_options->expand_menu_toolbar;
436 options->marks_save = c_options->marks_save;
437 options->with_rename = c_options->with_rename;
438 options->collections_on_top = c_options->collections_on_top;
439 options->hide_window_in_fullscreen = c_options->hide_window_in_fullscreen;
440 config_entry_to_option(help_search_engine_entry, &options->help_search_engine, NULL);
442 options->external_preview.enable = c_options->external_preview.enable;
443 config_entry_to_option(external_preview_select_entry, &options->external_preview.select, NULL);
444 config_entry_to_option(external_preview_extract_entry, &options->external_preview.extract, NULL);
446 options->read_metadata_in_idle = c_options->read_metadata_in_idle;
448 options->star_rating.star = c_options->star_rating.star;
449 options->star_rating.rejected = c_options->star_rating.rejected;
451 options->threads.duplicates = c_options->threads.duplicates > 0 ? c_options->threads.duplicates : -1;
454 set_debug_level(debug_c);
458 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
460 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
461 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
463 config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
464 options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
465 if (options->color_profile.render_intent != c_options->color_profile.render_intent)
467 options->color_profile.render_intent = c_options->color_profile.render_intent;
472 options->mouse_button_8 = c_options->mouse_button_8;
473 options->mouse_button_9 = c_options->mouse_button_9;
475 options->override_disable_gpu = c_options->override_disable_gpu;
477 config_tab_keywords_save();
479 image_options_sync();
484 layout_refresh(NULL);
487 if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, NULL);
489 toolbar_apply(TOOLBAR_MAIN);
490 toolbar_apply(TOOLBAR_STATUS);
494 *-----------------------------------------------------------------------------
495 * config window main button callbacks (private)
496 *-----------------------------------------------------------------------------
499 static void config_window_close_cb(GtkWidget *widget, gpointer data)
501 gtk_widget_destroy(configwindow);
506 static void config_window_help_cb(GtkWidget *widget, gpointer data)
508 GtkWidget *notebook = data;
511 static gchar *html_section[] =
513 "GuideOptionsGeneral.html",
514 "GuideOptionsImage.html",
515 "GuideOptionsOSD.html",
516 "GuideOptionsWindow.html",
517 "GuideOptionsKeyboard.html",
518 "GuideOptionsFiltering.html",
519 "GuideOptionsMetadata.html",
520 "GuideOptionsKeywords.html",
521 "GuideOptionsColor.html",
522 "GuideOptionsStereo.html",
523 "GuideOptionsBehavior.html",
524 "GuideOptionsToolbar.html",
525 "GuideOptionsToolbar.html",
526 "GuideOptionsAdvanced.html"
529 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
530 help_window_show(html_section[i]);
533 static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpointer data)
535 config_window_close_cb(NULL, NULL);
539 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
542 GtkNotebook *notebook = data;
550 lw = layout_window_list->data;
552 window = gtk_widget_get_window(widget);
553 gdk_window_get_root_origin(window, &x, &y);
554 w = gdk_window_get_width(window);
555 h = gdk_window_get_height(window);
556 page_number = gtk_notebook_get_current_page(notebook);
558 lw->options.preferences_window.x = x;
559 lw->options.preferences_window.y = y;
560 lw->options.preferences_window.w = w;
561 lw->options.preferences_window.h = h;
562 lw->options.preferences_window.page_number = page_number;
564 config_window_apply();
565 layout_util_sync(lw);
566 save_options(options);
567 config_window_close_cb(NULL, NULL);
571 *-----------------------------------------------------------------------------
572 * config window setup (private)
573 *-----------------------------------------------------------------------------
576 static void quality_menu_cb(GtkWidget *combo, gpointer data)
580 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
584 *option = GDK_INTERP_NEAREST;
587 *option = GDK_INTERP_TILES;
590 *option = GDK_INTERP_BILINEAR;
595 static void dnd_default_action_selection_menu_cb(GtkWidget *combo, gpointer data)
599 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
603 *option = DND_ACTION_ASK;
606 *option = DND_ACTION_COPY;
609 *option = DND_ACTION_MOVE;
613 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
617 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
620 *option = CLIPBOARD_PRIMARY;
623 *option = CLIPBOARD_CLIPBOARD;
626 *option = CLIPBOARD_BOTH;
629 *option = CLIPBOARD_BOTH;
633 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
634 guint option, guint *option_c)
641 pref_table_label(table, column, row, text, 0.0);
643 combo = gtk_combo_box_text_new();
645 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
646 if (option == GDK_INTERP_NEAREST) current = 0;
647 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
648 if (option == GDK_INTERP_TILES) current = 1;
649 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear (best, but slowest)"));
650 if (option == GDK_INTERP_BILINEAR) current = 2;
652 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
654 g_signal_connect(G_OBJECT(combo), "changed",
655 G_CALLBACK(quality_menu_cb), option_c);
657 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
658 gtk_widget_show(combo);
661 static void add_dnd_default_action_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, DnDAction option, DnDAction *option_c)
668 pref_table_label(table, column, row, text, 0.0);
670 combo = gtk_combo_box_text_new();
672 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Ask"));
673 if (option == DND_ACTION_ASK) current = 0;
674 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Copy"));
675 if (option == DND_ACTION_COPY) current = 1;
676 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Move"));
677 if (option == DND_ACTION_MOVE) current = 2;
679 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
681 g_signal_connect(G_OBJECT(combo), "changed",
682 G_CALLBACK(dnd_default_action_selection_menu_cb), option_c);
684 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
685 gtk_widget_show(combo);
688 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
689 gint option, gint *option_c)
696 pref_table_label(table, column, row, text, 0.0);
698 combo = gtk_combo_box_text_new();
700 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Primary"));
701 if (option == CLIPBOARD_PRIMARY) current = 0;
702 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Clipboard"));
703 if (option == CLIPBOARD_CLIPBOARD) current = 1;
704 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Both"));
705 if (option == CLIPBOARD_BOTH) current = 2;
707 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
709 g_signal_connect(G_OBJECT(combo), "changed",
710 G_CALLBACK(clipboard_selection_menu_cb), option_c);
712 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
713 gtk_widget_show(combo);
716 typedef struct _UseableMouseItems UseableMouseItems;
717 struct _UseableMouseItems
719 gchar *name; /* GtkActionEntry terminology */
724 static const UseableMouseItems useable_mouse_items[] = {
726 {"FirstImage", N_("First Image"), GTK_STOCK_GOTO_TOP},
727 {"PrevImage", N_("Previous Image"), GTK_STOCK_GO_UP},
728 {"NextImage", N_("Next Image"), GTK_STOCK_GO_DOWN},
729 {"LastImage", N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
730 {"Back", N_("Back"), GTK_STOCK_GO_BACK},
731 {"Forward", N_("Forward"), GTK_STOCK_GO_FORWARD},
732 {"Home", N_("Home"), GTK_STOCK_HOME},
733 {"Up", N_("Up"), GTK_STOCK_GO_UP},
734 {"FirstPage", N_("First page"), GTK_STOCK_MEDIA_PREVIOUS},
735 {"LastPage", N_("Last Page"), GTK_STOCK_MEDIA_NEXT},
736 {"NextPage", N_("Next page"), GTK_STOCK_MEDIA_FORWARD},
737 {"PrevPage", N_("Previous Page"), GTK_STOCK_MEDIA_REWIND},
738 {"NewWindow", N_("New _window"), GTK_STOCK_NEW},
739 {"NewCollection", N_("New collection"), GTK_STOCK_INDEX},
740 {"OpenCollection", N_("Open collection"), GTK_STOCK_OPEN},
741 {"Search", N_("Search"), GTK_STOCK_FIND},
742 {"FindDupes", N_("Find duplicates"), GTK_STOCK_FIND},
743 {"NewFolder", N_("New folder"),GTK_STOCK_DIRECTORY},
744 {"Copy", N_("Copy"), GTK_STOCK_COPY},
745 {"Move", N_("Move"), PIXBUF_INLINE_ICON_MOVE},
746 {"Rename", N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
747 {"Delete", N_("Delete"), GTK_STOCK_DELETE},
748 {"CloseWindow", N_("Close Window"), GTK_STOCK_CLOSE},
749 {"PanView", N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
750 {"SelectAll", N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
751 {"SelectNone", N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
752 {"SelectInvert", N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
753 {"ShowFileFilter", N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
754 {"RectangularSelection", N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
755 {"Print", N_("Print"), GTK_STOCK_PRINT},
756 {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
757 {"LayoutConfig", N_("Configure this window"), GTK_STOCK_PREFERENCES},
758 {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
759 {"RotateCW", N_("Rotate clockwise 90°"), PIXBUF_INLINE_ICON_CW},
760 {"RotateCCW", N_("Rotate counterclockwise 90°"), PIXBUF_INLINE_ICON_CCW},
761 {"Rotate180", N_("Rotate 180°"), PIXBUF_INLINE_ICON_180},
762 {"Mirror", N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
763 {"Flip", N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
764 {"AlterNone", N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
765 {"ZoomIn", N_("Zoom in"), GTK_STOCK_ZOOM_IN},
766 {"ZoomOut", N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
767 {"Zoom100", N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
768 {"ZoomFit", N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
769 {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
770 {"ZoomFillVert", N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
771 {"Zoom200", N_("Zoom 2:1"), GTK_STOCK_FILE},
772 {"Zoom300", N_("Zoom 3:1"), GTK_STOCK_FILE},
773 {"Zoom400", N_("Zoom 4:1"), GTK_STOCK_FILE},
774 {"Zoom50", N_("Zoom 1:2"), GTK_STOCK_FILE},
775 {"Zoom33", N_("Zoom1:3"), GTK_STOCK_FILE},
776 {"Zoom25", N_("Zoom 1:4"), GTK_STOCK_FILE},
777 {"ConnectZoomIn", N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
778 {"SplitPaneSync", N_("Split Pane Sync"), PIXBUF_INLINE_SPLIT_PANE_SYNC},
779 {"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
780 {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
781 {"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
782 {"SlideShowPause", N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
783 {"SlideShowFaster", N_("Slideshow Faster"), GTK_STOCK_FILE},
784 {"SlideShowSlower", N_("Slideshow Slower"), GTK_STOCK_FILE},
785 {"Refresh", N_("Refresh"), GTK_STOCK_REFRESH},
786 {"HelpContents", N_("Help"), GTK_STOCK_HELP},
787 {"ExifWin", N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
788 {"Thumbnails", N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
789 {"ShowMarks", N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
790 {"DrawRectangle", N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
791 {"FloatTools", N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
792 {"SBar", N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
793 {"SBarSort", N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
794 {"Quit", N_("Quit"), GTK_STOCK_QUIT},
798 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
800 gchar **option = data;
803 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
805 const UseableMouseItems *list = useable_mouse_items;
809 if (g_strcmp0(list->label, label) == 0)
817 *option = g_strdup(list->name);
821 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
822 gchar *option, gchar **option_c)
830 pref_table_label(table, column, row, text, 0.0);
832 combo = gtk_combo_box_text_new();
834 const UseableMouseItems *list = useable_mouse_items;
838 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
839 if (g_strcmp0(list->name, option) == 0)
847 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
849 g_signal_connect(G_OBJECT(combo), "changed",
850 G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
852 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
853 gtk_widget_show(combo);
856 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
860 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
863 if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
865 c_options->thumbnails.max_width = thumb_size_list[n].w;
866 c_options->thumbnails.max_height = thumb_size_list[n].h;
870 c_options->thumbnails.max_width = options->thumbnails.max_width;
871 c_options->thumbnails.max_height = options->thumbnails.max_height;
875 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
881 c_options->thumbnails.max_width = options->thumbnails.max_width;
882 c_options->thumbnails.max_height = options->thumbnails.max_height;
884 pref_table_label(table, column, row, text, 0.0);
886 combo = gtk_combo_box_text_new();
889 for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
894 w = thumb_size_list[i].w;
895 h = thumb_size_list[i].h;
897 buf = g_strdup_printf("%d x %d", w, h);
898 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
901 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
908 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
909 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
915 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
916 g_signal_connect(G_OBJECT(combo), "changed",
917 G_CALLBACK(thumb_size_menu_cb), NULL);
919 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
920 gtk_widget_show(combo);
923 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
927 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
931 *option = PR_STEREO_NONE;
934 *option = PR_STEREO_ANAGLYPH_RC;
937 *option = PR_STEREO_ANAGLYPH_GM;
940 *option = PR_STEREO_ANAGLYPH_YB;
943 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
946 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
949 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
952 *option = PR_STEREO_ANAGLYPH_DB_RC;
955 *option = PR_STEREO_ANAGLYPH_DB_GM;
958 *option = PR_STEREO_ANAGLYPH_DB_YB;
961 *option = PR_STEREO_HORIZ;
964 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
967 *option = PR_STEREO_VERT;
970 *option = PR_STEREO_VERT | PR_STEREO_HALF;
973 *option = PR_STEREO_FIXED;
978 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
979 gint option, gint *option_c, gboolean add_fixed)
986 pref_table_label(table, column, row, text, 0.0);
988 combo = gtk_combo_box_text_new();
990 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
992 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
993 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
994 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
995 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
996 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
997 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
998 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
999 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
1000 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
1001 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
1002 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
1003 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
1004 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
1005 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
1006 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
1007 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
1008 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
1009 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
1011 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
1012 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
1013 if (option & PR_STEREO_HORIZ)
1016 if (option & PR_STEREO_HALF) current = 11;
1019 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
1020 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
1021 if (option & PR_STEREO_VERT)
1024 if (option & PR_STEREO_HALF) current = 13;
1029 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
1030 if (option & PR_STEREO_FIXED) current = 14;
1033 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1035 g_signal_connect(G_OBJECT(combo), "changed",
1036 G_CALLBACK(stereo_mode_menu_cb), option_c);
1038 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1039 gtk_widget_show(combo);
1042 static void video_menu_cb(GtkWidget *combo, gpointer data)
1044 gchar **option = data;
1046 EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
1050 static void video_menu_populate(gpointer data, gpointer user_data)
1052 GtkWidget *combo = user_data;
1053 EditorDescription *ed = data;
1055 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1058 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1059 gchar *option, gchar **option_c)
1063 /* use lists since they are sorted */
1064 GList *eds = editor_list_get();
1068 pref_table_label(table, column, row, text, 0.0);
1070 combo = gtk_combo_box_text_new();
1071 g_list_foreach(eds,video_menu_populate,(gpointer)combo);
1072 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1074 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1076 g_signal_connect(G_OBJECT(combo), "changed",
1077 G_CALLBACK(video_menu_cb), option_c);
1079 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1080 gtk_widget_show(combo);
1083 static void filter_store_populate(void)
1087 if (!filter_store) return;
1089 gtk_list_store_clear(filter_store);
1091 work = filter_get_list();
1100 gtk_list_store_append(filter_store, &iter);
1101 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1105 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1106 gchar *new_text, gpointer data)
1108 GtkWidget *model = data;
1109 FilterEntry *fe = data;
1113 if (!new_text || strlen(new_text) < 1) return;
1115 tpath = gtk_tree_path_new_from_string(path_str);
1116 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1117 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1119 g_free(fe->extensions);
1120 fe->extensions = g_strdup(new_text);
1122 gtk_tree_path_free(tpath);
1126 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1127 gchar *new_text, gpointer data)
1129 GtkWidget *model = data;
1130 FilterEntry *fe = data;
1135 if (!new_text || !new_text[0]) return;
1137 tpath = gtk_tree_path_new_from_string(path_str);
1138 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1139 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1141 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1143 if (strcmp(new_text, _(format_class_list[i])) == 0)
1150 gtk_tree_path_free(tpath);
1154 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1155 gchar *new_text, gpointer data)
1157 GtkWidget *model = data;
1162 if (!new_text || !new_text[0]) return;
1164 tpath = gtk_tree_path_new_from_string(path_str);
1165 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1166 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1168 g_free(fe->description);
1169 fe->description = g_strdup(new_text);
1171 gtk_tree_path_free(tpath);
1174 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
1175 gchar *path_str, gpointer data)
1177 GtkWidget *model = data;
1182 tpath = gtk_tree_path_new_from_string(path_str);
1183 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1184 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1186 fe->enabled = !fe->enabled;
1188 gtk_tree_path_free(tpath);
1192 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
1193 gchar *path_str, gpointer data)
1195 GtkWidget *model = data;
1200 tpath = gtk_tree_path_new_from_string(path_str);
1201 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1202 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1204 fe->writable = !fe->writable;
1205 if (fe->writable) fe->allow_sidecar = FALSE;
1207 gtk_tree_path_free(tpath);
1211 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
1212 gchar *path_str, gpointer data)
1214 GtkWidget *model = data;
1219 tpath = gtk_tree_path_new_from_string(path_str);
1220 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1221 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1223 fe->allow_sidecar = !fe->allow_sidecar;
1224 if (fe->allow_sidecar) fe->writable = FALSE;
1226 gtk_tree_path_free(tpath);
1230 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1231 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1235 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1237 switch (GPOINTER_TO_INT(data))
1240 g_object_set(GTK_CELL_RENDERER(cell),
1241 "active", fe->enabled, NULL);
1244 g_object_set(GTK_CELL_RENDERER(cell),
1245 "text", fe->extensions, NULL);
1247 case FE_DESCRIPTION:
1248 g_object_set(GTK_CELL_RENDERER(cell),
1249 "text", fe->description, NULL);
1252 g_object_set(GTK_CELL_RENDERER(cell),
1253 "text", _(format_class_list[fe->file_class]), NULL);
1256 g_object_set(GTK_CELL_RENDERER(cell),
1257 "active", fe->writable, NULL);
1259 case FE_ALLOW_SIDECAR:
1260 g_object_set(GTK_CELL_RENDERER(cell),
1261 "active", fe->allow_sidecar, NULL);
1266 static gboolean filter_add_scroll(gpointer data)
1270 GtkCellRenderer *cell;
1271 GtkTreeViewColumn *column;
1274 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1275 path = gtk_tree_path_new_from_indices(rows-1, -1);
1277 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1279 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1280 cell = g_list_last(list_cells)->data;
1282 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1283 path, column, FALSE, 0.0, 0.0 );
1284 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1285 path, column, cell, TRUE);
1287 gtk_tree_path_free(path);
1288 g_list_free(list_cells);
1293 static void filter_add_cb(GtkWidget *widget, gpointer data)
1295 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1296 filter_store_populate();
1298 g_idle_add((GSourceFunc)filter_add_scroll, data);
1301 static void filter_remove_cb(GtkWidget *widget, gpointer data)
1303 GtkWidget *filter_view = data;
1304 GtkTreeSelection *selection;
1308 if (!filter_store) return;
1309 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1310 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1311 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1314 filter_remove_entry(fe);
1316 filter_store_populate();
1319 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1323 GtkTreeViewColumn *column;
1325 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1326 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1327 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1329 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1333 gtk_tree_path_free(path);
1338 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
1341 filter_add_defaults();
1343 filter_store_populate();
1345 g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1348 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1350 /* no op, only so cancel button appears */
1353 static void filter_default_cb(GtkWidget *widget, gpointer data)
1357 gd = generic_dialog_new(_("Reset filters"),
1358 "reset_filter", widget, TRUE,
1359 dummy_cancel_cb, data);
1360 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1361 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1362 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1363 gtk_widget_show(gd->dialog);
1366 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1368 GtkWidget *frame = data;
1370 gtk_widget_set_sensitive(frame,
1371 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1374 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
1376 layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1379 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
1381 file_util_trash_clear();
1384 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
1388 gd = generic_dialog_new(_("Clear trash"),
1389 "clear_trash", widget, TRUE,
1390 dummy_cancel_cb, NULL);
1391 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1392 _("This will remove the trash contents."), FALSE);
1393 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1394 entry = gtk_entry_new();
1395 gtk_widget_set_can_focus(entry, FALSE);
1396 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1397 if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1398 gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1399 gtk_widget_show(entry);
1400 gtk_widget_show(gd->dialog);
1403 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
1405 GtkWidget *pTextView;
1406 GtkTextBuffer *pTextBuffer;
1410 pTextView = GTK_WIDGET(data);
1412 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1413 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1414 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1416 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1417 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1420 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
1422 GtkTextView *text_view = data;
1423 GtkTextBuffer *buffer;
1425 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1426 if (!configwindow) return;
1428 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1429 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1432 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1436 gd = generic_dialog_new(_("Reset image overlay template string"),
1437 "reset_image_overlay_template_string", widget, TRUE,
1438 dummy_cancel_cb, data);
1439 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1440 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1441 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1442 gtk_widget_show(gd->dialog);
1445 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
1447 help_window_show("GuideOptionsOSD.html");
1450 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer data)
1452 #if GTK_CHECK_VERSION(3,4,0)
1455 PangoFontDescription *font_desc;
1457 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1458 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1460 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1462 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1463 font = pango_font_description_to_string(font_desc);
1464 g_free(c_options->image_overlay.font);
1465 c_options->image_overlay.font = g_strdup(font);
1469 gtk_widget_destroy(dialog);
1473 font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
1474 c_options->image_overlay.font = g_strdup(font);
1478 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer data)
1481 #if GTK_CHECK_VERSION(3,4,0)
1484 dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1485 colour.red = options->image_overlay.text_red;
1486 colour.green = options->image_overlay.text_green;
1487 colour.blue = options->image_overlay.text_blue;
1488 colour.alpha = options->image_overlay.text_alpha;
1489 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1490 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1492 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1494 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1495 c_options->image_overlay.text_red = colour.red*255;
1496 c_options->image_overlay.text_green = colour.green*255;
1497 c_options->image_overlay.text_blue = colour.blue*255;
1498 c_options->image_overlay.text_alpha = colour.alpha*255;
1500 gtk_widget_destroy(dialog);
1503 GtkColorSelection *colorsel;
1505 dialog = gtk_color_selection_dialog_new("Image Overlay Text Colour");
1506 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1507 colour.red = options->image_overlay.text_red*257;
1508 colour.green = options->image_overlay.text_green*257;
1509 colour.blue = options->image_overlay.text_blue*257;
1510 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1511 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1512 gtk_color_selection_set_current_color(colorsel, &colour);
1513 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.text_alpha*257);
1515 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1517 gtk_color_selection_get_current_color(colorsel, &colour);
1518 c_options->image_overlay.text_red = colour.red/257;
1519 c_options->image_overlay.text_green = colour.green/257;
1520 c_options->image_overlay.text_blue = colour.blue/257;
1521 c_options->image_overlay.text_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1523 gtk_widget_destroy (dialog);
1528 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer data)
1531 #if GTK_CHECK_VERSION(3,4,0)
1534 dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1535 colour.red = options->image_overlay.background_red;
1536 colour.green = options->image_overlay.background_green;
1537 colour.blue = options->image_overlay.background_blue;
1538 colour.alpha = options->image_overlay.background_alpha;
1539 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1540 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1542 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1544 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1545 c_options->image_overlay.background_red = colour.red*255;
1546 c_options->image_overlay.background_green = colour.green*255;
1547 c_options->image_overlay.background_blue = colour.blue*255;
1548 c_options->image_overlay.background_alpha = colour.alpha*255;
1550 gtk_widget_destroy(dialog);
1553 GtkColorSelection *colorsel;
1555 dialog = gtk_color_selection_dialog_new("Image Overlay Background Colour");
1556 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1557 colour.red = options->image_overlay.background_red*257;
1558 colour.green = options->image_overlay.background_green*257;
1559 colour.blue = options->image_overlay.background_blue*257;
1560 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1561 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1562 gtk_color_selection_set_current_color(colorsel, &colour);
1563 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.background_alpha*257);
1565 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1567 gtk_color_selection_get_current_color(colorsel, &colour);
1568 c_options->image_overlay.background_red = colour.red/257;
1569 c_options->image_overlay.background_green = colour.green/257;
1570 c_options->image_overlay.background_blue = colour.blue/257;
1571 c_options->image_overlay.background_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1573 gtk_widget_destroy(dialog);
1577 static void accel_store_populate(void)
1580 GList *groups, *actions;
1582 const gchar *accel_path;
1586 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1588 gtk_tree_store_clear(accel_store);
1589 lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
1591 g_assert(lw && lw->ui_manager);
1592 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1595 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1598 action = GTK_ACTION(actions->data);
1599 accel_path = gtk_action_get_accel_path(action);
1600 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1602 gchar *label, *label2, *tooltip, *accel;
1603 g_object_get(action,
1604 "tooltip", &tooltip,
1608 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1614 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1618 gtk_tree_store_append(accel_store, &iter, NULL);
1619 gtk_tree_store_set(accel_store, &iter,
1622 AE_TOOLTIP, tooltip ? tooltip : "",
1623 AE_ACCEL, accel_path,
1631 actions = actions->next;
1634 groups = groups->next;
1638 static void accel_store_cleared_cb(GtkCellRendererAccel *accel, gchar *path_string, gpointer user_data)
1643 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1645 gchar *accel1 = data;
1650 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1652 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1653 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1655 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1657 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1658 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1667 static void accel_store_edited_cb(GtkCellRendererAccel *accel, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode, gpointer user_data)
1669 GtkTreeModel *model = (GtkTreeModel *)accel_store;
1673 GtkAccelKey old_key, key;
1674 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1676 gtk_tree_model_get_iter(model, &iter, path);
1677 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1679 /* test if the accelerator can be stored without conflicts*/
1680 gtk_accel_map_lookup_entry(accel_path, &old_key);
1682 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1683 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1684 gtk_accel_map_lookup_entry(accel_path, &key);
1686 /* restore the original for now, the key will be really changed when the changes are confirmed */
1687 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1689 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1690 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1692 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1693 gtk_tree_path_free(path);
1697 static gboolean accel_default_scroll(GtkTreeView *data)
1701 GtkTreeViewColumn *column;
1703 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1704 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1705 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1707 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1711 gtk_tree_path_free(path);
1716 static void accel_default_cb(GtkWidget *widget, gpointer data)
1718 accel_store_populate();
1720 g_idle_add((GSourceFunc)accel_default_scroll, data);
1723 void accel_remove_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1725 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1728 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1731 gchar *accel_path, *accel;
1733 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1734 gtk_accel_map_lookup_entry(accel_path, &key);
1735 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1737 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1739 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1744 static void accel_reset_cb(GtkWidget *widget, gpointer data)
1746 GtkTreeSelection *selection;
1748 if (!accel_store) return;
1749 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1750 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1755 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1759 GtkWidget *scrolled;
1760 GtkWidget *viewport;
1762 scrolled = gtk_scrolled_window_new(NULL, NULL);
1763 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1764 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1765 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1766 label = gtk_label_new(title);
1767 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1768 gtk_widget_show(scrolled);
1770 viewport = gtk_viewport_new(NULL, NULL);
1771 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1772 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1773 gtk_widget_show(viewport);
1775 vbox = gtk_vbox_new(FALSE, 0);
1776 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1777 gtk_widget_show(vbox);
1782 static void cache_standard_cb(GtkWidget *widget, gpointer data)
1784 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1786 c_options->thumbnails.spec_standard =TRUE;
1787 c_options->thumbnails.cache_into_dirs = FALSE;
1791 static void cache_geeqie_cb(GtkWidget *widget, gpointer data)
1793 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1795 c_options->thumbnails.spec_standard =FALSE;
1796 c_options->thumbnails.cache_into_dirs = FALSE;
1800 static void cache_local_cb(GtkWidget *widget, gpointer data)
1802 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1804 c_options->thumbnails.cache_into_dirs = TRUE;
1805 c_options->thumbnails.spec_standard =FALSE;
1809 static void help_search_engine_entry_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1810 GdkEvent *event, gpointer userdata)
1812 if (pos == GTK_ENTRY_ICON_PRIMARY)
1814 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1818 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1822 static void star_rating_star_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1823 GdkEvent *event, gpointer userdata)
1825 gchar *rating_symbol;
1827 if (pos == GTK_ENTRY_ICON_PRIMARY)
1829 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1830 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1831 g_free(rating_symbol);
1835 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1836 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1837 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1841 static void star_rating_rejected_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1842 GdkEvent *event, gpointer userdata)
1844 gchar *rating_symbol;
1846 if (pos == GTK_ENTRY_ICON_PRIMARY)
1848 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1849 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1850 g_free(rating_symbol);
1854 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1855 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1856 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1860 static guint star_rating_symbol_test(GtkWidget *widget, gpointer data)
1862 GtkContainer *hbox = data;
1863 GString *str = g_string_new(NULL);
1864 GtkEntry *hex_code_entry;
1865 gchar *hex_code_full;
1868 guint64 hex_value = 0;
1870 list = gtk_container_get_children(hbox);
1872 hex_code_entry = g_list_nth_data(list, 2);
1873 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1875 hex_code = g_strsplit(hex_code_full, "+", 2);
1876 if (hex_code[0] && hex_code[1])
1878 hex_value = strtoull(hex_code[1], NULL, 16);
1880 if (!hex_value || hex_value > 0x10FFFF)
1882 hex_value = 0x003F; // Unicode 'Question Mark'
1884 str = g_string_append_unichar(str, (gunichar)hex_value);
1885 gtk_label_set_text(g_list_nth_data(list, 1), str->str);
1887 g_strfreev(hex_code);
1888 g_string_free(str, TRUE);
1889 g_free(hex_code_full);
1894 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1896 guint64 star_symbol;
1898 star_symbol = star_rating_symbol_test(widget, data);
1899 c_options->star_rating.star = star_symbol;
1902 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1904 guint64 rejected_symbol;
1906 rejected_symbol = star_rating_symbol_test(widget, data);
1907 c_options->star_rating.rejected = rejected_symbol;
1910 /* general options tab */
1911 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1912 typedef struct _TZData TZData;
1916 GCancellable *cancellable;
1918 GtkWidget *progress;
1920 GFile *timezone_database_gq;
1921 gchar *timezone_database_user;
1924 static void config_tab_general(GtkWidget *notebook)
1929 GtkWidget *group_frame;
1930 GtkWidget *subgroup;
1932 GtkWidget *ct_button;
1935 gint hours, minutes, remainder;
1937 GtkWidget *star_rating_entry;
1939 gchar *rating_symbol;
1942 GNetworkMonitor *net_mon;
1943 GSocketConnectable *geeqie_org;
1944 gboolean internet_available;
1947 vbox = scrolled_notebook_page(notebook, _("General"));
1949 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1951 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1952 add_thumb_size_menu(table, 0, 0, _("Size:"));
1953 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1955 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1956 pref_label_new(hbox, _("Custom size: "));
1957 pref_spin_new_int(hbox, _("Width:"), NULL, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
1958 pref_spin_new_int(hbox, _("Height:"), NULL, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
1960 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
1961 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1963 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1964 pref_checkbox_link_sensitivity(ct_button, subgroup);
1966 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
1967 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
1968 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
1969 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1970 button = pref_radiobutton_new(group_frame, NULL, get_thumbnails_cache_dir(),
1971 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1972 G_CALLBACK(cache_geeqie_cb), NULL);
1974 group_frame = pref_frame_new(subgroup, TRUE,
1975 _("Store thumbnails local to image folder (non-standard)"),
1976 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1977 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
1978 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
1979 G_CALLBACK(cache_local_cb), NULL);
1981 group_frame = pref_frame_new(subgroup, TRUE,
1982 _("Use standard thumbnail style and cache, shared with other applications"),
1983 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1984 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
1985 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1986 G_CALLBACK(cache_standard_cb), NULL);
1988 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
1989 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
1991 pref_checkbox_new_int(group, _("Thumbnail color management"),
1992 options->thumbnails.use_color_management, &c_options->thumbnails.use_color_management);
1994 spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
1996 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
1997 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
1999 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
2000 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
2001 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
2003 // pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
2004 // options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
2007 pref_spacer(group, PREF_PAD_GROUP);
2009 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
2011 c_options->star_rating.star = options->star_rating.star;
2012 c_options->star_rating.rejected = options->star_rating.rejected;
2014 str = g_string_new(NULL);
2015 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2016 pref_label_new(hbox, _("Star character: "));
2017 str = g_string_append_unichar(str, options->star_rating.star);
2018 pref_label_new(hbox, g_strdup(str->str));
2019 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
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_star_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_star_icon_cb),
2043 g_string_free(str, TRUE);
2044 g_free(rating_symbol);
2046 str = g_string_new(NULL);
2047 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2048 pref_label_new(hbox, _("Rejected character: "));
2049 str = g_string_append_unichar(str, options->star_rating.rejected);
2050 pref_label_new(hbox, g_strdup(str->str));
2051 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2052 star_rating_entry = gtk_entry_new();
2053 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2054 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2055 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2056 gtk_widget_show(star_rating_entry);
2057 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2058 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2059 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2060 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2061 gtk_widget_show(button);
2062 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."));
2063 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2064 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2065 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2066 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2067 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2068 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2069 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2070 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2071 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2072 G_CALLBACK(star_rating_rejected_icon_cb),
2075 g_string_free(str, TRUE);
2076 g_free(rating_symbol);
2078 pref_spacer(group, PREF_PAD_GROUP);
2080 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2082 c_options->slideshow.delay = options->slideshow.delay;
2083 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2084 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2085 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2086 seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2087 SLIDESHOW_SUBSECOND_PRECISION;
2089 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2091 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2093 options->slideshow.delay ? hours : 0.0,
2094 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2095 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2096 spin = pref_spin_new(hbox, ":" , NULL,
2098 options->slideshow.delay ? minutes: 0.0,
2099 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2100 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2101 spin = pref_spin_new(hbox, ":", NULL,
2102 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2103 options->slideshow.delay ? seconds : 10.0,
2104 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2105 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2107 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2108 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2110 pref_spacer(group, PREF_PAD_GROUP);
2112 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2114 pref_spin_new_int(group, _("Decoded image cache size (MiB):"), NULL,
2115 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2116 pref_checkbox_new_int(group, _("Preload next image"),
2117 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2119 pref_checkbox_new_int(group, _("Refresh on file change"),
2120 options->update_on_time_change, &c_options->update_on_time_change);
2123 pref_spacer(group, PREF_PAD_GROUP);
2125 group = pref_group_new(vbox, FALSE, _("Expand menu and toolbar"), GTK_ORIENTATION_VERTICAL);
2127 pref_checkbox_new_int(group, _("Expand menu and toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2128 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2129 gtk_widget_set_tooltip_text(group, _("Expand the menu and toolbar to the full width of the window"));
2131 pref_spacer(group, PREF_PAD_GROUP);
2133 net_mon = g_network_monitor_get_default();
2134 geeqie_org = g_network_address_parse_uri(GQ_WEBSITE, 80, NULL);
2135 internet_available = g_network_monitor_can_reach(net_mon, geeqie_org, NULL, NULL);
2136 g_object_unref(geeqie_org);
2138 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2139 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2141 if (!internet_available)
2143 gtk_widget_set_sensitive(group, FALSE);
2146 tz = g_new0(TZData, 1);
2148 path = path_from_utf8(TIMEZONE_DATABASE);
2149 basename = g_path_get_basename(path);
2150 tz->timezone_database_user = g_build_filename(get_rc_dir(), basename, NULL);
2154 if (isfile(tz->timezone_database_user))
2156 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2160 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2163 if (!internet_available)
2165 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"));
2169 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"));
2171 gtk_widget_show(button);
2173 pref_spacer(group, PREF_PAD_GROUP);
2175 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2177 help_search_engine_entry = gtk_entry_new();
2178 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2179 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2180 gtk_widget_show(help_search_engine_entry);
2182 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"));
2184 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2185 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2186 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2187 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2188 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2189 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2190 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2191 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2192 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2193 G_CALLBACK(help_search_engine_entry_icon_cb),
2194 help_search_engine_entry);
2198 static void config_tab_image(GtkWidget *notebook)
2203 GtkWidget *ct_button;
2204 GtkWidget *enlargement_button;
2207 GtkWidget *two_pass;
2209 GtkWidget *gpu_accel;
2212 vbox = scrolled_notebook_page(notebook, _("Image"));
2214 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2216 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2217 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2218 if (options->image.use_clutter_renderer && !options->disable_gpu)
2220 gtk_widget_set_sensitive(table, FALSE);
2224 gpu_accel = pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library (Requires restart)"),
2225 options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2226 if (options->disable_gpu && !options->override_disable_gpu)
2228 gtk_widget_set_sensitive(gpu_accel, FALSE);
2232 two_pass = pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2233 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2234 if (options->image.use_clutter_renderer && !options->disable_gpu)
2236 gtk_widget_set_sensitive(two_pass, FALSE);
2239 c_options->image.zoom_increment = options->image.zoom_increment;
2240 spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2241 0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2242 G_CALLBACK(zoom_increment_cb), NULL);
2243 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2245 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2247 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2248 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2249 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2250 spin = pref_spin_new_int(hbox, NULL, NULL,
2252 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2253 pref_checkbox_link_sensitivity(enlargement_button, spin);
2254 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."));
2256 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2257 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2258 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2259 spin = pref_spin_new_int(hbox, NULL, NULL,
2261 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2262 pref_checkbox_link_sensitivity(ct_button, spin);
2263 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."));
2265 group = pref_group_new(vbox, FALSE, _("Tile size"), GTK_ORIENTATION_VERTICAL);
2266 gtk_widget_set_sensitive(group, !options->image.use_clutter_renderer);
2268 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2269 spin = pref_spin_new_int(hbox, _("Pixels"), _("(Requires restart)"),
2271 options->image.tile_size, &c_options->image.tile_size);
2272 gtk_widget_set_tooltip_text(GTK_WIDGET(hbox), _("This value changes the size of the tiles large images are split into. Increasing the size of the tiles will reduce the tiling effect seen on image changes, but will also slightly increase the delay before the first part of a large image is seen."));
2274 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2276 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2277 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2279 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2280 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2282 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2283 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2285 c_options->image.border_color = options->image.border_color;
2287 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2288 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2290 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2291 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2293 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2294 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2296 group = pref_group_new(vbox, FALSE, _("Convenience"), GTK_ORIENTATION_VERTICAL);
2298 pref_checkbox_new_int(group, _("Auto rotate proofs using Exif information"),
2299 options->image.exif_proof_rotate_enable, &c_options->image.exif_proof_rotate_enable);
2304 static void save_default_window_layout_cb(GtkWidget *widget, gpointer data)
2306 LayoutWindow *lw = NULL;
2307 gchar *default_path;
2310 /* Get current lw */
2313 tmp_id = lw->options.id;
2314 lw->options.id = g_strdup("lw_default");
2316 default_path = g_build_filename(get_rc_dir(), DEFAULT_WINDOW_LAYOUT, NULL);
2317 save_default_layout_options_to_file(default_path, options, lw);
2318 g_free(lw->options.id);
2319 lw->options.id = tmp_id;
2320 g_free(default_path);
2323 #if GTK_CHECK_VERSION(3,22,0)
2324 static gboolean popover_cb(gpointer data)
2326 GtkPopover *popover = data;
2328 gtk_popover_popdown(popover);
2333 static void default_layout_changed_cb(GtkWidget *button, GtkPopover *popover)
2335 gtk_popover_popup(popover);
2337 g_timeout_add(2000, popover_cb, popover);
2340 static GtkWidget *create_popover(GtkWidget *parent, GtkWidget *child, GtkPositionType pos)
2344 popover = gtk_popover_new(parent);
2345 gtk_popover_set_position(GTK_POPOVER (popover), pos);
2346 gtk_container_add (GTK_CONTAINER(popover), child);
2347 gtk_container_set_border_width(GTK_CONTAINER (popover), 6);
2348 gtk_widget_show (child);
2354 static void config_tab_windows(GtkWidget *notebook)
2359 GtkWidget *subgroup;
2361 GtkWidget *ct_button;
2364 vbox = scrolled_notebook_page(notebook, _("Windows"));
2366 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2368 ct_button = pref_checkbox_new_int(group, _("Remember session"),
2369 options->save_window_positions, &c_options->save_window_positions);
2371 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2372 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2373 pref_checkbox_link_sensitivity(ct_button, button);
2375 button = pref_checkbox_new_int(group, _("Remember window workspace"),
2376 options->save_window_workspace, &c_options->save_window_workspace);
2377 pref_checkbox_link_sensitivity(ct_button, button);
2379 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2380 options->tools_restore_state, &c_options->tools_restore_state);
2382 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2383 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2385 pref_checkbox_new_int(group, _("Show window IDs"),
2386 options->show_window_ids, &c_options->show_window_ids);
2388 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2389 pref_label_new(subgroup, _("Use current layout for default: "));
2390 button = pref_button_new(subgroup, NULL, _("Set"), FALSE, G_CALLBACK(save_default_window_layout_cb), NULL);
2392 #if GTK_CHECK_VERSION(3,22,0)
2395 popover = create_popover(button, gtk_label_new(_("Current window layout\nhas been set as default")), GTK_POS_TOP);
2396 gtk_popover_set_modal(GTK_POPOVER (popover), FALSE);
2397 g_signal_connect(button, "clicked", G_CALLBACK(default_layout_changed_cb), popover);
2400 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2402 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2403 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2405 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2406 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2407 options->image.limit_window_size, &c_options->image.limit_window_size);
2408 spin = pref_spin_new_int(hbox, NULL, NULL,
2410 options->image.max_window_size, &c_options->image.max_window_size);
2411 pref_checkbox_link_sensitivity(ct_button, spin);
2413 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2415 c_options->fullscreen.screen = options->fullscreen.screen;
2416 c_options->fullscreen.above = options->fullscreen.above;
2417 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2418 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2419 gtk_widget_show(hbox);
2421 pref_checkbox_new_int(group, _("Smooth image flip"),
2422 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2423 pref_checkbox_new_int(group, _("Disable screen saver"),
2424 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2427 #define PRE_FORMATTED_COLUMNS 5
2428 static void config_tab_osd(GtkWidget *notebook)
2434 GtkWidget *image_overlay_template_view;
2435 GtkWidget *scrolled;
2436 GtkWidget *scrolled_pre_formatted;
2437 GtkTextBuffer *buffer;
2439 GtkWidget *subgroup;
2441 vbox = scrolled_notebook_page(notebook, _("OSD"));
2443 image_overlay_template_view = gtk_text_view_new();
2445 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2447 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2449 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2450 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2451 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2452 gtk_widget_show(scrolled_pre_formatted);
2453 gtk_widget_show(subgroup);
2455 pref_line(group, PREF_PAD_GAP);
2457 pref_label_new(group, _("Image overlay template"));
2459 scrolled = gtk_scrolled_window_new(NULL, NULL);
2460 gtk_widget_set_size_request(scrolled, 200, 150);
2461 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2462 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2463 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2464 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2465 gtk_widget_show(scrolled);
2467 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2468 _("Extensive formatting options are shown in the Help file"));
2470 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2471 gtk_widget_show(image_overlay_template_view);
2473 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2475 #if GTK_CHECK_VERSION(3,4,0)
2476 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2477 G_CALLBACK(image_overlay_set_font_cb), notebook);
2479 button = gtk_font_button_new();
2480 gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
2481 gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
2482 g_signal_connect(G_OBJECT(button), "font-set",
2483 G_CALLBACK(image_overlay_set_font_cb),NULL);
2485 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2486 gtk_widget_show(button);
2488 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2489 G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2490 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2491 gtk_widget_show(button);
2493 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2494 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2495 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2496 gtk_widget_show(button);
2497 image_overlay_set_text_colours();
2499 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2500 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2501 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2502 gtk_widget_show(button);
2504 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2505 G_CALLBACK(image_overlay_help_cb), NULL);
2506 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2507 gtk_widget_show(button);
2509 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2510 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2511 g_signal_connect(G_OBJECT(buffer), "changed",
2512 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2514 pref_line(group, PREF_PAD_GAP);
2516 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2517 hbox = gtk_hbox_new(FALSE, 0);
2518 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2519 gtk_widget_show(hbox);
2520 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2521 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2522 gtk_widget_show(label);
2523 pref_spacer(group,TRUE);
2525 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2526 hbox = gtk_hbox_new(FALSE, 0);
2527 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2528 gtk_widget_show(hbox);
2529 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2530 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2531 gtk_widget_show(label);
2532 pref_spacer(group,TRUE);
2534 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2535 hbox = gtk_hbox_new(FALSE, 0);
2536 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2537 gtk_widget_show(hbox);
2538 label = gtk_label_new(_("%path:39%"));
2539 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2540 gtk_widget_show(label);
2541 pref_spacer(group,TRUE);
2543 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2544 hbox = gtk_hbox_new(FALSE, 0);
2545 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2546 gtk_widget_show(hbox);
2547 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%"));
2548 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2549 gtk_widget_show(label);
2550 pref_spacer(group,TRUE);
2552 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2553 hbox = gtk_hbox_new(FALSE, 0);
2554 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2555 gtk_widget_show(hbox);
2556 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2557 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2558 gtk_widget_show(label);
2561 static GtkTreeModel *create_class_model(void)
2563 GtkListStore *model;
2567 /* create list store */
2568 model = gtk_list_store_new(1, G_TYPE_STRING);
2569 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2571 gtk_list_store_append(model, &iter);
2572 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2574 return GTK_TREE_MODEL (model);
2579 static void config_tab_files(GtkWidget *notebook)
2586 GtkWidget *ct_button;
2587 GtkWidget *scrolled;
2588 GtkWidget *filter_view;
2589 GtkCellRenderer *renderer;
2590 GtkTreeSelection *selection;
2591 GtkTreeViewColumn *column;
2593 vbox = scrolled_notebook_page(notebook, _("Files"));
2595 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2597 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2598 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2599 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2600 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2601 pref_checkbox_new_int(group, _("Case sensitive sort"),
2602 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2603 pref_checkbox_new_int(group, _("Natural sort order"),
2604 options->file_sort.natural, &c_options->file_sort.natural);
2605 pref_checkbox_new_int(group, _("Disable file extension checks"),
2606 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2608 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2609 options->file_filter.disable, &c_options->file_filter.disable);
2612 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2614 sidecar_ext_entry = gtk_entry_new();
2615 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2616 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2617 gtk_widget_show(sidecar_ext_entry);
2619 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2621 frame = pref_group_parent(group);
2622 g_signal_connect(G_OBJECT(ct_button), "toggled",
2623 G_CALLBACK(filter_disable_cb), frame);
2624 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2626 scrolled = gtk_scrolled_window_new(NULL, NULL);
2627 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2628 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2629 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2630 gtk_widget_show(scrolled);
2632 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2633 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2634 g_object_unref(filter_store);
2635 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2636 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2638 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2640 column = gtk_tree_view_column_new();
2641 gtk_tree_view_column_set_title(column, _("Filter"));
2642 gtk_tree_view_column_set_resizable(column, TRUE);
2644 renderer = gtk_cell_renderer_toggle_new();
2645 g_signal_connect(G_OBJECT(renderer), "toggled",
2646 G_CALLBACK(filter_store_enable_cb), filter_store);
2647 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2648 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2649 GINT_TO_POINTER(FE_ENABLE), NULL);
2651 renderer = gtk_cell_renderer_text_new();
2652 g_signal_connect(G_OBJECT(renderer), "edited",
2653 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2654 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2655 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2656 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2657 GINT_TO_POINTER(FE_EXTENSION), NULL);
2658 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2660 column = gtk_tree_view_column_new();
2661 gtk_tree_view_column_set_title(column, _("Description"));
2662 gtk_tree_view_column_set_resizable(column, TRUE);
2663 gtk_tree_view_column_set_fixed_width(column, 200);
2664 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2666 renderer = gtk_cell_renderer_text_new();
2667 g_signal_connect(G_OBJECT(renderer), "edited",
2668 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2669 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2670 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2671 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2672 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2673 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2675 column = gtk_tree_view_column_new();
2676 gtk_tree_view_column_set_title(column, _("Class"));
2677 gtk_tree_view_column_set_resizable(column, TRUE);
2678 renderer = gtk_cell_renderer_combo_new();
2679 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2680 "model", create_class_model(),
2685 g_signal_connect(G_OBJECT(renderer), "edited",
2686 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2687 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2688 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2689 GINT_TO_POINTER(FE_CLASS), NULL);
2690 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2692 column = gtk_tree_view_column_new();
2693 gtk_tree_view_column_set_title(column, _("Writable"));
2694 gtk_tree_view_column_set_resizable(column, FALSE);
2695 renderer = gtk_cell_renderer_toggle_new();
2696 g_signal_connect(G_OBJECT(renderer), "toggled",
2697 G_CALLBACK(filter_store_writable_cb), filter_store);
2698 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2699 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2700 GINT_TO_POINTER(FE_WRITABLE), NULL);
2701 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2703 column = gtk_tree_view_column_new();
2704 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2705 gtk_tree_view_column_set_resizable(column, FALSE);
2706 renderer = gtk_cell_renderer_toggle_new();
2707 g_signal_connect(G_OBJECT(renderer), "toggled",
2708 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2709 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2710 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2711 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2712 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2715 filter_store_populate();
2716 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2717 gtk_widget_show(filter_view);
2719 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2721 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2722 G_CALLBACK(filter_default_cb), filter_view);
2723 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2724 gtk_widget_show(button);
2726 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2727 G_CALLBACK(filter_remove_cb), filter_view);
2728 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2729 gtk_widget_show(button);
2731 button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2732 G_CALLBACK(filter_add_cb), filter_view);
2733 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2734 gtk_widget_show(button);
2738 static void config_tab_metadata(GtkWidget *notebook)
2743 GtkWidget *ct_button;
2747 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2750 group = pref_group_new(vbox, FALSE, _("Metadata writing process"), GTK_ORIENTATION_VERTICAL);
2752 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2754 label = pref_label_new(group, _("Metadata are written in the following order. The process ends after first success."));
2755 #if GTK_CHECK_VERSION(3,16,0)
2756 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2757 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2759 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2762 ct_button = pref_checkbox_new_int(group, _("1) Save metadata in image files, or sidecar files, according to the XMP standard"),
2763 options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2765 gtk_widget_set_sensitive(ct_button, FALSE);
2768 pref_checkbox_new_int(group, _("2) Save metadata in '.metadata' folder, local to image folder (non-standard)"),
2769 options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2771 text = g_strdup_printf(_("3) Save metadata in Geeqie private directory '%s'"), get_metadata_cache_dir());
2772 label = pref_label_new(group, text);
2773 #if GTK_CHECK_VERSION(3,16,0)
2774 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2775 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2777 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2779 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2782 group = pref_group_new(vbox, FALSE, _("Step 1: Write to image files"), GTK_ORIENTATION_VERTICAL);
2784 gtk_widget_set_sensitive(group, FALSE);
2787 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2788 pref_checkbox_link_sensitivity(ct_button, hbox);
2790 pref_checkbox_new_int(hbox, _("Store metadata also in legacy IPTC tags (converted according to IPTC4XMP standard)"),
2791 options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2793 pref_checkbox_new_int(hbox, _("Warn if the image files are unwritable"),
2794 options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2796 pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
2797 options->metadata.confirm_write, &c_options->metadata.confirm_write);
2799 pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
2800 options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2802 group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
2804 gtk_widget_set_sensitive(group, FALSE);
2807 pref_checkbox_new_int(group, _("Use GQview legacy metadata format (supports only keywords and comments) instead of XMP"),
2808 options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2811 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2812 pref_checkbox_new_int(group, _("Write the same description tags (keywords, comment, etc.) to all grouped sidecars"),
2813 options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2815 pref_checkbox_new_int(group, _("Allow keywords to differ only in case"),
2816 options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2818 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"),
2819 options->metadata.write_orientation, &c_options->metadata.write_orientation);
2821 gtk_widget_set_sensitive(ct_button, FALSE);
2824 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2826 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"),
2827 options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2829 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2830 pref_checkbox_link_sensitivity(ct_button, hbox);
2832 pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1,
2833 options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2835 pref_checkbox_new_int(group, _("Write metadata on image change"),
2836 options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2838 pref_checkbox_new_int(group, _("Write metadata on directory change"),
2839 options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2841 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2843 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"),
2844 options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2845 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");
2850 typedef struct _KeywordFindData KeywordFindData;
2851 struct _KeywordFindData
2858 GtkWidget *button_close;
2859 GtkWidget *button_stop;
2860 GtkWidget *button_start;
2861 GtkWidget *progress;
2869 guint idle_id; /* event source id */
2872 #define KEYWORD_DIALOG_WIDTH 400
2874 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
2876 GList *list_d = NULL;
2877 GList *list_f = NULL;
2881 filelist_read(dir_fd, &list_f, &list_d);
2885 filelist_read(dir_fd, &list_f, NULL);
2888 list_f = filelist_filter(list_f, FALSE);
2889 list_d = filelist_filter(list_d, TRUE);
2891 kfd->list = g_list_concat(list_f, kfd->list);
2892 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
2895 static void keywords_find_reset(KeywordFindData *kfd)
2897 filelist_free(kfd->list);
2900 filelist_free(kfd->list_dir);
2901 kfd->list_dir = NULL;
2904 static void keywords_find_close_cb(GenericDialog *fd, gpointer data)
2906 KeywordFindData *kfd = data;
2908 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
2910 keywords_find_reset(kfd);
2911 generic_dialog_close(kfd->gd);
2915 static void keywords_find_finish(KeywordFindData *kfd)
2917 keywords_find_reset(kfd);
2919 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
2920 spinner_set_interval(kfd->spinner, -1);
2922 gtk_widget_set_sensitive(kfd->group, TRUE);
2923 gtk_widget_set_sensitive(kfd->button_start, TRUE);
2924 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2925 gtk_widget_set_sensitive(kfd->button_close, TRUE);
2928 static void keywords_find_stop_cb(GenericDialog *fd, gpointer data)
2930 KeywordFindData *kfd = data;
2932 g_idle_remove_by_data(kfd);
2934 keywords_find_finish(kfd);
2937 static gboolean keywords_find_file(gpointer data)
2939 KeywordFindData *kfd = data;
2941 GtkTextBuffer *buffer;
2949 fd = kfd->list->data;
2950 kfd->list = g_list_remove(kfd->list, fd);
2952 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
2953 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2957 gtk_text_buffer_get_end_iter(buffer, &iter);
2958 tmp = g_strconcat(keywords->data, "\n", NULL);
2959 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
2961 keywords = keywords->next;
2964 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
2965 file_data_unref(fd);
2966 string_list_free(keywords);
2970 else if (kfd->list_dir)
2974 fd = kfd->list_dir->data;
2975 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
2977 keywords_find_folder(kfd, fd);
2979 file_data_unref(fd);
2984 keywords_find_finish(kfd);
2989 static void keywords_find_start_cb(GenericDialog *fd, gpointer data)
2991 KeywordFindData *kfd = data;
2994 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
2996 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
2997 parse_out_relatives(path);
3001 warning_dialog(_("Invalid folder"),
3002 _("The specified folder can not be found."),
3003 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
3009 gtk_widget_set_sensitive(kfd->group, FALSE);
3010 gtk_widget_set_sensitive(kfd->button_start, FALSE);
3011 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
3012 gtk_widget_set_sensitive(kfd->button_close, FALSE);
3013 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
3015 dir_fd = file_data_new_dir(path);
3016 keywords_find_folder(kfd, dir_fd);
3017 file_data_unref(dir_fd);
3018 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
3024 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
3026 KeywordFindData *kfd;
3030 kfd = g_new0(KeywordFindData, 1);
3032 kfd->gd = generic_dialog_new(_("Search for keywords"),
3033 "search_for_keywords",
3036 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
3037 kfd->gd->cancel_cb = keywords_find_close_cb;
3038 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
3039 keywords_find_close_cb, FALSE);
3040 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
3041 keywords_find_start_cb, FALSE);
3042 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
3043 keywords_find_stop_cb, FALSE);
3044 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3046 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
3048 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
3049 pref_spacer(hbox, PREF_PAD_INDENT);
3050 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
3052 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3053 pref_label_new(hbox, _("Folder:"));
3055 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
3056 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
3057 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
3058 gtk_widget_show(label);
3060 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
3062 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
3063 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3065 kfd->progress = gtk_entry_new();
3066 gtk_widget_set_can_focus(kfd->progress, FALSE);
3067 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
3068 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
3069 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
3070 gtk_widget_show(kfd->progress);
3072 kfd->spinner = spinner_new(NULL, -1);
3073 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
3074 gtk_widget_show(kfd->spinner);
3078 gtk_widget_show(kfd->gd->dialog);
3081 static void keywords_find_cb(GtkWidget *widget, gpointer data)
3083 const gchar *path = layout_get_path(NULL);
3085 if (!path || !*path) path = homedir();
3086 keywords_find_dialog(widget, path);
3089 static void config_tab_keywords_save()
3091 GtkTextIter start, end;
3092 GtkTextBuffer *buffer;
3093 GList *kw_list = NULL;
3099 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3100 gtk_text_buffer_get_bounds(buffer, &start, &end);
3102 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3104 kw_split = strtok(buffer_text, "\n");
3105 while (kw_split != NULL)
3111 if (g_strcmp0(work->data, kw_split) == 0)
3120 kw_list = g_list_append(kw_list, g_strdup(kw_split));
3122 kw_split = strtok(NULL, "\n");
3125 keyword_list_set(kw_list);
3127 string_list_free(kw_list);
3128 g_free(buffer_text);
3131 static void config_tab_keywords(GtkWidget *notebook)
3137 GtkWidget *scrolled;
3139 GtkTextBuffer *buffer;
3142 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3144 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3146 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3148 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
3149 G_CALLBACK(keywords_find_cb), keyword_text);
3150 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
3153 keyword_text = gtk_text_view_new();
3154 gtk_widget_set_size_request(keyword_text, 20, 20);
3155 scrolled = gtk_scrolled_window_new(NULL, NULL);
3156 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3157 gtk_widget_show(scrolled);
3159 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
3160 gtk_widget_show(keyword_text);
3162 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3164 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3165 gtk_text_buffer_create_tag(buffer, "monospace",
3166 "family", "monospace", NULL);
3168 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3169 gtk_text_buffer_get_start_iter(buffer, &iter);
3170 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3173 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3175 GList *kwl = keyword_list_get();
3176 kwl = g_list_first(kwl);
3179 gtk_text_buffer_get_end_iter (buffer, &iter);
3180 tmp = g_strconcat(kwl->data, "\n", NULL);
3181 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3186 gtk_text_buffer_set_modified(buffer, FALSE);
3193 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3195 gint *option = data;
3197 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3201 *option = INTENT_PERCEPTUAL;
3204 *option = INTENT_RELATIVE_COLORIMETRIC;
3207 *option = INTENT_SATURATION;
3210 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3215 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3216 gint option, gint *option_c)
3223 pref_table_label(table, column, row, text, 0.0);
3225 combo = gtk_combo_box_text_new();
3227 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3228 if (option == INTENT_PERCEPTUAL) current = 0;
3229 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3230 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3231 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3232 if (option == INTENT_SATURATION) current = 2;
3233 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3234 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3236 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3238 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3240 g_signal_connect(G_OBJECT(combo), "changed",
3241 G_CALLBACK(intent_menu_cb), option_c);
3243 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
3244 gtk_widget_show(combo);
3248 static void config_tab_color(GtkWidget *notebook)
3257 vbox = scrolled_notebook_page(notebook, _("Color management"));
3259 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3261 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3264 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3265 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3267 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3268 pref_label_bold(label, TRUE, FALSE);
3270 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3271 pref_label_bold(label, TRUE, FALSE);
3273 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3274 pref_label_bold(label, TRUE, FALSE);
3276 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3281 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3282 pref_table_label(table, 0, i + 1, buf, 1.0);
3285 entry = gtk_entry_new();
3286 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3287 if (options->color_profile.input_name[i])
3289 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3291 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3292 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3293 gtk_widget_show(entry);
3294 color_profile_input_name_entry[i] = entry;
3296 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3297 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3298 gtk_widget_set_size_request(entry, 160, -1);
3299 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3300 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3301 gtk_widget_show(tabcomp);
3302 color_profile_input_file_entry[i] = entry;
3305 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3307 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3309 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3310 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3312 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3314 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3315 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3316 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3317 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3318 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3320 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3322 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3324 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3326 gtk_widget_show(tabcomp);
3329 /* advanced entry tab */
3330 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer data)
3332 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3334 c_options->file_ops.use_system_trash = FALSE;
3335 c_options->file_ops.no_trash = FALSE;
3339 static void use_system_trash_cb(GtkWidget *widget, gpointer data)
3341 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3343 c_options->file_ops.use_system_trash = TRUE;
3344 c_options->file_ops.no_trash = FALSE;
3348 static void use_no_cache_cb(GtkWidget *widget, gpointer data)
3350 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3352 c_options->file_ops.no_trash = TRUE;
3356 static void config_tab_behavior(GtkWidget *notebook)
3363 GtkWidget *ct_button;
3367 GtkWidget *with_rename;
3368 GtkWidget *collections_on_top;
3369 GtkWidget *hide_window_in_fullscreen;
3370 GtkWidget *checkbox;
3373 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3375 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3377 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3378 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3379 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3380 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3381 pref_checkbox_new_int(group, _("Enable Delete key"),
3382 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3384 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3385 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3387 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3388 pref_checkbox_link_sensitivity(ct_button, hbox);
3390 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3391 pref_label_new(hbox, _("Folder:"));
3393 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3394 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3395 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3396 gtk_widget_show(tabcomp);
3398 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3399 pref_checkbox_link_sensitivity(ct_button, hbox);
3401 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3402 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MiB"),
3403 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3404 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3405 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3406 G_CALLBACK(safe_delete_view_cb), NULL);
3407 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3408 gtk_widget_show(button);
3410 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3411 G_CALLBACK(safe_delete_clear_cb), NULL);
3412 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3413 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3414 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3416 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3417 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3419 gtk_widget_show(button);
3421 pref_spacer(group, PREF_PAD_GROUP);
3424 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3426 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3427 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3429 pref_checkbox_new_int(group, _("In place renaming"),
3430 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3432 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3433 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3435 tmp = pref_checkbox_new_int(group, _("Circular selection lists"),
3436 options->circular_selection_lists, &c_options->circular_selection_lists);
3437 gtk_widget_set_tooltip_text(tmp, _("Traverse selection lists in a circular manner"));
3439 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3440 options->marks_save, &c_options->marks_save);
3441 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3443 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3444 options->with_rename, &c_options->with_rename);
3445 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3447 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3448 options->collections_on_top, &c_options->collections_on_top);
3449 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3451 hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3452 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3453 gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice");
3455 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3456 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3458 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3459 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3461 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3462 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3464 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3465 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3467 pref_spacer(group, PREF_PAD_GROUP);
3469 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3471 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3472 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3473 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3474 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3475 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3476 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3477 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3478 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3479 pref_checkbox_new_int(group, _("Play video by left click on image"),
3480 options->image_l_click_video, &c_options->image_l_click_video);
3481 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3482 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3484 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3485 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3486 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3487 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3488 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3490 pref_spacer(group, PREF_PAD_GROUP);
3492 group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3494 checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3495 options->override_disable_gpu, &c_options->override_disable_gpu);
3496 gtk_widget_set_tooltip_text(checkbox, "Contact the developers for usage");
3499 pref_spacer(group, PREF_PAD_GROUP);
3501 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3503 pref_spin_new_int(group, _("Debug level:"), NULL,
3504 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3506 pref_checkbox_new_int(group, _("Timer data"),
3507 options->log_window.timer_data, &c_options->log_window.timer_data);
3509 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3510 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3514 /* accelerators tab */
3515 static void config_tab_accelerators(GtkWidget *notebook)
3521 GtkWidget *scrolled;
3522 GtkWidget *accel_view;
3523 GtkCellRenderer *renderer;
3524 GtkTreeSelection *selection;
3525 GtkTreeViewColumn *column;
3527 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3529 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3531 scrolled = gtk_scrolled_window_new(NULL, NULL);
3532 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3533 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3534 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3535 gtk_widget_show(scrolled);
3537 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3539 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3540 g_object_unref(accel_store);
3541 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3542 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3544 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3546 renderer = gtk_cell_renderer_text_new();
3548 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3553 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3554 gtk_tree_view_column_set_resizable(column, TRUE);
3555 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3558 renderer = gtk_cell_renderer_accel_new();
3559 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3560 G_CALLBACK(accel_store_cleared_cb), accel_store);
3561 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3562 G_CALLBACK(accel_store_edited_cb), accel_store);
3565 g_object_set (renderer,
3567 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3570 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3575 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3576 gtk_tree_view_column_set_resizable(column, TRUE);
3577 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3579 renderer = gtk_cell_renderer_text_new();
3581 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3586 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3587 gtk_tree_view_column_set_resizable(column, TRUE);
3588 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3590 renderer = gtk_cell_renderer_text_new();
3592 column = gtk_tree_view_column_new_with_attributes("Accel",
3597 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3598 gtk_tree_view_column_set_resizable(column, TRUE);
3599 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3601 accel_store_populate();
3602 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3603 gtk_widget_show(accel_view);
3605 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3607 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3608 G_CALLBACK(accel_default_cb), accel_view);
3609 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3610 gtk_widget_show(button);
3612 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3613 G_CALLBACK(accel_reset_cb), accel_view);
3614 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3615 gtk_widget_show(button);
3618 /* toolbar main tab */
3619 static void config_tab_toolbar_main(GtkWidget *notebook)
3622 GtkWidget *toolbardata;
3625 lw = layout_window_list->data;
3627 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3629 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3630 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3631 gtk_widget_show(vbox);
3634 /* toolbar status tab */
3635 static void config_tab_toolbar_status(GtkWidget *notebook)
3638 GtkWidget *toolbardata;
3641 lw = layout_window_list->data;
3643 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3645 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3646 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3647 gtk_widget_show(vbox);
3651 static gint extension_sort_cb(gconstpointer a, gconstpointer b)
3653 return g_strcmp0((gchar *)a, (gchar *)b);
3656 static void config_tab_advanced(GtkWidget *notebook)
3660 GSList *formats_list;
3661 GList *extensions_list = NULL;
3664 GdkPixbufFormat *fm;
3666 GString *types_string = g_string_new(NULL);
3667 GtkWidget *types_string_label;
3668 GtkWidget *threads_string_label;
3669 GtkWidget *dupes_threads_spin;
3671 vbox = scrolled_notebook_page(notebook, _("Advanced"));
3672 group = pref_group_new(vbox, FALSE, _("External preview extraction"), GTK_ORIENTATION_VERTICAL);
3674 pref_checkbox_new_int(group, _("Use external preview extraction - Requires restart"), options->external_preview.enable, &c_options->external_preview.enable);
3676 pref_spacer(group, PREF_PAD_GROUP);
3678 formats_list = gdk_pixbuf_get_formats();
3680 while (formats_list)
3682 fm = formats_list->data;
3683 extensions = gdk_pixbuf_format_get_extensions(fm);
3686 while (extensions[i])
3688 extensions_list = g_list_insert_sorted(extensions_list, g_strdup(extensions[i]), extension_sort_cb);
3692 g_strfreev(extensions);
3693 formats_list = formats_list->next;
3696 while (extensions_list)
3698 if (types_string->len == 0)
3700 types_string = g_string_append(types_string, extensions_list->data);
3704 types_string = g_string_append(types_string, ", ");
3705 types_string = g_string_append(types_string, extensions_list->data);
3708 extensions_list = extensions_list->next;
3711 types_string = g_string_prepend(types_string, _("Usable file types:\n"));
3712 types_string_label = pref_label_new(group, types_string->str);
3713 gtk_label_set_line_wrap(GTK_LABEL(types_string_label), TRUE);
3715 pref_spacer(group, PREF_PAD_GROUP);
3717 group = pref_group_new(vbox, FALSE, _("File identification tool"), GTK_ORIENTATION_VERTICAL);
3718 external_preview_select_entry = gtk_entry_new();
3719 tabcomp = tab_completion_new(&external_preview_select_entry, options->external_preview.select, NULL, NULL, NULL, NULL);
3720 tab_completion_add_select_button(external_preview_select_entry, _("Select file identification tool"), FALSE);
3721 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3722 gtk_widget_show(tabcomp);
3724 group = pref_group_new(vbox, FALSE, _("Preview extraction tool"), GTK_ORIENTATION_VERTICAL);
3725 external_preview_extract_entry = gtk_entry_new();
3726 tabcomp = tab_completion_new(&external_preview_extract_entry, options->external_preview.extract, NULL, NULL, NULL, NULL);
3727 tab_completion_add_select_button(external_preview_extract_entry, _("Select preview extraction tool"), FALSE);
3728 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3729 gtk_widget_show(tabcomp);
3731 gtk_widget_show(vbox);
3733 g_slist_free(formats_list);
3734 string_list_free(extensions_list);
3735 g_string_free(types_string, TRUE);
3737 pref_spacer(group, PREF_PAD_GROUP);
3739 pref_line(vbox, PREF_PAD_SPACE);
3740 group = pref_group_new(vbox, FALSE, _("Thread pool limits"), GTK_ORIENTATION_VERTICAL);
3742 threads_string_label = pref_label_new(group, "This option limits the number of threads (or cpu cores)\nthat Geeqie will use when running duplicate checks. The default value is 0, which means all available cores will be used.");
3743 gtk_label_set_line_wrap(GTK_LABEL(threads_string_label), TRUE);
3745 pref_spacer(vbox, PREF_PAD_GROUP);
3747 dupes_threads_spin = pref_spin_new_int(vbox, _("Duplicate check:"), _("max. threads"), 0, get_cpu_cores(), 1, options->threads.duplicates, &c_options->threads.duplicates);
3748 gtk_widget_set_tooltip_markup(dupes_threads_spin, _("Set to 0 for unlimited"));
3752 static void config_tab_stereo(GtkWidget *notebook)
3760 GtkWidget *fs_button;
3761 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3763 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3765 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3766 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3768 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3769 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3770 pref_checkbox_new_int(box, _("Mirror left image"),
3771 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3772 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3773 pref_checkbox_new_int(box, _("Flip left image"),
3774 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3775 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3776 pref_checkbox_new_int(box, _("Mirror right image"),
3777 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3778 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3779 pref_checkbox_new_int(box, _("Flip right image"),
3780 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3781 pref_checkbox_new_int(group, _("Swap left and right images"),
3782 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3783 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3784 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3786 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3787 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3788 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3789 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3790 pref_checkbox_link_sensitivity(fs_button, box2);
3791 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3792 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3793 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3794 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3795 pref_checkbox_new_int(box, _("Mirror left image"),
3796 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3797 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3798 pref_checkbox_new_int(box, _("Flip left image"),
3799 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3800 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3801 pref_checkbox_new_int(box, _("Mirror right image"),
3802 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3803 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3804 pref_checkbox_new_int(box, _("Flip right image"),
3805 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3806 pref_checkbox_new_int(box2, _("Swap left and right images"),
3807 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3808 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3809 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3811 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3812 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3813 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3814 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3815 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
3816 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3817 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
3818 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3819 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
3820 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3821 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
3822 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3823 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
3824 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3828 /* Main preferences window */
3829 static void config_window_create(LayoutWindow *lw)
3831 GtkWidget *win_vbox;
3833 GtkWidget *notebook;
3835 GtkWidget *ct_button;
3837 if (!c_options) c_options = init_options(NULL);
3839 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3840 DEBUG_NAME(configwindow);
3841 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3842 g_signal_connect(G_OBJECT(configwindow), "delete_event",
3843 G_CALLBACK(config_window_delete), NULL);
3844 if (options->save_dialog_window_positions)
3846 gtk_window_resize(GTK_WINDOW(configwindow), lw->options.preferences_window.w, lw->options.preferences_window.h);
3847 gtk_window_move(GTK_WINDOW(configwindow), lw->options.preferences_window.x, lw->options.preferences_window.y);
3851 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
3853 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
3854 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
3856 win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
3857 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
3858 gtk_widget_show(win_vbox);
3860 notebook = gtk_notebook_new();
3861 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
3862 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
3863 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
3865 config_tab_general(notebook);
3866 config_tab_image(notebook);
3867 config_tab_osd(notebook);
3868 config_tab_windows(notebook);
3869 config_tab_accelerators(notebook);
3870 config_tab_files(notebook);
3871 config_tab_metadata(notebook);
3872 config_tab_keywords(notebook);
3873 config_tab_color(notebook);
3874 config_tab_stereo(notebook);
3875 config_tab_behavior(notebook);
3876 config_tab_toolbar_main(notebook);
3877 config_tab_toolbar_status(notebook);
3878 config_tab_advanced(notebook);
3880 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), lw->options.preferences_window.page_number);
3882 hbox = gtk_hbutton_box_new();
3883 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
3884 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
3885 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
3886 gtk_widget_show(hbox);
3888 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
3889 G_CALLBACK(config_window_help_cb), notebook);
3890 gtk_container_add(GTK_CONTAINER(hbox), button);
3891 gtk_widget_set_can_default(button, TRUE);
3892 gtk_widget_show(button);
3894 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
3895 G_CALLBACK(config_window_ok_cb), notebook);
3896 gtk_container_add(GTK_CONTAINER(hbox), button);
3897 gtk_widget_set_can_default(button, TRUE);
3898 gtk_widget_grab_default(button);
3899 gtk_widget_show(button);
3903 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
3904 G_CALLBACK(config_window_close_cb), NULL);
3905 gtk_container_add(GTK_CONTAINER(hbox), button);
3906 gtk_widget_set_can_default(button, TRUE);
3907 gtk_widget_show(button);
3909 if (!generic_dialog_get_alternative_button_order(configwindow))
3911 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
3914 gtk_widget_show(notebook);
3916 gtk_widget_show(configwindow);
3920 *-----------------------------------------------------------------------------
3921 * config window show (public)
3922 *-----------------------------------------------------------------------------
3925 void show_config_window(LayoutWindow *lw)
3929 gtk_window_present(GTK_WINDOW(configwindow));
3933 config_window_create(lw);
3942 void show_about_window(LayoutWindow *lw)
3944 GdkPixbuf *pixbuf_logo;
3945 GdkPixbuf *pixbuf_icon;
3946 gchar *authors[1000];
3951 gchar *timezone_path;
3955 #define LINE_LENGTH 1000
3956 gchar line[LINE_LENGTH];
3958 copyright = g_string_new(NULL);
3959 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");
3961 path = path_from_utf8(TIMEZONE_DATABASE);
3962 basename = g_path_get_basename(path);
3963 timezone_path = g_build_filename(get_rc_dir(), basename, NULL);
3964 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
3966 cd = ZDOpenDatabase(timezone_path);
3969 copyright = g_string_append(copyright, ZDGetNotice(cd));
3970 ZDCloseDatabase(cd);
3974 g_free(timezone_path);
3978 path = g_build_filename(gq_helpdir, "AUTHORS", NULL);
3979 fp = fopen(path, "r");
3982 while(fgets(line, LINE_LENGTH, fp))
3984 /* get rid of ending \n from fgets */
3985 line[strlen(line) - 1] = '\0';
3986 authors[i_authors] = g_strdup(line);
3989 authors[i_authors] = NULL;
3994 comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
3995 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
3997 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
3998 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
3999 gtk_show_about_dialog(GTK_WINDOW(lw->window),
4000 "title", _("About Geeqie"),
4002 "program-name", GQ_APPNAME,
4004 "logo", pixbuf_logo,
4005 "icon", pixbuf_icon,
4006 "website", GQ_WEBSITE,
4007 "website-label", "Website",
4008 "comments", comment,
4010 "translator-credits", _("translator-credits"),
4011 "wrap-license", TRUE,
4012 "license", copyright->str,
4015 g_string_free(copyright, TRUE);
4018 while(n < i_authors)
4028 static void image_overlay_set_text_colours()
4030 c_options->image_overlay.text_red = options->image_overlay.text_red;
4031 c_options->image_overlay.text_green = options->image_overlay.text_green;
4032 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
4033 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
4034 c_options->image_overlay.background_red = options->image_overlay.background_red;
4035 c_options->image_overlay.background_green = options->image_overlay.background_green;
4036 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
4037 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
4041 *-----------------------------------------------------------------------------
4042 * timezone database routines
4043 *-----------------------------------------------------------------------------
4046 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
4048 GError *error = NULL;
4050 gchar *tmp_filename;
4052 if (!g_cancellable_is_cancelled(tz->cancellable))
4054 generic_dialog_close(tz->gd);
4058 if (g_file_copy_finish(G_FILE(source_object), res, &error))
4060 tmp_filename = g_file_get_parse_name(tz->tmp_g_file);
4061 move_file(tmp_filename, tz->timezone_database_user);
4062 g_free(tmp_filename);
4066 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4069 g_file_delete(tz->tmp_g_file, NULL, &error);
4070 g_object_unref(tz->tmp_g_file);
4071 tz->tmp_g_file = NULL;
4072 g_object_unref(tz->cancellable);
4073 g_object_unref(tz->timezone_database_gq);
4076 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
4080 if (!g_cancellable_is_cancelled(tz->cancellable))
4082 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
4086 static void timezone_cancel_button_cb(GenericDialog *gd, gpointer data)
4090 g_cancellable_cancel(tz->cancellable);
4093 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
4096 GError *error = NULL;
4097 GFileIOStream *io_stream;
4104 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
4108 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4109 log_printf("Error: Download timezone database failed:\n%s", error->message);
4110 g_error_free(error);
4111 g_object_unref(tz->tmp_g_file);
4115 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE);
4117 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
4119 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
4121 tz->progress = gtk_progress_bar_new();
4122 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
4123 gtk_widget_show(tz->progress);
4125 gtk_widget_show(tz->gd->dialog);
4126 tz->cancellable = g_cancellable_new();
4127 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);
4129 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
4132 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */