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[] = {
126 /* config memory values */
127 static ConfOptions *c_options = NULL;
134 static GtkWidget *configwindow = NULL;
135 static GtkListStore *filter_store = NULL;
136 static GtkTreeStore *accel_store = NULL;
138 static GtkWidget *safe_delete_path_entry;
140 static GtkWidget *color_profile_input_file_entry[COLOR_PROFILE_INPUTS];
141 static GtkWidget *color_profile_input_name_entry[COLOR_PROFILE_INPUTS];
142 static GtkWidget *color_profile_screen_file_entry;
143 static GtkWidget *external_preview_select_entry;
144 static GtkWidget *external_preview_extract_entry;
146 static GtkWidget *sidecar_ext_entry;
147 static GtkWidget *help_search_engine_entry;
150 #define CONFIG_WINDOW_DEF_WIDTH 700
151 #define CONFIG_WINDOW_DEF_HEIGHT 600
154 *-----------------------------------------------------------------------------
155 * option widget callbacks (private)
156 *-----------------------------------------------------------------------------
159 static void zoom_increment_cb(GtkWidget *spin, gpointer data)
161 c_options->image.zoom_increment = (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) * 100.0 + 0.01);
164 static void slideshow_delay_hours_cb(GtkWidget *spin, gpointer data)
166 gint mins_secs_tenths, delay;
168 mins_secs_tenths = c_options->slideshow.delay %
169 (3600 * SLIDESHOW_SUBSECOND_PRECISION);
171 delay = (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
172 (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
175 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
176 SLIDESHOW_SUBSECOND_PRECISION;
179 static void slideshow_delay_minutes_cb(GtkWidget *spin, gpointer data)
181 gint hours, secs_tenths, delay;
183 hours = c_options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
184 secs_tenths = c_options->slideshow.delay % (60 * SLIDESHOW_SUBSECOND_PRECISION);
186 delay = hours * (3600 * SLIDESHOW_SUBSECOND_PRECISION) +
187 (gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
188 (60 * SLIDESHOW_SUBSECOND_PRECISION) + secs_tenths);
190 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
191 SLIDESHOW_SUBSECOND_PRECISION;
194 static void slideshow_delay_seconds_cb(GtkWidget *spin, gpointer data)
196 gint hours_mins, delay;
198 hours_mins = c_options->slideshow.delay / (60 * SLIDESHOW_SUBSECOND_PRECISION);
200 delay = (hours_mins * (60 * SLIDESHOW_SUBSECOND_PRECISION)) +
201 (gint)(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)) *
202 (gdouble)(SLIDESHOW_SUBSECOND_PRECISION) + 0.01);
204 c_options->slideshow.delay = delay > 0 ? delay : SLIDESHOW_MIN_SECONDS *
205 SLIDESHOW_SUBSECOND_PRECISION;
209 *-----------------------------------------------------------------------------
210 * sync program to config window routine (private)
211 *-----------------------------------------------------------------------------
214 void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*func)(const gchar *))
220 buf = gtk_entry_get_text(GTK_ENTRY(entry));
221 if (buf && strlen(buf) > 0)
226 *option = g_strdup(buf);
231 static gboolean accel_apply_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
233 gchar *accel_path, *accel;
235 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, AE_KEY, &accel, -1);
237 if (accel_path && accel_path[0])
240 gtk_accelerator_parse(accel, &key.accel_key, &key.accel_mods);
241 gtk_accel_map_change_entry(accel_path, key.accel_key, key.accel_mods, TRUE);
251 static void config_window_apply(void)
253 gboolean refresh = FALSE;
258 config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash);
260 if (options->file_filter.show_hidden_files != c_options->file_filter.show_hidden_files) refresh = TRUE;
261 if (options->file_filter.show_parent_directory != c_options->file_filter.show_parent_directory) refresh = TRUE;
262 if (options->file_filter.show_dot_directory != c_options->file_filter.show_dot_directory) refresh = TRUE;
263 if (options->file_sort.case_sensitive != c_options->file_sort.case_sensitive) refresh = TRUE;
264 if (options->file_sort.natural != c_options->file_sort.natural) refresh = TRUE;
265 if (options->file_filter.disable_file_extension_checks != c_options->file_filter.disable_file_extension_checks) refresh = TRUE;
266 if (options->file_filter.disable != c_options->file_filter.disable) refresh = TRUE;
268 options->file_ops.confirm_delete = c_options->file_ops.confirm_delete;
269 options->file_ops.enable_delete_key = c_options->file_ops.enable_delete_key;
270 options->file_ops.confirm_move_to_trash = c_options->file_ops.confirm_move_to_trash;
271 options->file_ops.use_system_trash = c_options->file_ops.use_system_trash;
272 options->file_ops.no_trash = c_options->file_ops.no_trash;
273 options->file_ops.safe_delete_folder_maxsize = c_options->file_ops.safe_delete_folder_maxsize;
274 options->tools_restore_state = c_options->tools_restore_state;
275 options->save_window_positions = c_options->save_window_positions;
276 options->use_saved_window_positions_for_new_windows = c_options->use_saved_window_positions_for_new_windows;
277 options->save_window_workspace = c_options->save_window_workspace;
278 options->save_dialog_window_positions = c_options->save_dialog_window_positions;
279 options->show_window_ids = c_options->show_window_ids;
280 options->image.scroll_reset_method = c_options->image.scroll_reset_method;
281 options->image.zoom_2pass = c_options->image.zoom_2pass;
282 options->image.fit_window_to_image = c_options->image.fit_window_to_image;
283 options->image.limit_window_size = c_options->image.limit_window_size;
284 options->image.zoom_to_fit_allow_expand = c_options->image.zoom_to_fit_allow_expand;
285 options->image.max_window_size = c_options->image.max_window_size;
286 options->image.limit_autofit_size = c_options->image.limit_autofit_size;
287 options->image.max_autofit_size = c_options->image.max_autofit_size;
288 options->image.max_enlargement_size = c_options->image.max_enlargement_size;
289 options->image.use_clutter_renderer = c_options->image.use_clutter_renderer;
290 options->image.tile_size = c_options->image.tile_size;
291 options->progressive_key_scrolling = c_options->progressive_key_scrolling;
292 options->keyboard_scroll_step = c_options->keyboard_scroll_step;
294 if (options->thumbnails.max_width != c_options->thumbnails.max_width
295 || options->thumbnails.max_height != c_options->thumbnails.max_height
296 || options->thumbnails.quality != c_options->thumbnails.quality)
298 thumb_format_changed = TRUE;
300 options->thumbnails.max_width = c_options->thumbnails.max_width;
301 options->thumbnails.max_height = c_options->thumbnails.max_height;
302 options->thumbnails.quality = c_options->thumbnails.quality;
304 options->thumbnails.enable_caching = c_options->thumbnails.enable_caching;
305 options->thumbnails.cache_into_dirs = c_options->thumbnails.cache_into_dirs;
306 options->thumbnails.use_exif = c_options->thumbnails.use_exif;
307 options->thumbnails.use_color_management = c_options->thumbnails.use_color_management;
308 options->thumbnails.collection_preview = c_options->thumbnails.collection_preview;
309 options->thumbnails.use_ft_metadata = c_options->thumbnails.use_ft_metadata;
310 // options->thumbnails.use_ft_metadata_small = c_options->thumbnails.use_ft_metadata_small;
311 options->thumbnails.spec_standard = c_options->thumbnails.spec_standard;
312 options->metadata.enable_metadata_dirs = c_options->metadata.enable_metadata_dirs;
313 options->file_filter.show_hidden_files = c_options->file_filter.show_hidden_files;
314 options->file_filter.show_parent_directory = c_options->file_filter.show_parent_directory;
315 options->file_filter.show_dot_directory = c_options->file_filter.show_dot_directory;
316 options->file_filter.disable_file_extension_checks = c_options->file_filter.disable_file_extension_checks;
318 options->file_sort.case_sensitive = c_options->file_sort.case_sensitive;
319 options->file_sort.natural = c_options->file_sort.natural;
320 options->file_filter.disable = c_options->file_filter.disable;
322 config_entry_to_option(sidecar_ext_entry, &options->sidecar.ext, NULL);
323 sidecar_ext_parse(options->sidecar.ext);
325 options->slideshow.random = c_options->slideshow.random;
326 options->slideshow.repeat = c_options->slideshow.repeat;
327 options->slideshow.delay = c_options->slideshow.delay;
329 options->mousewheel_scrolls = c_options->mousewheel_scrolls;
330 options->image_lm_click_nav = c_options->image_lm_click_nav;
331 options->image_l_click_video = c_options->image_l_click_video;
332 options->image_l_click_video_editor = c_options->image_l_click_video_editor;
334 options->file_ops.enable_in_place_rename = c_options->file_ops.enable_in_place_rename;
336 options->image.tile_cache_max = c_options->image.tile_cache_max;
337 options->image.image_cache_max = c_options->image.image_cache_max;
339 options->image.zoom_quality = c_options->image.zoom_quality;
341 options->image.zoom_increment = c_options->image.zoom_increment;
343 options->image.enable_read_ahead = c_options->image.enable_read_ahead;
346 if (options->image.use_custom_border_color != c_options->image.use_custom_border_color
347 || options->image.use_custom_border_color_in_fullscreen != c_options->image.use_custom_border_color_in_fullscreen
348 || !gdk_color_equal(&options->image.border_color, &c_options->image.border_color))
350 options->image.use_custom_border_color_in_fullscreen = c_options->image.use_custom_border_color_in_fullscreen;
351 options->image.use_custom_border_color = c_options->image.use_custom_border_color;
352 options->image.border_color = c_options->image.border_color;
353 layout_colors_update();
354 view_window_colors_update();
357 options->image.alpha_color_1 = c_options->image.alpha_color_1;
358 options->image.alpha_color_2 = c_options->image.alpha_color_2;
360 options->fullscreen.screen = c_options->fullscreen.screen;
361 options->fullscreen.clean_flip = c_options->fullscreen.clean_flip;
362 options->fullscreen.disable_saver = c_options->fullscreen.disable_saver;
363 options->fullscreen.above = c_options->fullscreen.above;
364 if (c_options->image_overlay.template_string)
365 set_image_overlay_template_string(&options->image_overlay.template_string,
366 c_options->image_overlay.template_string);
367 if (c_options->image_overlay.font)
368 set_image_overlay_font_string(&options->image_overlay.font,
369 c_options->image_overlay.font);
370 options->image_overlay.text_red = c_options->image_overlay.text_red;
371 options->image_overlay.text_green = c_options->image_overlay.text_green;
372 options->image_overlay.text_blue = c_options->image_overlay.text_blue;
373 options->image_overlay.text_alpha = c_options->image_overlay.text_alpha;
374 options->image_overlay.background_red = c_options->image_overlay.background_red;
375 options->image_overlay.background_green = c_options->image_overlay.background_green;
376 options->image_overlay.background_blue = c_options->image_overlay.background_blue;
377 options->image_overlay.background_alpha = c_options->image_overlay.background_alpha;
378 options->update_on_time_change = c_options->update_on_time_change;
379 options->image.exif_proof_rotate_enable = c_options->image.exif_proof_rotate_enable;
381 options->duplicates_similarity_threshold = c_options->duplicates_similarity_threshold;
382 options->rot_invariant_sim = c_options->rot_invariant_sim;
384 options->tree_descend_subdirs = c_options->tree_descend_subdirs;
386 options->view_dir_list_single_click_enter = c_options->view_dir_list_single_click_enter;
387 options->circular_selection_lists = c_options->circular_selection_lists;
389 options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
390 options->dnd_icon_size = c_options->dnd_icon_size;
391 options->clipboard_selection = c_options->clipboard_selection;
392 options->dnd_default_action = c_options->dnd_default_action;
394 options->metadata.save_in_image_file = c_options->metadata.save_in_image_file;
395 options->metadata.save_legacy_IPTC = c_options->metadata.save_legacy_IPTC;
396 options->metadata.warn_on_write_problems = c_options->metadata.warn_on_write_problems;
397 options->metadata.save_legacy_format = c_options->metadata.save_legacy_format;
398 options->metadata.sync_grouped_files = c_options->metadata.sync_grouped_files;
399 options->metadata.confirm_write = c_options->metadata.confirm_write;
400 options->metadata.sidecar_extended_name = c_options->metadata.sidecar_extended_name;
401 options->metadata.confirm_timeout = c_options->metadata.confirm_timeout;
402 options->metadata.confirm_after_timeout = c_options->metadata.confirm_after_timeout;
403 options->metadata.confirm_on_image_change = c_options->metadata.confirm_on_image_change;
404 options->metadata.confirm_on_dir_change = c_options->metadata.confirm_on_dir_change;
405 options->metadata.keywords_case_sensitive = c_options->metadata.keywords_case_sensitive;
406 options->metadata.write_orientation = c_options->metadata.write_orientation;
407 options->stereo.mode = (c_options->stereo.mode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
408 (c_options->stereo.tmp.mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
409 (c_options->stereo.tmp.flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
410 (c_options->stereo.tmp.mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
411 (c_options->stereo.tmp.flip_left ? PR_STEREO_FLIP_LEFT : 0) |
412 (c_options->stereo.tmp.swap ? PR_STEREO_SWAP : 0) |
413 (c_options->stereo.tmp.temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
414 options->stereo.fsmode = (c_options->stereo.fsmode & (PR_STEREO_HORIZ | PR_STEREO_VERT | PR_STEREO_FIXED | PR_STEREO_ANAGLYPH | PR_STEREO_HALF)) |
415 (c_options->stereo.tmp.fs_mirror_right ? PR_STEREO_MIRROR_RIGHT : 0) |
416 (c_options->stereo.tmp.fs_flip_right ? PR_STEREO_FLIP_RIGHT : 0) |
417 (c_options->stereo.tmp.fs_mirror_left ? PR_STEREO_MIRROR_LEFT : 0) |
418 (c_options->stereo.tmp.fs_flip_left ? PR_STEREO_FLIP_LEFT : 0) |
419 (c_options->stereo.tmp.fs_swap ? PR_STEREO_SWAP : 0) |
420 (c_options->stereo.tmp.fs_temp_disable ? PR_STEREO_TEMP_DISABLE : 0);
421 options->stereo.enable_fsmode = c_options->stereo.enable_fsmode;
422 options->stereo.fixed_w = c_options->stereo.fixed_w;
423 options->stereo.fixed_h = c_options->stereo.fixed_h;
424 options->stereo.fixed_x1 = c_options->stereo.fixed_x1;
425 options->stereo.fixed_y1 = c_options->stereo.fixed_y1;
426 options->stereo.fixed_x2 = c_options->stereo.fixed_x2;
427 options->stereo.fixed_y2 = c_options->stereo.fixed_y2;
429 options->info_keywords.height = c_options->info_keywords.height;
430 options->info_title.height = c_options->info_title.height;
431 options->info_comment.height = c_options->info_comment.height;
432 options->info_rating.height = c_options->info_rating.height;
434 options->show_predefined_keyword_tree = c_options->show_predefined_keyword_tree;
435 options->expand_menu_toolbar = c_options->expand_menu_toolbar;
437 options->marks_save = c_options->marks_save;
438 options->with_rename = c_options->with_rename;
439 options->collections_on_top = c_options->collections_on_top;
440 options->hide_window_in_fullscreen = c_options->hide_window_in_fullscreen;
441 config_entry_to_option(help_search_engine_entry, &options->help_search_engine, NULL);
443 options->external_preview.enable = c_options->external_preview.enable;
444 config_entry_to_option(external_preview_select_entry, &options->external_preview.select, NULL);
445 config_entry_to_option(external_preview_extract_entry, &options->external_preview.extract, NULL);
447 options->read_metadata_in_idle = c_options->read_metadata_in_idle;
449 options->star_rating.star = c_options->star_rating.star;
450 options->star_rating.rejected = c_options->star_rating.rejected;
452 options->threads.duplicates = c_options->threads.duplicates > 0 ? c_options->threads.duplicates : -1;
455 set_debug_level(debug_c);
459 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
461 config_entry_to_option(color_profile_input_name_entry[i], &options->color_profile.input_name[i], NULL);
462 config_entry_to_option(color_profile_input_file_entry[i], &options->color_profile.input_file[i], NULL);
464 config_entry_to_option(color_profile_screen_file_entry, &options->color_profile.screen_file, NULL);
465 options->color_profile.use_x11_screen_profile = c_options->color_profile.use_x11_screen_profile;
466 if (options->color_profile.render_intent != c_options->color_profile.render_intent)
468 options->color_profile.render_intent = c_options->color_profile.render_intent;
473 options->mouse_button_8 = c_options->mouse_button_8;
474 options->mouse_button_9 = c_options->mouse_button_9;
476 options->override_disable_gpu = c_options->override_disable_gpu;
478 config_tab_keywords_save();
480 image_options_sync();
485 layout_refresh(NULL);
488 if (accel_store) gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_apply_cb, NULL);
490 toolbar_apply(TOOLBAR_MAIN);
491 toolbar_apply(TOOLBAR_STATUS);
495 *-----------------------------------------------------------------------------
496 * config window main button callbacks (private)
497 *-----------------------------------------------------------------------------
500 static void config_window_close_cb(GtkWidget *widget, gpointer data)
502 gtk_widget_destroy(configwindow);
507 static void config_window_help_cb(GtkWidget *widget, gpointer data)
509 GtkWidget *notebook = data;
512 static gchar *html_section[] =
514 "GuideOptionsGeneral.html",
515 "GuideOptionsImage.html",
516 "GuideOptionsOSD.html",
517 "GuideOptionsWindow.html",
518 "GuideOptionsKeyboard.html",
519 "GuideOptionsFiltering.html",
520 "GuideOptionsMetadata.html",
521 "GuideOptionsKeywords.html",
522 "GuideOptionsColor.html",
523 "GuideOptionsStereo.html",
524 "GuideOptionsBehavior.html",
525 "GuideOptionsToolbar.html",
526 "GuideOptionsToolbar.html",
527 "GuideOptionsAdvanced.html"
530 i = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
531 help_window_show(html_section[i]);
534 static gboolean config_window_delete(GtkWidget *widget, GdkEventAny *event, gpointer data)
536 config_window_close_cb(NULL, NULL);
540 static void config_window_ok_cb(GtkWidget *widget, gpointer data)
543 GtkNotebook *notebook = data;
551 lw = layout_window_list->data;
553 window = gtk_widget_get_window(widget);
554 gdk_window_get_root_origin(window, &x, &y);
555 w = gdk_window_get_width(window);
556 h = gdk_window_get_height(window);
557 page_number = gtk_notebook_get_current_page(notebook);
559 lw->options.preferences_window.x = x;
560 lw->options.preferences_window.y = y;
561 lw->options.preferences_window.w = w;
562 lw->options.preferences_window.h = h;
563 lw->options.preferences_window.page_number = page_number;
565 config_window_apply();
566 layout_util_sync(lw);
567 save_options(options);
568 config_window_close_cb(NULL, NULL);
572 *-----------------------------------------------------------------------------
573 * config window setup (private)
574 *-----------------------------------------------------------------------------
577 static void quality_menu_cb(GtkWidget *combo, gpointer data)
581 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
585 *option = GDK_INTERP_NEAREST;
588 *option = GDK_INTERP_TILES;
591 *option = GDK_INTERP_BILINEAR;
596 static void dnd_default_action_selection_menu_cb(GtkWidget *combo, gpointer data)
600 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
604 *option = DND_ACTION_ASK;
607 *option = DND_ACTION_COPY;
610 *option = DND_ACTION_MOVE;
614 static void clipboard_selection_menu_cb(GtkWidget *combo, gpointer data)
618 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
621 *option = CLIPBOARD_PRIMARY;
624 *option = CLIPBOARD_CLIPBOARD;
627 *option = CLIPBOARD_BOTH;
630 *option = CLIPBOARD_BOTH;
634 static void add_quality_menu(GtkWidget *table, gint column, gint row, const gchar *text,
635 guint option, guint *option_c)
642 pref_table_label(table, column, row, text, 0.0);
644 combo = gtk_combo_box_text_new();
646 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Nearest (worst, but fastest)"));
647 if (option == GDK_INTERP_NEAREST) current = 0;
648 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Tiles"));
649 if (option == GDK_INTERP_TILES) current = 1;
650 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Bilinear (best, but slowest)"));
651 if (option == GDK_INTERP_BILINEAR) current = 2;
653 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
655 g_signal_connect(G_OBJECT(combo), "changed",
656 G_CALLBACK(quality_menu_cb), option_c);
658 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
659 gtk_widget_show(combo);
662 static void add_dnd_default_action_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text, DnDAction option, DnDAction *option_c)
669 pref_table_label(table, column, row, text, 0.0);
671 combo = gtk_combo_box_text_new();
673 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Ask"));
674 if (option == DND_ACTION_ASK) current = 0;
675 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Copy"));
676 if (option == DND_ACTION_COPY) current = 1;
677 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Move"));
678 if (option == DND_ACTION_MOVE) current = 2;
680 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
682 g_signal_connect(G_OBJECT(combo), "changed",
683 G_CALLBACK(dnd_default_action_selection_menu_cb), option_c);
685 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
686 gtk_widget_show(combo);
689 static void add_clipboard_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
690 gint option, gint *option_c)
697 pref_table_label(table, column, row, text, 0.0);
699 combo = gtk_combo_box_text_new();
701 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Primary"));
702 if (option == CLIPBOARD_PRIMARY) current = 0;
703 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Clipboard"));
704 if (option == CLIPBOARD_CLIPBOARD) current = 1;
705 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Both"));
706 if (option == CLIPBOARD_BOTH) current = 2;
708 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
710 g_signal_connect(G_OBJECT(combo), "changed",
711 G_CALLBACK(clipboard_selection_menu_cb), option_c);
713 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
714 gtk_widget_show(combo);
717 typedef struct _UseableMouseItems UseableMouseItems;
718 struct _UseableMouseItems
720 gchar *name; /* GtkActionEntry terminology */
725 static const UseableMouseItems useable_mouse_items[] = {
727 {"FirstImage", N_("First Image"), GTK_STOCK_GOTO_TOP},
728 {"PrevImage", N_("Previous Image"), GTK_STOCK_GO_UP},
729 {"NextImage", N_("Next Image"), GTK_STOCK_GO_DOWN},
730 {"LastImage", N_("Last Image"), GTK_STOCK_GOTO_BOTTOM},
731 {"Back", N_("Back"), GTK_STOCK_GO_BACK},
732 {"Forward", N_("Forward"), GTK_STOCK_GO_FORWARD},
733 {"Home", N_("Home"), GTK_STOCK_HOME},
734 {"Up", N_("Up"), GTK_STOCK_GO_UP},
735 {"FirstPage", N_("First page"), GTK_STOCK_MEDIA_PREVIOUS},
736 {"LastPage", N_("Last Page"), GTK_STOCK_MEDIA_NEXT},
737 {"NextPage", N_("Next page"), GTK_STOCK_MEDIA_FORWARD},
738 {"PrevPage", N_("Previous Page"), GTK_STOCK_MEDIA_REWIND},
739 {"NewWindow", N_("New _window"), GTK_STOCK_NEW},
740 {"NewCollection", N_("New collection"), GTK_STOCK_INDEX},
741 {"OpenCollection", N_("Open collection"), GTK_STOCK_OPEN},
742 {"Search", N_("Search"), GTK_STOCK_FIND},
743 {"FindDupes", N_("Find duplicates"), GTK_STOCK_FIND},
744 {"NewFolder", N_("New folder"),GTK_STOCK_DIRECTORY},
745 {"Copy", N_("Copy"), GTK_STOCK_COPY},
746 {"Move", N_("Move"), PIXBUF_INLINE_ICON_MOVE},
747 {"Rename", N_("Rename"), PIXBUF_INLINE_ICON_RENAME},
748 {"Delete", N_("Delete"), GTK_STOCK_DELETE},
749 {"CloseWindow", N_("Close Window"), GTK_STOCK_CLOSE},
750 {"PanView", N_("Pan view"), PIXBUF_INLINE_ICON_PANORAMA},
751 {"SelectAll", N_("Select all"), PIXBUF_INLINE_ICON_SELECT_ALL},
752 {"SelectNone", N_("Select none"), PIXBUF_INLINE_ICON_SELECT_NONE},
753 {"SelectInvert", N_("Select invert"), PIXBUF_INLINE_ICON_SELECT_INVERT},
754 {"ShowFileFilter", N_("Show file filter"), PIXBUF_INLINE_ICON_FILE_FILTER},
755 {"RectangularSelection", N_("Select rectangle"), PIXBUF_INLINE_ICON_SELECT_RECTANGLE},
756 {"Print", N_("Print"), GTK_STOCK_PRINT},
757 {"Preferences", N_("Preferences"), GTK_STOCK_PREFERENCES},
758 {"LayoutConfig", N_("Configure this window"), GTK_STOCK_PREFERENCES},
759 {"Maintenance", N_("Cache maintenance"), PIXBUF_INLINE_ICON_MAINTENANCE},
760 {"RotateCW", N_("Rotate clockwise 90°"), PIXBUF_INLINE_ICON_CW},
761 {"RotateCCW", N_("Rotate counterclockwise 90°"), PIXBUF_INLINE_ICON_CCW},
762 {"Rotate180", N_("Rotate 180°"), PIXBUF_INLINE_ICON_180},
763 {"Mirror", N_("Mirror"), PIXBUF_INLINE_ICON_MIRROR},
764 {"Flip", N_("Flip"), PIXBUF_INLINE_ICON_FLIP},
765 {"AlterNone", N_("Original state"), PIXBUF_INLINE_ICON_ORIGINAL},
766 {"ZoomIn", N_("Zoom in"), GTK_STOCK_ZOOM_IN},
767 {"ZoomOut", N_("Zoom out"), GTK_STOCK_ZOOM_OUT},
768 {"Zoom100", N_("Zoom 1:1"), GTK_STOCK_ZOOM_100},
769 {"ZoomFit", N_("Zoom to fit"), GTK_STOCK_ZOOM_FIT},
770 {"ZoomFillHor", N_("Fit Horizontaly"), PIXBUF_INLINE_ICON_ZOOMFILLHOR},
771 {"ZoomFillVert", N_("Fit vertically"), PIXBUF_INLINE_ICON_ZOOMFILLVERT},
772 {"Zoom200", N_("Zoom 2:1"), GTK_STOCK_FILE},
773 {"Zoom300", N_("Zoom 3:1"), GTK_STOCK_FILE},
774 {"Zoom400", N_("Zoom 4:1"), GTK_STOCK_FILE},
775 {"Zoom50", N_("Zoom 1:2"), GTK_STOCK_FILE},
776 {"Zoom33", N_("Zoom1:3"), GTK_STOCK_FILE},
777 {"Zoom25", N_("Zoom 1:4"), GTK_STOCK_FILE},
778 {"ConnectZoomIn", N_("Connected Zoom in"), GTK_STOCK_ZOOM_IN},
779 {"SplitPaneSync", N_("Split Pane Sync"), PIXBUF_INLINE_SPLIT_PANE_SYNC},
780 {"Grayscale", N_("Grayscale"), PIXBUF_INLINE_ICON_GRAYSCALE},
781 {"OverUnderExposed", N_("Over Under Exposed"), PIXBUF_INLINE_ICON_EXPOSURE},
782 {"HideTools", N_("Hide file list"), PIXBUF_INLINE_ICON_HIDETOOLS},
783 {"SlideShowPause", N_("Pause slideshow"), GTK_STOCK_MEDIA_PAUSE},
784 {"SlideShowFaster", N_("Slideshow Faster"), GTK_STOCK_FILE},
785 {"SlideShowSlower", N_("Slideshow Slower"), GTK_STOCK_FILE},
786 {"Refresh", N_("Refresh"), GTK_STOCK_REFRESH},
787 {"HelpContents", N_("Help"), GTK_STOCK_HELP},
788 {"ExifWin", N_("Exif window"), PIXBUF_INLINE_ICON_EXIF},
789 {"Thumbnails", N_("Show thumbnails"), PIXBUF_INLINE_ICON_THUMB},
790 {"ShowMarks", N_("Show marks"), PIXBUF_INLINE_ICON_MARKS},
791 {"DrawRectangle", N_("Draw Rectangle"), PIXBUF_INLINE_ICON_DRAW_RECTANGLE},
792 {"FloatTools", N_("Float file list"), PIXBUF_INLINE_ICON_FLOAT},
793 {"SBar", N_("Info sidebar"), PIXBUF_INLINE_ICON_INFO},
794 {"SBarSort", N_("Sort manager"), PIXBUF_INLINE_ICON_SORT},
795 {"Quit", N_("Quit"), GTK_STOCK_QUIT},
799 static void mouse_buttons_selection_menu_cb(GtkWidget *combo, gpointer data)
801 gchar **option = data;
804 label = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo));
806 const UseableMouseItems *list = useable_mouse_items;
810 if (g_strcmp0(list->label, label) == 0)
818 *option = g_strdup(list->name);
822 static void add_mouse_selection_menu(GtkWidget *table, gint column, gint row, const gchar *text,
823 gchar *option, gchar **option_c)
831 pref_table_label(table, column, row, text, 0.0);
833 combo = gtk_combo_box_text_new();
835 const UseableMouseItems *list = useable_mouse_items;
839 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), list->label);
840 if (g_strcmp0(list->name, option) == 0)
848 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
850 g_signal_connect(G_OBJECT(combo), "changed",
851 G_CALLBACK(mouse_buttons_selection_menu_cb), option_c);
853 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
854 gtk_widget_show(combo);
857 static void thumb_size_menu_cb(GtkWidget *combo, gpointer data)
861 n = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
864 if ((guint) n < sizeof(thumb_size_list) / sizeof(ThumbSize))
866 c_options->thumbnails.max_width = thumb_size_list[n].w;
867 c_options->thumbnails.max_height = thumb_size_list[n].h;
871 c_options->thumbnails.max_width = options->thumbnails.max_width;
872 c_options->thumbnails.max_height = options->thumbnails.max_height;
876 static void add_thumb_size_menu(GtkWidget *table, gint column, gint row, gchar *text)
882 c_options->thumbnails.max_width = options->thumbnails.max_width;
883 c_options->thumbnails.max_height = options->thumbnails.max_height;
885 pref_table_label(table, column, row, text, 0.0);
887 combo = gtk_combo_box_text_new();
890 for (i = 0; (guint) i < sizeof(thumb_size_list) / sizeof(ThumbSize); i++)
895 w = thumb_size_list[i].w;
896 h = thumb_size_list[i].h;
898 buf = g_strdup_printf("%d x %d", w, h);
899 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
902 if (w == options->thumbnails.max_width && h == options->thumbnails.max_height) current = i;
909 buf = g_strdup_printf("%s %d x %d", _("Custom"), options->thumbnails.max_width, options->thumbnails.max_height);
910 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), buf);
916 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
917 g_signal_connect(G_OBJECT(combo), "changed",
918 G_CALLBACK(thumb_size_menu_cb), NULL);
920 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
921 gtk_widget_show(combo);
924 static void stereo_mode_menu_cb(GtkWidget *combo, gpointer data)
928 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
932 *option = PR_STEREO_NONE;
935 *option = PR_STEREO_ANAGLYPH_RC;
938 *option = PR_STEREO_ANAGLYPH_GM;
941 *option = PR_STEREO_ANAGLYPH_YB;
944 *option = PR_STEREO_ANAGLYPH_GRAY_RC;
947 *option = PR_STEREO_ANAGLYPH_GRAY_GM;
950 *option = PR_STEREO_ANAGLYPH_GRAY_YB;
953 *option = PR_STEREO_ANAGLYPH_DB_RC;
956 *option = PR_STEREO_ANAGLYPH_DB_GM;
959 *option = PR_STEREO_ANAGLYPH_DB_YB;
962 *option = PR_STEREO_HORIZ;
965 *option = PR_STEREO_HORIZ | PR_STEREO_HALF;
968 *option = PR_STEREO_VERT;
971 *option = PR_STEREO_VERT | PR_STEREO_HALF;
974 *option = PR_STEREO_FIXED;
979 static void add_stereo_mode_menu(GtkWidget *table, gint column, gint row, const gchar *text,
980 gint option, gint *option_c, gboolean add_fixed)
987 pref_table_label(table, column, row, text, 0.0);
989 combo = gtk_combo_box_text_new();
991 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Single image"));
993 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Red-Cyan"));
994 if (option & PR_STEREO_ANAGLYPH_RC) current = 1;
995 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Green-Magenta"));
996 if (option & PR_STEREO_ANAGLYPH_GM) current = 2;
997 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Yellow-Blue"));
998 if (option & PR_STEREO_ANAGLYPH_YB) current = 3;
999 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Red-Cyan"));
1000 if (option & PR_STEREO_ANAGLYPH_GRAY_RC) current = 4;
1001 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Green-Magenta"));
1002 if (option & PR_STEREO_ANAGLYPH_GRAY_GM) current = 5;
1003 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Gray Yellow-Blue"));
1004 if (option & PR_STEREO_ANAGLYPH_GRAY_YB) current = 6;
1005 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Red-Cyan"));
1006 if (option & PR_STEREO_ANAGLYPH_DB_RC) current = 7;
1007 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Green-Magenta"));
1008 if (option & PR_STEREO_ANAGLYPH_DB_GM) current = 8;
1009 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Anaglyph Dubois Yellow-Blue"));
1010 if (option & PR_STEREO_ANAGLYPH_DB_YB) current = 9;
1012 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side"));
1013 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Side by Side Half size"));
1014 if (option & PR_STEREO_HORIZ)
1017 if (option & PR_STEREO_HALF) current = 11;
1020 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom"));
1021 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Top - Bottom Half size"));
1022 if (option & PR_STEREO_VERT)
1025 if (option & PR_STEREO_HALF) current = 13;
1030 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Fixed position"));
1031 if (option & PR_STEREO_FIXED) current = 14;
1034 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1036 g_signal_connect(G_OBJECT(combo), "changed",
1037 G_CALLBACK(stereo_mode_menu_cb), option_c);
1039 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1040 gtk_widget_show(combo);
1043 static void video_menu_cb(GtkWidget *combo, gpointer data)
1045 gchar **option = data;
1047 EditorDescription *ed = g_list_nth_data(editor_list_get(), gtk_combo_box_get_active(GTK_COMBO_BOX(combo)));
1051 static void video_menu_populate(gpointer data, gpointer user_data)
1053 GtkWidget *combo = user_data;
1054 EditorDescription *ed = data;
1056 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), ed->name);
1059 static void add_video_menu(GtkWidget *table, gint column, gint row, const gchar *text,
1060 gchar *option, gchar **option_c)
1064 /* use lists since they are sorted */
1065 GList *eds = editor_list_get();
1069 pref_table_label(table, column, row, text, 0.0);
1071 combo = gtk_combo_box_text_new();
1072 g_list_foreach(eds,video_menu_populate,(gpointer)combo);
1073 current = option ? g_list_index(eds,g_hash_table_lookup(editors,option)): -1;
1075 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
1077 g_signal_connect(G_OBJECT(combo), "changed",
1078 G_CALLBACK(video_menu_cb), option_c);
1080 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
1081 gtk_widget_show(combo);
1084 static void filter_store_populate(void)
1088 if (!filter_store) return;
1090 gtk_list_store_clear(filter_store);
1092 work = filter_get_list();
1101 gtk_list_store_append(filter_store, &iter);
1102 gtk_list_store_set(filter_store, &iter, 0, fe, -1);
1106 static void filter_store_ext_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1107 gchar *new_text, gpointer data)
1109 GtkWidget *model = data;
1110 FilterEntry *fe = data;
1114 if (!new_text || strlen(new_text) < 1) return;
1116 tpath = gtk_tree_path_new_from_string(path_str);
1117 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1118 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1120 g_free(fe->extensions);
1121 fe->extensions = g_strdup(new_text);
1123 gtk_tree_path_free(tpath);
1127 static void filter_store_class_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1128 gchar *new_text, gpointer data)
1130 GtkWidget *model = data;
1131 FilterEntry *fe = data;
1136 if (!new_text || !new_text[0]) return;
1138 tpath = gtk_tree_path_new_from_string(path_str);
1139 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1140 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1142 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
1144 if (strcmp(new_text, _(format_class_list[i])) == 0)
1151 gtk_tree_path_free(tpath);
1155 static void filter_store_desc_edit_cb(GtkCellRendererText *cell, gchar *path_str,
1156 gchar *new_text, gpointer data)
1158 GtkWidget *model = data;
1163 if (!new_text || !new_text[0]) return;
1165 tpath = gtk_tree_path_new_from_string(path_str);
1166 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1167 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1169 g_free(fe->description);
1170 fe->description = g_strdup(new_text);
1172 gtk_tree_path_free(tpath);
1175 static void filter_store_enable_cb(GtkCellRendererToggle *renderer,
1176 gchar *path_str, gpointer data)
1178 GtkWidget *model = data;
1183 tpath = gtk_tree_path_new_from_string(path_str);
1184 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1185 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1187 fe->enabled = !fe->enabled;
1189 gtk_tree_path_free(tpath);
1193 static void filter_store_writable_cb(GtkCellRendererToggle *renderer,
1194 gchar *path_str, gpointer data)
1196 GtkWidget *model = data;
1201 tpath = gtk_tree_path_new_from_string(path_str);
1202 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1203 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1205 fe->writable = !fe->writable;
1206 if (fe->writable) fe->allow_sidecar = FALSE;
1208 gtk_tree_path_free(tpath);
1212 static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer,
1213 gchar *path_str, gpointer data)
1215 GtkWidget *model = data;
1220 tpath = gtk_tree_path_new_from_string(path_str);
1221 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath);
1222 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1);
1224 fe->allow_sidecar = !fe->allow_sidecar;
1225 if (fe->allow_sidecar) fe->writable = FALSE;
1227 gtk_tree_path_free(tpath);
1231 static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1232 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1236 gtk_tree_model_get(tree_model, iter, 0, &fe, -1);
1238 switch (GPOINTER_TO_INT(data))
1241 g_object_set(GTK_CELL_RENDERER(cell),
1242 "active", fe->enabled, NULL);
1245 g_object_set(GTK_CELL_RENDERER(cell),
1246 "text", fe->extensions, NULL);
1248 case FE_DESCRIPTION:
1249 g_object_set(GTK_CELL_RENDERER(cell),
1250 "text", fe->description, NULL);
1253 g_object_set(GTK_CELL_RENDERER(cell),
1254 "text", _(format_class_list[fe->file_class]), NULL);
1257 g_object_set(GTK_CELL_RENDERER(cell),
1258 "active", fe->writable, NULL);
1260 case FE_ALLOW_SIDECAR:
1261 g_object_set(GTK_CELL_RENDERER(cell),
1262 "active", fe->allow_sidecar, NULL);
1267 static gboolean filter_add_scroll(gpointer data)
1271 GtkCellRenderer *cell;
1272 GtkTreeViewColumn *column;
1275 rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(filter_store), NULL);
1276 path = gtk_tree_path_new_from_indices(rows-1, -1);
1278 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data), 0);
1280 list_cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
1281 cell = g_list_last(list_cells)->data;
1283 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1284 path, column, FALSE, 0.0, 0.0 );
1285 gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(data),
1286 path, column, cell, TRUE);
1288 gtk_tree_path_free(path);
1289 g_list_free(list_cells);
1294 static void filter_add_cb(GtkWidget *widget, gpointer data)
1296 filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE);
1297 filter_store_populate();
1299 g_idle_add((GSourceFunc)filter_add_scroll, data);
1302 static void filter_remove_cb(GtkWidget *widget, gpointer data)
1304 GtkWidget *filter_view = data;
1305 GtkTreeSelection *selection;
1309 if (!filter_store) return;
1310 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
1311 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
1312 gtk_tree_model_get(GTK_TREE_MODEL(filter_store), &iter, 0, &fe, -1);
1315 filter_remove_entry(fe);
1317 filter_store_populate();
1320 static gboolean filter_default_ok_scroll(GtkTreeView *data)
1324 GtkTreeViewColumn *column;
1326 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter);
1327 path = gtk_tree_model_get_path(GTK_TREE_MODEL(filter_store), &iter);
1328 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1330 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1334 gtk_tree_path_free(path);
1339 static void filter_default_ok_cb(GenericDialog *gd, gpointer data)
1342 filter_add_defaults();
1344 filter_store_populate();
1346 g_idle_add((GSourceFunc)filter_default_ok_scroll, gd->data);
1349 static void dummy_cancel_cb(GenericDialog *gd, gpointer data)
1351 /* no op, only so cancel button appears */
1354 static void filter_default_cb(GtkWidget *widget, gpointer data)
1358 gd = generic_dialog_new(_("Reset filters"),
1359 "reset_filter", widget, TRUE,
1360 dummy_cancel_cb, data);
1361 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset filters"),
1362 _("This will reset the file filters to the defaults.\nContinue?"), TRUE);
1363 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, filter_default_ok_cb, TRUE);
1364 gtk_widget_show(gd->dialog);
1367 static void filter_disable_cb(GtkWidget *widget, gpointer data)
1369 GtkWidget *frame = data;
1371 gtk_widget_set_sensitive(frame,
1372 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
1375 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
1377 layout_set_path(NULL, gtk_entry_get_text(GTK_ENTRY(safe_delete_path_entry)));
1380 static void safe_delete_clear_ok_cb(GenericDialog *gd, gpointer data)
1382 file_util_trash_clear();
1385 static void safe_delete_clear_cb(GtkWidget *widget, gpointer data)
1389 gd = generic_dialog_new(_("Clear trash"),
1390 "clear_trash", widget, TRUE,
1391 dummy_cancel_cb, NULL);
1392 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Clear trash"),
1393 _("This will remove the trash contents."), FALSE);
1394 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, safe_delete_clear_ok_cb, TRUE);
1395 entry = gtk_entry_new();
1396 gtk_widget_set_can_focus(entry, FALSE);
1397 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1398 if (options->file_ops.safe_delete_path) gtk_entry_set_text(GTK_ENTRY(entry), options->file_ops.safe_delete_path);
1399 gtk_box_pack_start(GTK_BOX(gd->vbox), entry, FALSE, FALSE, 0);
1400 gtk_widget_show(entry);
1401 gtk_widget_show(gd->dialog);
1404 static void image_overlay_template_view_changed_cb(GtkWidget *widget, gpointer data)
1406 GtkWidget *pTextView;
1407 GtkTextBuffer *pTextBuffer;
1411 pTextView = GTK_WIDGET(data);
1413 pTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pTextView));
1414 gtk_text_buffer_get_start_iter(pTextBuffer, &iStart);
1415 gtk_text_buffer_get_end_iter(pTextBuffer, &iEnd);
1417 set_image_overlay_template_string(&c_options->image_overlay.template_string,
1418 gtk_text_buffer_get_text(pTextBuffer, &iStart, &iEnd, TRUE));
1421 static void image_overlay_default_template_ok_cb(GenericDialog *gd, gpointer data)
1423 GtkTextView *text_view = data;
1424 GtkTextBuffer *buffer;
1426 set_default_image_overlay_template_string(&options->image_overlay.template_string);
1427 if (!configwindow) return;
1429 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
1430 gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
1433 static void image_overlay_default_template_cb(GtkWidget *widget, gpointer data)
1437 gd = generic_dialog_new(_("Reset image overlay template string"),
1438 "reset_image_overlay_template_string", widget, TRUE,
1439 dummy_cancel_cb, data);
1440 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, _("Reset image overlay template string"),
1441 _("This will reset the image overlay template string to the default.\nContinue?"), TRUE);
1442 generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, image_overlay_default_template_ok_cb, TRUE);
1443 gtk_widget_show(gd->dialog);
1446 static void image_overlay_help_cb(GtkWidget *widget, gpointer data)
1448 help_window_show("GuideOptionsOSD.html");
1451 static void image_overlay_set_font_cb(GtkWidget *widget, gpointer data)
1453 #if GTK_CHECK_VERSION(3,4,0)
1456 PangoFontDescription *font_desc;
1458 dialog = gtk_font_chooser_dialog_new("Image Overlay Font", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1459 gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog), options->image_overlay.font);
1461 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1463 font_desc = gtk_font_chooser_get_font_desc(GTK_FONT_CHOOSER(dialog));
1464 font = pango_font_description_to_string(font_desc);
1465 g_free(c_options->image_overlay.font);
1466 c_options->image_overlay.font = g_strdup(font);
1470 gtk_widget_destroy(dialog);
1474 font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
1475 c_options->image_overlay.font = g_strdup(font);
1479 static void image_overlay_set_text_colour_cb(GtkWidget *widget, gpointer data)
1482 #if GTK_CHECK_VERSION(3,4,0)
1485 dialog = gtk_color_chooser_dialog_new("Image Overlay Text Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1486 colour.red = options->image_overlay.text_red;
1487 colour.green = options->image_overlay.text_green;
1488 colour.blue = options->image_overlay.text_blue;
1489 colour.alpha = options->image_overlay.text_alpha;
1490 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1491 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1493 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1495 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1496 c_options->image_overlay.text_red = colour.red*255;
1497 c_options->image_overlay.text_green = colour.green*255;
1498 c_options->image_overlay.text_blue = colour.blue*255;
1499 c_options->image_overlay.text_alpha = colour.alpha*255;
1501 gtk_widget_destroy(dialog);
1504 GtkColorSelection *colorsel;
1506 dialog = gtk_color_selection_dialog_new("Image Overlay Text Colour");
1507 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1508 colour.red = options->image_overlay.text_red*257;
1509 colour.green = options->image_overlay.text_green*257;
1510 colour.blue = options->image_overlay.text_blue*257;
1511 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1512 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1513 gtk_color_selection_set_current_color(colorsel, &colour);
1514 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.text_alpha*257);
1516 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1518 gtk_color_selection_get_current_color(colorsel, &colour);
1519 c_options->image_overlay.text_red = colour.red/257;
1520 c_options->image_overlay.text_green = colour.green/257;
1521 c_options->image_overlay.text_blue = colour.blue/257;
1522 c_options->image_overlay.text_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1524 gtk_widget_destroy (dialog);
1529 static void image_overlay_set_background_colour_cb(GtkWidget *widget, gpointer data)
1532 #if GTK_CHECK_VERSION(3,4,0)
1535 dialog = gtk_color_chooser_dialog_new("Image Overlay Background Colour", GTK_WINDOW(gtk_widget_get_toplevel(widget)));
1536 colour.red = options->image_overlay.background_red;
1537 colour.green = options->image_overlay.background_green;
1538 colour.blue = options->image_overlay.background_blue;
1539 colour.alpha = options->image_overlay.background_alpha;
1540 gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1541 gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(dialog), TRUE);
1543 if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_CANCEL)
1545 gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(dialog), &colour);
1546 c_options->image_overlay.background_red = colour.red*255;
1547 c_options->image_overlay.background_green = colour.green*255;
1548 c_options->image_overlay.background_blue = colour.blue*255;
1549 c_options->image_overlay.background_alpha = colour.alpha*255;
1551 gtk_widget_destroy(dialog);
1554 GtkColorSelection *colorsel;
1556 dialog = gtk_color_selection_dialog_new("Image Overlay Background Colour");
1557 gtk_window_set_keep_above(GTK_WINDOW(dialog),TRUE);
1558 colour.red = options->image_overlay.background_red*257;
1559 colour.green = options->image_overlay.background_green*257;
1560 colour.blue = options->image_overlay.background_blue*257;
1561 colorsel = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(dialog)));
1562 gtk_color_selection_set_has_opacity_control(colorsel, TRUE);
1563 gtk_color_selection_set_current_color(colorsel, &colour);
1564 gtk_color_selection_set_current_alpha(colorsel, options->image_overlay.background_alpha*257);
1566 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
1568 gtk_color_selection_get_current_color(colorsel, &colour);
1569 c_options->image_overlay.background_red = colour.red/257;
1570 c_options->image_overlay.background_green = colour.green/257;
1571 c_options->image_overlay.background_blue = colour.blue/257;
1572 c_options->image_overlay.background_alpha = gtk_color_selection_get_current_alpha(colorsel)/257;
1574 gtk_widget_destroy(dialog);
1578 static void accel_store_populate(void)
1581 GList *groups, *actions;
1583 const gchar *accel_path;
1587 if (!accel_store || !layout_window_list || !layout_window_list->data) return;
1589 gtk_tree_store_clear(accel_store);
1590 lw = layout_window_list->data; /* get the actions from the first window, it should not matter, they should be the same in all windows */
1592 g_assert(lw && lw->ui_manager);
1593 groups = gtk_ui_manager_get_action_groups(lw->ui_manager);
1596 actions = gtk_action_group_list_actions(GTK_ACTION_GROUP(groups->data));
1599 action = GTK_ACTION(actions->data);
1600 accel_path = gtk_action_get_accel_path(action);
1601 if (accel_path && gtk_accel_map_lookup_entry(accel_path, &key))
1603 gchar *label, *label2, *tooltip, *accel;
1604 g_object_get(action,
1605 "tooltip", &tooltip,
1609 if (pango_parse_markup(label, -1, '_', NULL, &label2, NULL, NULL) && label2)
1615 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1619 gtk_tree_store_append(accel_store, &iter, NULL);
1620 gtk_tree_store_set(accel_store, &iter,
1623 AE_TOOLTIP, tooltip ? tooltip : "",
1624 AE_ACCEL, accel_path,
1632 actions = actions->next;
1635 groups = groups->next;
1639 static void accel_store_cleared_cb(GtkCellRendererAccel *accel, gchar *path_string, gpointer user_data)
1644 static gboolean accel_remove_key_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1646 gchar *accel1 = data;
1651 gtk_tree_model_get(model, iter, AE_KEY, &accel2, -1);
1653 gtk_accelerator_parse(accel1, &key1.accel_key, &key1.accel_mods);
1654 gtk_accelerator_parse(accel2, &key2.accel_key, &key2.accel_mods);
1656 if (key1.accel_key == key2.accel_key && key1.accel_mods == key2.accel_mods)
1658 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1659 DEBUG_1("accelerator key '%s' is already used, removing.", accel1);
1668 static void accel_store_edited_cb(GtkCellRendererAccel *accel, gchar *path_string, guint accel_key, GdkModifierType accel_mods, guint hardware_keycode, gpointer user_data)
1670 GtkTreeModel *model = (GtkTreeModel *)accel_store;
1674 GtkAccelKey old_key, key;
1675 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
1677 gtk_tree_model_get_iter(model, &iter, path);
1678 gtk_tree_model_get(model, &iter, AE_ACCEL, &accel_path, -1);
1680 /* test if the accelerator can be stored without conflicts*/
1681 gtk_accel_map_lookup_entry(accel_path, &old_key);
1683 /* change the key and read it back (change may fail on keys hardcoded in gtk)*/
1684 gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
1685 gtk_accel_map_lookup_entry(accel_path, &key);
1687 /* restore the original for now, the key will be really changed when the changes are confirmed */
1688 gtk_accel_map_change_entry(accel_path, old_key.accel_key, old_key.accel_mods, TRUE);
1690 acc = gtk_accelerator_name(key.accel_key, key.accel_mods);
1691 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, acc);
1693 gtk_tree_store_set(accel_store, &iter, AE_KEY, acc, -1);
1694 gtk_tree_path_free(path);
1698 static gboolean accel_default_scroll(GtkTreeView *data)
1702 GtkTreeViewColumn *column;
1704 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(accel_store), &iter);
1705 path = gtk_tree_model_get_path(GTK_TREE_MODEL(accel_store), &iter);
1706 column = gtk_tree_view_get_column(GTK_TREE_VIEW(data),0);
1708 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(data),
1712 gtk_tree_path_free(path);
1717 static void accel_default_cb(GtkWidget *widget, gpointer data)
1719 accel_store_populate();
1721 g_idle_add((GSourceFunc)accel_default_scroll, data);
1724 void accel_remove_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1726 gtk_tree_store_set(accel_store, iter, AE_KEY, "", -1);
1729 void accel_reset_selection(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
1732 gchar *accel_path, *accel;
1734 gtk_tree_model_get(model, iter, AE_ACCEL, &accel_path, -1);
1735 gtk_accel_map_lookup_entry(accel_path, &key);
1736 accel = gtk_accelerator_name(key.accel_key, key.accel_mods);
1738 gtk_tree_model_foreach(GTK_TREE_MODEL(accel_store), accel_remove_key_cb, accel);
1740 gtk_tree_store_set(accel_store, iter, AE_KEY, accel, -1);
1745 static void accel_reset_cb(GtkWidget *widget, gpointer data)
1747 GtkTreeSelection *selection;
1749 if (!accel_store) return;
1750 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data));
1751 gtk_tree_selection_selected_foreach(selection, &accel_reset_selection, NULL);
1756 static GtkWidget *scrolled_notebook_page(GtkWidget *notebook, const gchar *title)
1760 GtkWidget *scrolled;
1761 GtkWidget *viewport;
1763 scrolled = gtk_scrolled_window_new(NULL, NULL);
1764 gtk_container_set_border_width(GTK_CONTAINER(scrolled), PREF_PAD_BORDER);
1765 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1766 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1767 label = gtk_label_new(title);
1768 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label);
1769 gtk_widget_show(scrolled);
1771 viewport = gtk_viewport_new(NULL, NULL);
1772 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1773 gtk_container_add(GTK_CONTAINER(scrolled), viewport);
1774 gtk_widget_show(viewport);
1776 vbox = gtk_vbox_new(FALSE, 0);
1777 gtk_container_add(GTK_CONTAINER(viewport), vbox);
1778 gtk_widget_show(vbox);
1783 static void cache_standard_cb(GtkWidget *widget, gpointer data)
1785 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1787 c_options->thumbnails.spec_standard =TRUE;
1788 c_options->thumbnails.cache_into_dirs = FALSE;
1792 static void cache_geeqie_cb(GtkWidget *widget, gpointer data)
1794 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1796 c_options->thumbnails.spec_standard =FALSE;
1797 c_options->thumbnails.cache_into_dirs = FALSE;
1801 static void cache_local_cb(GtkWidget *widget, gpointer data)
1803 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
1805 c_options->thumbnails.cache_into_dirs = TRUE;
1806 c_options->thumbnails.spec_standard =FALSE;
1810 static void help_search_engine_entry_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1811 GdkEvent *event, gpointer userdata)
1813 if (pos == GTK_ENTRY_ICON_PRIMARY)
1815 gtk_entry_set_text(GTK_ENTRY(userdata), HELP_SEARCH_ENGINE);
1819 gtk_entry_set_text(GTK_ENTRY(userdata), "");
1823 static void star_rating_star_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1824 GdkEvent *event, gpointer userdata)
1826 gchar *rating_symbol;
1828 if (pos == GTK_ENTRY_ICON_PRIMARY)
1830 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_STAR);
1831 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1832 g_free(rating_symbol);
1836 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1837 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1838 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1842 static void star_rating_rejected_icon_cb(GtkEntry *entry, GtkEntryIconPosition pos,
1843 GdkEvent *event, gpointer userdata)
1845 gchar *rating_symbol;
1847 if (pos == GTK_ENTRY_ICON_PRIMARY)
1849 rating_symbol = g_strdup_printf("U+%X", STAR_RATING_REJECTED);
1850 gtk_entry_set_text(GTK_ENTRY(userdata), rating_symbol);
1851 g_free(rating_symbol);
1855 gtk_entry_set_text(GTK_ENTRY(userdata), "U+");
1856 gtk_widget_grab_focus(GTK_WIDGET(userdata));
1857 gtk_editable_select_region(GTK_EDITABLE(userdata), 2, 2);
1861 static guint star_rating_symbol_test(GtkWidget *widget, gpointer data)
1863 GtkContainer *hbox = data;
1864 GString *str = g_string_new(NULL);
1865 GtkEntry *hex_code_entry;
1866 gchar *hex_code_full;
1869 guint64 hex_value = 0;
1871 list = gtk_container_get_children(hbox);
1873 hex_code_entry = g_list_nth_data(list, 2);
1874 hex_code_full = g_strdup(gtk_entry_get_text(hex_code_entry));
1876 hex_code = g_strsplit(hex_code_full, "+", 2);
1877 if (hex_code[0] && hex_code[1])
1879 hex_value = strtoull(hex_code[1], NULL, 16);
1881 if (!hex_value || hex_value > 0x10FFFF)
1883 hex_value = 0x003F; // Unicode 'Question Mark'
1885 str = g_string_append_unichar(str, (gunichar)hex_value);
1886 gtk_label_set_text(g_list_nth_data(list, 1), str->str);
1888 g_strfreev(hex_code);
1889 g_string_free(str, TRUE);
1890 g_free(hex_code_full);
1895 static void star_rating_star_test_cb(GtkWidget *widget, gpointer data)
1897 guint64 star_symbol;
1899 star_symbol = star_rating_symbol_test(widget, data);
1900 c_options->star_rating.star = star_symbol;
1903 static void star_rating_rejected_test_cb(GtkWidget *widget, gpointer data)
1905 guint64 rejected_symbol;
1907 rejected_symbol = star_rating_symbol_test(widget, data);
1908 c_options->star_rating.rejected = rejected_symbol;
1911 /* general options tab */
1912 static void timezone_database_install_cb(GtkWidget *widget, gpointer data);
1913 typedef struct _TZData TZData;
1917 GCancellable *cancellable;
1919 GtkWidget *progress;
1921 GFile *timezone_database_gq;
1922 gchar *timezone_database_user;
1925 static void config_tab_general(GtkWidget *notebook)
1930 GtkWidget *group_frame;
1931 GtkWidget *subgroup;
1933 GtkWidget *ct_button;
1936 gint hours, minutes, remainder;
1938 GtkWidget *star_rating_entry;
1940 gchar *rating_symbol;
1943 GNetworkMonitor *net_mon;
1944 GSocketConnectable *geeqie_org;
1945 gboolean internet_available;
1948 vbox = scrolled_notebook_page(notebook, _("General"));
1950 group = pref_group_new(vbox, FALSE, _("Thumbnails"), GTK_ORIENTATION_VERTICAL);
1952 table = pref_table_new(group, 2, 2, FALSE, FALSE);
1953 add_thumb_size_menu(table, 0, 0, _("Size:"));
1954 add_quality_menu(table, 0, 1, _("Quality:"), options->thumbnails.quality, &c_options->thumbnails.quality);
1956 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
1957 pref_label_new(hbox, _("Custom size: "));
1958 pref_spin_new_int(hbox, _("Width:"), NULL, 1, 512, 1, options->thumbnails.max_width, &c_options->thumbnails.max_width);
1959 pref_spin_new_int(hbox, _("Height:"), NULL, 1, 512, 1, options->thumbnails.max_height, &c_options->thumbnails.max_height);
1961 ct_button = pref_checkbox_new_int(group, _("Cache thumbnails and sim. files"),
1962 options->thumbnails.enable_caching, &c_options->thumbnails.enable_caching);
1964 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1965 pref_checkbox_link_sensitivity(ct_button, subgroup);
1967 c_options->thumbnails.spec_standard = options->thumbnails.spec_standard;
1968 c_options->thumbnails.cache_into_dirs = options->thumbnails.cache_into_dirs;
1969 group_frame = pref_frame_new(subgroup, TRUE, _("Use Geeqie thumbnail style and cache"),
1970 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1971 button = pref_radiobutton_new(group_frame, NULL, get_thumbnails_cache_dir(),
1972 !options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1973 G_CALLBACK(cache_geeqie_cb), NULL);
1975 group_frame = pref_frame_new(subgroup, TRUE,
1976 _("Store thumbnails local to image folder (non-standard)"),
1977 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1978 pref_radiobutton_new(group_frame, button, "*/.thumbnails",
1979 !options->thumbnails.spec_standard && options->thumbnails.cache_into_dirs,
1980 G_CALLBACK(cache_local_cb), NULL);
1982 group_frame = pref_frame_new(subgroup, TRUE,
1983 _("Use standard thumbnail style and cache, shared with other applications"),
1984 GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
1985 pref_radiobutton_new(group_frame, button, get_thumbnails_standard_cache_dir(),
1986 options->thumbnails.spec_standard && !options->thumbnails.cache_into_dirs,
1987 G_CALLBACK(cache_standard_cb), NULL);
1989 pref_checkbox_new_int(group, _("Use EXIF thumbnails when available (EXIF thumbnails may be outdated)"),
1990 options->thumbnails.use_exif, &c_options->thumbnails.use_exif);
1992 pref_checkbox_new_int(group, _("Thumbnail color management"),
1993 options->thumbnails.use_color_management, &c_options->thumbnails.use_color_management);
1995 spin = pref_spin_new_int(group, _("Collection preview:"), NULL,
1997 options->thumbnails.collection_preview, &c_options->thumbnails.collection_preview);
1998 gtk_widget_set_tooltip_text(spin, _("The maximum number of thumbnails shown in a Collection preview montage"));
2000 #ifdef HAVE_FFMPEGTHUMBNAILER_METADATA
2001 pref_checkbox_new_int(group, _("Use embedded metadata in video files as thumbnails when available"),
2002 options->thumbnails.use_ft_metadata, &c_options->thumbnails.use_ft_metadata);
2004 // pref_checkbox_new_int(group, _("Ignore embedded metadata if size is too small"),
2005 // options->thumbnails.use_ft_metadata_small, &c_options->thumbnails.use_ft_metadata_small);
2008 pref_spacer(group, PREF_PAD_GROUP);
2010 group = pref_group_new(vbox, FALSE, _("Star Rating"), GTK_ORIENTATION_VERTICAL);
2012 c_options->star_rating.star = options->star_rating.star;
2013 c_options->star_rating.rejected = options->star_rating.rejected;
2015 str = g_string_new(NULL);
2016 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2017 pref_label_new(hbox, _("Star character: "));
2018 str = g_string_append_unichar(str, options->star_rating.star);
2019 pref_label_new(hbox, g_strdup(str->str));
2020 rating_symbol = g_strdup_printf("U+%X", options->star_rating.star);
2021 star_rating_entry = gtk_entry_new();
2022 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2023 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2024 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2025 gtk_widget_show(star_rating_entry);
2026 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2027 G_CALLBACK(star_rating_star_test_cb), hbox);
2028 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2029 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2030 gtk_widget_show(button);
2031 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."));
2032 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2033 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2034 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2035 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2036 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2037 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2038 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2039 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2040 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2041 G_CALLBACK(star_rating_star_icon_cb),
2044 g_string_free(str, TRUE);
2045 g_free(rating_symbol);
2047 str = g_string_new(NULL);
2048 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2049 pref_label_new(hbox, _("Rejected character: "));
2050 str = g_string_append_unichar(str, options->star_rating.rejected);
2051 pref_label_new(hbox, g_strdup(str->str));
2052 rating_symbol = g_strdup_printf("U+%X", options->star_rating.rejected);
2053 star_rating_entry = gtk_entry_new();
2054 gtk_entry_set_text(GTK_ENTRY(star_rating_entry), rating_symbol);
2055 gtk_box_pack_start(GTK_BOX(hbox), star_rating_entry, FALSE, FALSE, 0);
2056 gtk_entry_set_width_chars(GTK_ENTRY(star_rating_entry), 15);
2057 gtk_widget_show(star_rating_entry);
2058 button = pref_button_new(NULL, NULL, _("Set"), FALSE,
2059 G_CALLBACK(star_rating_rejected_test_cb), hbox);
2060 gtk_widget_set_tooltip_text(button, _("Display selected character"));
2061 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2062 gtk_widget_show(button);
2063 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."));
2064 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2065 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2066 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2067 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2068 gtk_entry_set_icon_from_stock(GTK_ENTRY(star_rating_entry),
2069 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2070 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(star_rating_entry),
2071 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2072 g_signal_connect(GTK_ENTRY(star_rating_entry), "icon-press",
2073 G_CALLBACK(star_rating_rejected_icon_cb),
2076 g_string_free(str, TRUE);
2077 g_free(rating_symbol);
2079 pref_spacer(group, PREF_PAD_GROUP);
2081 group = pref_group_new(vbox, FALSE, _("Slide show"), GTK_ORIENTATION_VERTICAL);
2083 c_options->slideshow.delay = options->slideshow.delay;
2084 hours = options->slideshow.delay / (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2085 remainder = options->slideshow.delay % (3600 * SLIDESHOW_SUBSECOND_PRECISION);
2086 minutes = remainder / (60 * SLIDESHOW_SUBSECOND_PRECISION);
2087 seconds = (gdouble)(remainder % (60 * SLIDESHOW_SUBSECOND_PRECISION)) /
2088 SLIDESHOW_SUBSECOND_PRECISION;
2090 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2092 spin = pref_spin_new(hbox, _("Delay between image change hrs:mins:secs.dec"), NULL,
2094 options->slideshow.delay ? hours : 0.0,
2095 G_CALLBACK(slideshow_delay_hours_cb), NULL);
2096 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2097 spin = pref_spin_new(hbox, ":" , NULL,
2099 options->slideshow.delay ? minutes: 0.0,
2100 G_CALLBACK(slideshow_delay_minutes_cb), NULL);
2101 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2102 spin = pref_spin_new(hbox, ":", NULL,
2103 SLIDESHOW_MIN_SECONDS, 59, 1.0, 1,
2104 options->slideshow.delay ? seconds : 10.0,
2105 G_CALLBACK(slideshow_delay_seconds_cb), NULL);
2106 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2108 pref_checkbox_new_int(group, _("Random"), options->slideshow.random, &c_options->slideshow.random);
2109 pref_checkbox_new_int(group, _("Repeat"), options->slideshow.repeat, &c_options->slideshow.repeat);
2111 pref_spacer(group, PREF_PAD_GROUP);
2113 group = pref_group_new(vbox, FALSE, _("Image loading and caching"), GTK_ORIENTATION_VERTICAL);
2115 pref_spin_new_int(group, _("Decoded image cache size (MiB):"), NULL,
2116 0, 99999, 1, options->image.image_cache_max, &c_options->image.image_cache_max);
2117 pref_checkbox_new_int(group, _("Preload next image"),
2118 options->image.enable_read_ahead, &c_options->image.enable_read_ahead);
2120 pref_checkbox_new_int(group, _("Refresh on file change"),
2121 options->update_on_time_change, &c_options->update_on_time_change);
2124 pref_spacer(group, PREF_PAD_GROUP);
2126 group = pref_group_new(vbox, FALSE, _("Expand menu and toolbar"), GTK_ORIENTATION_VERTICAL);
2128 pref_checkbox_new_int(group, _("Expand menu and toolbar (NOTE! Geeqie must be restarted for change to take effect)"),
2129 options->expand_menu_toolbar, &c_options->expand_menu_toolbar);
2130 gtk_widget_set_tooltip_text(group, _("Expand the menu and toolbar to the full width of the window"));
2132 pref_spacer(group, PREF_PAD_GROUP);
2134 net_mon = g_network_monitor_get_default();
2135 geeqie_org = g_network_address_parse_uri(GQ_WEBSITE, 80, NULL);
2136 internet_available = g_network_monitor_can_reach(net_mon, geeqie_org, NULL, NULL);
2137 g_object_unref(geeqie_org);
2139 group = pref_group_new(vbox, FALSE, _("Timezone database"), GTK_ORIENTATION_VERTICAL);
2140 hbox = pref_box_new(group, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2142 if (!internet_available)
2144 gtk_widget_set_sensitive(group, FALSE);
2147 tz = g_new0(TZData, 1);
2149 path = path_from_utf8(TIMEZONE_DATABASE);
2150 basename = g_path_get_basename(path);
2151 tz->timezone_database_user = g_build_filename(get_rc_dir(), basename, NULL);
2155 if (isfile(tz->timezone_database_user))
2157 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Update"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2161 button = pref_button_new(GTK_WIDGET(hbox), NULL, _("Install"), FALSE, G_CALLBACK(timezone_database_install_cb), tz);
2164 if (!internet_available)
2166 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"));
2170 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"));
2172 gtk_widget_show(button);
2174 pref_spacer(group, PREF_PAD_GROUP);
2176 group = pref_group_new(vbox, FALSE, _("On-line help search engine"), GTK_ORIENTATION_VERTICAL);
2178 help_search_engine_entry = gtk_entry_new();
2179 gtk_entry_set_text(GTK_ENTRY(help_search_engine_entry), options->help_search_engine);
2180 gtk_box_pack_start(GTK_BOX(group), help_search_engine_entry, FALSE, FALSE, 0);
2181 gtk_widget_show(help_search_engine_entry);
2183 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"));
2185 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2186 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
2187 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2188 GTK_ENTRY_ICON_SECONDARY, _("Clear"));
2189 gtk_entry_set_icon_from_stock(GTK_ENTRY(help_search_engine_entry),
2190 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_REVERT_TO_SAVED);
2191 gtk_entry_set_icon_tooltip_text (GTK_ENTRY(help_search_engine_entry),
2192 GTK_ENTRY_ICON_PRIMARY, _("Default"));
2193 g_signal_connect(GTK_ENTRY(help_search_engine_entry), "icon-press",
2194 G_CALLBACK(help_search_engine_entry_icon_cb),
2195 help_search_engine_entry);
2199 static void config_tab_image(GtkWidget *notebook)
2204 GtkWidget *ct_button;
2205 GtkWidget *enlargement_button;
2208 GtkWidget *two_pass;
2210 GtkWidget *gpu_accel;
2213 vbox = scrolled_notebook_page(notebook, _("Image"));
2215 group = pref_group_new(vbox, FALSE, _("Zoom"), GTK_ORIENTATION_VERTICAL);
2217 table = pref_table_new(group, 2, 1, FALSE, FALSE);
2218 add_quality_menu(table, 0, 0, _("Quality:"), options->image.zoom_quality, &c_options->image.zoom_quality);
2219 if (options->image.use_clutter_renderer && !options->disable_gpu)
2221 gtk_widget_set_sensitive(table, FALSE);
2225 gpu_accel = pref_checkbox_new_int(group, _("Use GPU acceleration via Clutter library (Requires restart)"),
2226 options->image.use_clutter_renderer, &c_options->image.use_clutter_renderer);
2227 if (options->disable_gpu && !options->override_disable_gpu)
2229 gtk_widget_set_sensitive(gpu_accel, FALSE);
2233 two_pass = pref_checkbox_new_int(group, _("Two pass rendering (apply HQ zoom and color correction in second pass)"),
2234 options->image.zoom_2pass, &c_options->image.zoom_2pass);
2235 if (options->image.use_clutter_renderer && !options->disable_gpu)
2237 gtk_widget_set_sensitive(two_pass, FALSE);
2240 c_options->image.zoom_increment = options->image.zoom_increment;
2241 spin = pref_spin_new(group, _("Zoom increment:"), NULL,
2242 0.01, 4.0, 0.01, 2, (gdouble)options->image.zoom_increment / 100.0,
2243 G_CALLBACK(zoom_increment_cb), NULL);
2244 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spin), GTK_UPDATE_ALWAYS);
2246 group = pref_group_new(vbox, FALSE, _("Fit image to window"), GTK_ORIENTATION_VERTICAL);
2248 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2249 enlargement_button = pref_checkbox_new_int(hbox, _("Allow enlargement of image (max. size in %)"),
2250 options->image.zoom_to_fit_allow_expand, &c_options->image.zoom_to_fit_allow_expand);
2251 spin = pref_spin_new_int(hbox, NULL, NULL,
2253 options->image.max_enlargement_size, &c_options->image.max_enlargement_size);
2254 pref_checkbox_link_sensitivity(enlargement_button, spin);
2255 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."));
2257 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2258 ct_button = pref_checkbox_new_int(hbox, _("Virtual window size (% of actual window):"),
2259 options->image.limit_autofit_size, &c_options->image.limit_autofit_size);
2260 spin = pref_spin_new_int(hbox, NULL, NULL,
2262 options->image.max_autofit_size, &c_options->image.max_autofit_size);
2263 pref_checkbox_link_sensitivity(ct_button, spin);
2264 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."));
2266 group = pref_group_new(vbox, FALSE, _("Tile size"), GTK_ORIENTATION_VERTICAL);
2267 gtk_widget_set_sensitive(group, !options->image.use_clutter_renderer);
2269 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2270 spin = pref_spin_new_int(hbox, _("Pixels"), _("(Requires restart)"),
2272 options->image.tile_size, &c_options->image.tile_size);
2273 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."));
2275 group = pref_group_new(vbox, FALSE, _("Appearance"), GTK_ORIENTATION_VERTICAL);
2277 pref_checkbox_new_int(group, _("Use custom border color in window mode"),
2278 options->image.use_custom_border_color, &c_options->image.use_custom_border_color);
2280 pref_checkbox_new_int(group, _("Use custom border color in fullscreen mode"),
2281 options->image.use_custom_border_color_in_fullscreen, &c_options->image.use_custom_border_color_in_fullscreen);
2283 pref_color_button_new(group, _("Border color"), &options->image.border_color,
2284 G_CALLBACK(pref_color_button_set_cb), &c_options->image.border_color);
2286 c_options->image.border_color = options->image.border_color;
2288 pref_color_button_new(group, _("Alpha channel color 1"), &options->image.alpha_color_1,
2289 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_1);
2291 pref_color_button_new(group, _("Alpha channel color 2"), &options->image.alpha_color_2,
2292 G_CALLBACK(pref_color_button_set_cb), &c_options->image.alpha_color_2);
2294 c_options->image.alpha_color_1 = options->image.alpha_color_1;
2295 c_options->image.alpha_color_2 = options->image.alpha_color_2;
2297 group = pref_group_new(vbox, FALSE, _("Convenience"), GTK_ORIENTATION_VERTICAL);
2299 pref_checkbox_new_int(group, _("Auto rotate proofs using Exif information"),
2300 options->image.exif_proof_rotate_enable, &c_options->image.exif_proof_rotate_enable);
2305 static void save_default_window_layout_cb(GtkWidget *widget, gpointer data)
2307 LayoutWindow *lw = NULL;
2308 gchar *default_path;
2311 /* Get current lw */
2314 tmp_id = lw->options.id;
2315 lw->options.id = g_strdup("lw_default");
2317 default_path = g_build_filename(get_rc_dir(), DEFAULT_WINDOW_LAYOUT, NULL);
2318 save_default_layout_options_to_file(default_path, options, lw);
2319 g_free(lw->options.id);
2320 lw->options.id = tmp_id;
2321 g_free(default_path);
2324 #if GTK_CHECK_VERSION(3,22,0)
2325 static gboolean popover_cb(gpointer data)
2327 GtkPopover *popover = data;
2329 gtk_popover_popdown(popover);
2334 static void default_layout_changed_cb(GtkWidget *button, GtkPopover *popover)
2336 gtk_popover_popup(popover);
2338 g_timeout_add(2000, popover_cb, popover);
2341 static GtkWidget *create_popover(GtkWidget *parent, GtkWidget *child, GtkPositionType pos)
2345 popover = gtk_popover_new(parent);
2346 gtk_popover_set_position(GTK_POPOVER (popover), pos);
2347 gtk_container_add (GTK_CONTAINER(popover), child);
2348 gtk_container_set_border_width(GTK_CONTAINER (popover), 6);
2349 gtk_widget_show (child);
2355 static void config_tab_windows(GtkWidget *notebook)
2360 GtkWidget *subgroup;
2362 GtkWidget *ct_button;
2365 vbox = scrolled_notebook_page(notebook, _("Windows"));
2367 group = pref_group_new(vbox, FALSE, _("State"), GTK_ORIENTATION_VERTICAL);
2369 ct_button = pref_checkbox_new_int(group, _("Remember session"),
2370 options->save_window_positions, &c_options->save_window_positions);
2372 button = pref_checkbox_new_int(group, _("Use saved window positions also for new windows"),
2373 options->use_saved_window_positions_for_new_windows, &c_options->use_saved_window_positions_for_new_windows);
2374 pref_checkbox_link_sensitivity(ct_button, button);
2376 button = pref_checkbox_new_int(group, _("Remember window workspace"),
2377 options->save_window_workspace, &c_options->save_window_workspace);
2378 pref_checkbox_link_sensitivity(ct_button, button);
2380 pref_checkbox_new_int(group, _("Remember tool state (float/hidden)"),
2381 options->tools_restore_state, &c_options->tools_restore_state);
2383 pref_checkbox_new_int(group, _("Remember dialog window positions"),
2384 options->save_dialog_window_positions, &c_options->save_dialog_window_positions);
2386 pref_checkbox_new_int(group, _("Show window IDs"),
2387 options->show_window_ids, &c_options->show_window_ids);
2389 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2390 pref_label_new(subgroup, _("Use current layout for default: "));
2391 button = pref_button_new(subgroup, NULL, _("Set"), FALSE, G_CALLBACK(save_default_window_layout_cb), NULL);
2393 #if GTK_CHECK_VERSION(3,22,0)
2396 popover = create_popover(button, gtk_label_new(_("Current window layout\nhas been set as default")), GTK_POS_TOP);
2397 gtk_popover_set_modal(GTK_POPOVER (popover), FALSE);
2398 g_signal_connect(button, "clicked", G_CALLBACK(default_layout_changed_cb), popover);
2401 group = pref_group_new(vbox, FALSE, _("Size"), GTK_ORIENTATION_VERTICAL);
2403 pref_checkbox_new_int(group, _("Fit window to image when tools are hidden/floating"),
2404 options->image.fit_window_to_image, &c_options->image.fit_window_to_image);
2406 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2407 ct_button = pref_checkbox_new_int(hbox, _("Limit size when auto-sizing window (%):"),
2408 options->image.limit_window_size, &c_options->image.limit_window_size);
2409 spin = pref_spin_new_int(hbox, NULL, NULL,
2411 options->image.max_window_size, &c_options->image.max_window_size);
2412 pref_checkbox_link_sensitivity(ct_button, spin);
2414 group = pref_group_new(vbox, FALSE, _("Full screen"), GTK_ORIENTATION_VERTICAL);
2416 c_options->fullscreen.screen = options->fullscreen.screen;
2417 c_options->fullscreen.above = options->fullscreen.above;
2418 hbox = fullscreen_prefs_selection_new(_("Location:"), &c_options->fullscreen.screen, &c_options->fullscreen.above);
2419 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2420 gtk_widget_show(hbox);
2422 pref_checkbox_new_int(group, _("Smooth image flip"),
2423 options->fullscreen.clean_flip, &c_options->fullscreen.clean_flip);
2424 pref_checkbox_new_int(group, _("Disable screen saver"),
2425 options->fullscreen.disable_saver, &c_options->fullscreen.disable_saver);
2428 #define PRE_FORMATTED_COLUMNS 5
2429 static void config_tab_osd(GtkWidget *notebook)
2435 GtkWidget *image_overlay_template_view;
2436 GtkWidget *scrolled;
2437 GtkWidget *scrolled_pre_formatted;
2438 GtkTextBuffer *buffer;
2440 GtkWidget *subgroup;
2442 vbox = scrolled_notebook_page(notebook, _("OSD"));
2444 image_overlay_template_view = gtk_text_view_new();
2446 group = pref_group_new(vbox, FALSE, _("Overlay Screen Display"), GTK_ORIENTATION_VERTICAL);
2448 subgroup = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2450 scrolled_pre_formatted = osd_new(PRE_FORMATTED_COLUMNS, image_overlay_template_view);
2451 gtk_widget_set_size_request(scrolled_pre_formatted, 200, 150);
2452 gtk_box_pack_start(GTK_BOX(subgroup), scrolled_pre_formatted, FALSE, FALSE, 0);
2453 gtk_widget_show(scrolled_pre_formatted);
2454 gtk_widget_show(subgroup);
2456 pref_line(group, PREF_PAD_GAP);
2458 pref_label_new(group, _("Image overlay template"));
2460 scrolled = gtk_scrolled_window_new(NULL, NULL);
2461 gtk_widget_set_size_request(scrolled, 200, 150);
2462 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2463 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2464 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2465 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 5);
2466 gtk_widget_show(scrolled);
2468 gtk_widget_set_tooltip_markup(image_overlay_template_view,
2469 _("Extensive formatting options are shown in the Help file"));
2471 gtk_container_add(GTK_CONTAINER(scrolled), image_overlay_template_view);
2472 gtk_widget_show(image_overlay_template_view);
2474 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2476 #if GTK_CHECK_VERSION(3,4,0)
2477 button = pref_button_new(NULL, GTK_STOCK_SELECT_FONT, _("Font"), FALSE,
2478 G_CALLBACK(image_overlay_set_font_cb), notebook);
2480 button = gtk_font_button_new();
2481 gtk_font_button_set_title(GTK_FONT_BUTTON(button), "Image Overlay Font");
2482 gtk_font_button_set_font_name(GTK_FONT_BUTTON(button), options->image_overlay.font);
2483 g_signal_connect(G_OBJECT(button), "font-set",
2484 G_CALLBACK(image_overlay_set_font_cb),NULL);
2486 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2487 gtk_widget_show(button);
2489 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Text"), FALSE,
2490 G_CALLBACK(image_overlay_set_text_colour_cb), NULL);
2491 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2492 gtk_widget_show(button);
2494 button = pref_button_new(NULL, GTK_STOCK_COLOR_PICKER, _("Background"), FALSE,
2495 G_CALLBACK(image_overlay_set_background_colour_cb), NULL);
2496 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2497 gtk_widget_show(button);
2498 image_overlay_set_text_colours();
2500 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2501 G_CALLBACK(image_overlay_default_template_cb), image_overlay_template_view);
2502 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2503 gtk_widget_show(button);
2505 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
2506 G_CALLBACK(image_overlay_help_cb), NULL);
2507 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2508 gtk_widget_show(button);
2510 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(image_overlay_template_view));
2511 if (options->image_overlay.template_string) gtk_text_buffer_set_text(buffer, options->image_overlay.template_string, -1);
2512 g_signal_connect(G_OBJECT(buffer), "changed",
2513 G_CALLBACK(image_overlay_template_view_changed_cb), image_overlay_template_view);
2515 pref_line(group, PREF_PAD_GAP);
2517 group = pref_group_new(vbox, FALSE, _("Exif, XMP or IPTC tags"), GTK_ORIENTATION_VERTICAL);
2518 hbox = gtk_hbox_new(FALSE, 0);
2519 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2520 gtk_widget_show(hbox);
2521 label = gtk_label_new(_("%Exif.Image.Orientation%"));
2522 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2523 gtk_widget_show(label);
2524 pref_spacer(group,TRUE);
2526 group = pref_group_new(vbox, FALSE, _("Field separators"), GTK_ORIENTATION_VERTICAL);
2527 hbox = gtk_hbox_new(FALSE, 0);
2528 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2529 gtk_widget_show(hbox);
2530 label = gtk_label_new(_("Separator shown only if both fields are non-null:\n%formatted.ShutterSpeed%|%formatted.ISOSpeedRating%"));
2531 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2532 gtk_widget_show(label);
2533 pref_spacer(group,TRUE);
2535 group = pref_group_new(vbox, FALSE, _("Field maximum length"), GTK_ORIENTATION_VERTICAL);
2536 hbox = gtk_hbox_new(FALSE, 0);
2537 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2538 gtk_widget_show(hbox);
2539 label = gtk_label_new(_("%path:39%"));
2540 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2541 gtk_widget_show(label);
2542 pref_spacer(group,TRUE);
2544 group = pref_group_new(vbox, FALSE, _("Pre- and post- text"), GTK_ORIENTATION_VERTICAL);
2545 hbox = gtk_hbox_new(FALSE, 0);
2546 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2547 gtk_widget_show(hbox);
2548 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%"));
2549 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2550 gtk_widget_show(label);
2551 pref_spacer(group,TRUE);
2553 group = pref_group_new(vbox, FALSE, _("Pango markup"), GTK_ORIENTATION_VERTICAL);
2554 hbox = gtk_hbox_new(FALSE, 0);
2555 gtk_box_pack_start(GTK_BOX(group), hbox, FALSE, FALSE, 0);
2556 gtk_widget_show(hbox);
2557 label = gtk_label_new(_("<b>bold</b>\n<u>underline</u>\n<i>italic</i>\n<s>strikethrough</s>"));
2558 gtk_box_pack_start(GTK_BOX(hbox),label, FALSE,FALSE,0);
2559 gtk_widget_show(label);
2562 static GtkTreeModel *create_class_model(void)
2564 GtkListStore *model;
2568 /* create list store */
2569 model = gtk_list_store_new(1, G_TYPE_STRING);
2570 for (i = 0; i < FILE_FORMAT_CLASSES; i++)
2572 gtk_list_store_append(model, &iter);
2573 gtk_list_store_set(model, &iter, 0, _(format_class_list[i]), -1);
2575 return GTK_TREE_MODEL (model);
2580 static void config_tab_files(GtkWidget *notebook)
2587 GtkWidget *ct_button;
2588 GtkWidget *scrolled;
2589 GtkWidget *filter_view;
2590 GtkCellRenderer *renderer;
2591 GtkTreeSelection *selection;
2592 GtkTreeViewColumn *column;
2594 vbox = scrolled_notebook_page(notebook, _("Files"));
2596 group = pref_box_new(vbox, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
2598 pref_checkbox_new_int(group, _("Show hidden files or folders"),
2599 options->file_filter.show_hidden_files, &c_options->file_filter.show_hidden_files);
2600 pref_checkbox_new_int(group, _("Show parent folder (..)"),
2601 options->file_filter.show_parent_directory, &c_options->file_filter.show_parent_directory);
2602 pref_checkbox_new_int(group, _("Case sensitive sort"),
2603 options->file_sort.case_sensitive, &c_options->file_sort.case_sensitive);
2604 pref_checkbox_new_int(group, _("Natural sort order"),
2605 options->file_sort.natural, &c_options->file_sort.natural);
2606 pref_checkbox_new_int(group, _("Disable file extension checks"),
2607 options->file_filter.disable_file_extension_checks, &c_options->file_filter.disable_file_extension_checks);
2609 ct_button = pref_checkbox_new_int(group, _("Disable File Filtering"),
2610 options->file_filter.disable, &c_options->file_filter.disable);
2613 group = pref_group_new(vbox, FALSE, _("Grouping sidecar extensions"), GTK_ORIENTATION_VERTICAL);
2615 sidecar_ext_entry = gtk_entry_new();
2616 gtk_entry_set_text(GTK_ENTRY(sidecar_ext_entry), options->sidecar.ext);
2617 gtk_box_pack_start(GTK_BOX(group), sidecar_ext_entry, FALSE, FALSE, 0);
2618 gtk_widget_show(sidecar_ext_entry);
2620 group = pref_group_new(vbox, TRUE, _("File types"), GTK_ORIENTATION_VERTICAL);
2622 frame = pref_group_parent(group);
2623 g_signal_connect(G_OBJECT(ct_button), "toggled",
2624 G_CALLBACK(filter_disable_cb), frame);
2625 gtk_widget_set_sensitive(frame, !options->file_filter.disable);
2627 scrolled = gtk_scrolled_window_new(NULL, NULL);
2628 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
2629 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2630 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
2631 gtk_widget_show(scrolled);
2633 filter_store = gtk_list_store_new(1, G_TYPE_POINTER);
2634 filter_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(filter_store));
2635 g_object_unref(filter_store);
2636 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(filter_view));
2637 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
2639 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(filter_view), FALSE);
2641 column = gtk_tree_view_column_new();
2642 gtk_tree_view_column_set_title(column, _("Filter"));
2643 gtk_tree_view_column_set_resizable(column, TRUE);
2645 renderer = gtk_cell_renderer_toggle_new();
2646 g_signal_connect(G_OBJECT(renderer), "toggled",
2647 G_CALLBACK(filter_store_enable_cb), filter_store);
2648 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2649 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2650 GINT_TO_POINTER(FE_ENABLE), NULL);
2652 renderer = gtk_cell_renderer_text_new();
2653 g_signal_connect(G_OBJECT(renderer), "edited",
2654 G_CALLBACK(filter_store_ext_edit_cb), filter_store);
2655 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2656 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2657 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2658 GINT_TO_POINTER(FE_EXTENSION), NULL);
2659 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2661 column = gtk_tree_view_column_new();
2662 gtk_tree_view_column_set_title(column, _("Description"));
2663 gtk_tree_view_column_set_resizable(column, TRUE);
2664 gtk_tree_view_column_set_fixed_width(column, 200);
2665 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
2667 renderer = gtk_cell_renderer_text_new();
2668 g_signal_connect(G_OBJECT(renderer), "edited",
2669 G_CALLBACK(filter_store_desc_edit_cb), filter_store);
2670 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE, NULL);
2671 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2672 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2673 GINT_TO_POINTER(FE_DESCRIPTION), NULL);
2674 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2676 column = gtk_tree_view_column_new();
2677 gtk_tree_view_column_set_title(column, _("Class"));
2678 gtk_tree_view_column_set_resizable(column, TRUE);
2679 renderer = gtk_cell_renderer_combo_new();
2680 g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
2681 "model", create_class_model(),
2686 g_signal_connect(G_OBJECT(renderer), "edited",
2687 G_CALLBACK(filter_store_class_edit_cb), filter_store);
2688 gtk_tree_view_column_pack_start(column, renderer, TRUE);
2689 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2690 GINT_TO_POINTER(FE_CLASS), NULL);
2691 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2693 column = gtk_tree_view_column_new();
2694 gtk_tree_view_column_set_title(column, _("Writable"));
2695 gtk_tree_view_column_set_resizable(column, FALSE);
2696 renderer = gtk_cell_renderer_toggle_new();
2697 g_signal_connect(G_OBJECT(renderer), "toggled",
2698 G_CALLBACK(filter_store_writable_cb), filter_store);
2699 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2700 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2701 GINT_TO_POINTER(FE_WRITABLE), NULL);
2702 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2704 column = gtk_tree_view_column_new();
2705 gtk_tree_view_column_set_title(column, _("Sidecar is allowed"));
2706 gtk_tree_view_column_set_resizable(column, FALSE);
2707 renderer = gtk_cell_renderer_toggle_new();
2708 g_signal_connect(G_OBJECT(renderer), "toggled",
2709 G_CALLBACK(filter_store_sidecar_cb), filter_store);
2710 gtk_tree_view_column_pack_start(column, renderer, FALSE);
2711 gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func,
2712 GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL);
2713 gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column);
2716 filter_store_populate();
2717 gtk_container_add(GTK_CONTAINER(scrolled), filter_view);
2718 gtk_widget_show(filter_view);
2720 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
2722 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
2723 G_CALLBACK(filter_default_cb), filter_view);
2724 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2725 gtk_widget_show(button);
2727 button = pref_button_new(NULL, GTK_STOCK_REMOVE, NULL, FALSE,
2728 G_CALLBACK(filter_remove_cb), filter_view);
2729 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2730 gtk_widget_show(button);
2732 button = pref_button_new(NULL, GTK_STOCK_ADD, NULL, FALSE,
2733 G_CALLBACK(filter_add_cb), filter_view);
2734 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
2735 gtk_widget_show(button);
2739 static void config_tab_metadata(GtkWidget *notebook)
2744 GtkWidget *ct_button;
2748 vbox = scrolled_notebook_page(notebook, _("Metadata"));
2751 group = pref_group_new(vbox, FALSE, _("Metadata writing process"), GTK_ORIENTATION_VERTICAL);
2753 label = pref_label_new(group, _("Warning: Geeqie is built without Exiv2. Some options are disabled."));
2755 label = pref_label_new(group, _("Metadata are written in the following order. The process ends after first success."));
2756 #if GTK_CHECK_VERSION(3,16,0)
2757 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2758 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2760 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2763 ct_button = pref_checkbox_new_int(group, _("1) Save metadata in image files, or sidecar files, according to the XMP standard"),
2764 options->metadata.save_in_image_file, &c_options->metadata.save_in_image_file);
2766 gtk_widget_set_sensitive(ct_button, FALSE);
2769 pref_checkbox_new_int(group, _("2) Save metadata in '.metadata' folder, local to image folder (non-standard)"),
2770 options->metadata.enable_metadata_dirs, &c_options->metadata.enable_metadata_dirs);
2772 text = g_strdup_printf(_("3) Save metadata in Geeqie private directory '%s'"), get_metadata_cache_dir());
2773 label = pref_label_new(group, text);
2774 #if GTK_CHECK_VERSION(3,16,0)
2775 gtk_label_set_xalign(GTK_LABEL(label), 0.0);
2776 gtk_label_set_yalign(GTK_LABEL(label), 0.5);
2778 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
2780 gtk_misc_set_padding(GTK_MISC(label), 22, 0);
2783 group = pref_group_new(vbox, FALSE, _("Step 1: Write to image files"), GTK_ORIENTATION_VERTICAL);
2785 gtk_widget_set_sensitive(group, FALSE);
2788 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
2789 pref_checkbox_link_sensitivity(ct_button, hbox);
2791 pref_checkbox_new_int(hbox, _("Store metadata also in legacy IPTC tags (converted according to IPTC4XMP standard)"),
2792 options->metadata.save_legacy_IPTC, &c_options->metadata.save_legacy_IPTC);
2794 pref_checkbox_new_int(hbox, _("Warn if the image files are unwritable"),
2795 options->metadata.warn_on_write_problems, &c_options->metadata.warn_on_write_problems);
2797 pref_checkbox_new_int(hbox, _("Ask before writing to image files"),
2798 options->metadata.confirm_write, &c_options->metadata.confirm_write);
2800 pref_checkbox_new_int(hbox, _("Create sidecar files named image.ext.xmp (as opposed to image.xmp)"),
2801 options->metadata.sidecar_extended_name, &c_options->metadata.sidecar_extended_name);
2803 group = pref_group_new(vbox, FALSE, _("Step 2 and 3: write to Geeqie private files"), GTK_ORIENTATION_VERTICAL);
2805 gtk_widget_set_sensitive(group, FALSE);
2808 pref_checkbox_new_int(group, _("Use GQview legacy metadata format (supports only keywords and comments) instead of XMP"),
2809 options->metadata.save_legacy_format, &c_options->metadata.save_legacy_format);
2812 group = pref_group_new(vbox, FALSE, _("Miscellaneous"), GTK_ORIENTATION_VERTICAL);
2813 pref_checkbox_new_int(group, _("Write the same description tags (keywords, comment, etc.) to all grouped sidecars"),
2814 options->metadata.sync_grouped_files, &c_options->metadata.sync_grouped_files);
2816 pref_checkbox_new_int(group, _("Allow keywords to differ only in case"),
2817 options->metadata.keywords_case_sensitive, &c_options->metadata.keywords_case_sensitive);
2819 ct_button = pref_checkbox_new_int(group, _("Write altered image orientation to the metadata"),
2820 options->metadata.write_orientation, &c_options->metadata.write_orientation);
2822 gtk_widget_set_sensitive(ct_button, FALSE);
2825 group = pref_group_new(vbox, FALSE, _("Auto-save options"), GTK_ORIENTATION_VERTICAL);
2827 ct_button = pref_checkbox_new_int(group, _("Write metadata after timeout"),
2828 options->metadata.confirm_after_timeout, &c_options->metadata.confirm_after_timeout);
2830 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
2831 pref_checkbox_link_sensitivity(ct_button, hbox);
2833 pref_spin_new_int(hbox, _("Timeout (seconds):"), NULL, 0, 900, 1,
2834 options->metadata.confirm_timeout, &c_options->metadata.confirm_timeout);
2836 pref_checkbox_new_int(group, _("Write metadata on image change"),
2837 options->metadata.confirm_on_image_change, &c_options->metadata.confirm_on_image_change);
2839 pref_checkbox_new_int(group, _("Write metadata on directory change"),
2840 options->metadata.confirm_on_dir_change, &c_options->metadata.confirm_on_dir_change);
2842 group = pref_group_new(vbox, FALSE, _("Pre-load metadata"), GTK_ORIENTATION_VERTICAL);
2844 ct_button = pref_checkbox_new_int(group, _("Read metadata in background"),
2845 options->read_metadata_in_idle, &c_options->read_metadata_in_idle);
2846 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");
2851 typedef struct _KeywordFindData KeywordFindData;
2852 struct _KeywordFindData
2859 GtkWidget *button_close;
2860 GtkWidget *button_stop;
2861 GtkWidget *button_start;
2862 GtkWidget *progress;
2870 guint idle_id; /* event source id */
2873 #define KEYWORD_DIALOG_WIDTH 400
2875 static void keywords_find_folder(KeywordFindData *kfd, FileData *dir_fd)
2877 GList *list_d = NULL;
2878 GList *list_f = NULL;
2882 filelist_read(dir_fd, &list_f, &list_d);
2886 filelist_read(dir_fd, &list_f, NULL);
2889 list_f = filelist_filter(list_f, FALSE);
2890 list_d = filelist_filter(list_d, TRUE);
2892 kfd->list = g_list_concat(list_f, kfd->list);
2893 kfd->list_dir = g_list_concat(list_d, kfd->list_dir);
2896 static void keywords_find_reset(KeywordFindData *kfd)
2898 filelist_free(kfd->list);
2901 filelist_free(kfd->list_dir);
2902 kfd->list_dir = NULL;
2905 static void keywords_find_close_cb(GenericDialog *fd, gpointer data)
2907 KeywordFindData *kfd = data;
2909 if (!gtk_widget_get_sensitive(kfd->button_close)) return;
2911 keywords_find_reset(kfd);
2912 generic_dialog_close(kfd->gd);
2916 static void keywords_find_finish(KeywordFindData *kfd)
2918 keywords_find_reset(kfd);
2920 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("done"));
2921 spinner_set_interval(kfd->spinner, -1);
2923 gtk_widget_set_sensitive(kfd->group, TRUE);
2924 gtk_widget_set_sensitive(kfd->button_start, TRUE);
2925 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
2926 gtk_widget_set_sensitive(kfd->button_close, TRUE);
2929 static void keywords_find_stop_cb(GenericDialog *fd, gpointer data)
2931 KeywordFindData *kfd = data;
2933 g_idle_remove_by_data(kfd);
2935 keywords_find_finish(kfd);
2938 static gboolean keywords_find_file(gpointer data)
2940 KeywordFindData *kfd = data;
2942 GtkTextBuffer *buffer;
2950 fd = kfd->list->data;
2951 kfd->list = g_list_remove(kfd->list, fd);
2953 keywords = metadata_read_list(fd, KEYWORD_KEY, METADATA_PLAIN);
2954 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
2958 gtk_text_buffer_get_end_iter(buffer, &iter);
2959 tmp = g_strconcat(keywords->data, "\n", NULL);
2960 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
2962 keywords = keywords->next;
2965 gtk_entry_set_text(GTK_ENTRY(kfd->progress), fd->path);
2966 file_data_unref(fd);
2967 string_list_free(keywords);
2971 else if (kfd->list_dir)
2975 fd = kfd->list_dir->data;
2976 kfd->list_dir = g_list_remove(kfd->list_dir, fd);
2978 keywords_find_folder(kfd, fd);
2980 file_data_unref(fd);
2985 keywords_find_finish(kfd);
2990 static void keywords_find_start_cb(GenericDialog *fd, gpointer data)
2992 KeywordFindData *kfd = data;
2995 if (kfd->list || !gtk_widget_get_sensitive(kfd->button_start)) return;
2997 path = remove_trailing_slash((gtk_entry_get_text(GTK_ENTRY(kfd->entry))));
2998 parse_out_relatives(path);
3002 warning_dialog(_("Invalid folder"),
3003 _("The specified folder can not be found."),
3004 GTK_STOCK_DIALOG_WARNING, kfd->gd->dialog);
3010 gtk_widget_set_sensitive(kfd->group, FALSE);
3011 gtk_widget_set_sensitive(kfd->button_start, FALSE);
3012 gtk_widget_set_sensitive(kfd->button_stop, TRUE);
3013 gtk_widget_set_sensitive(kfd->button_close, FALSE);
3014 spinner_set_interval(kfd->spinner, SPINNER_SPEED);
3016 dir_fd = file_data_new_dir(path);
3017 keywords_find_folder(kfd, dir_fd);
3018 file_data_unref(dir_fd);
3019 kfd->idle_id = g_idle_add(keywords_find_file, kfd);
3025 static void keywords_find_dialog(GtkWidget *widget, const gchar *path)
3027 KeywordFindData *kfd;
3031 kfd = g_new0(KeywordFindData, 1);
3033 kfd->gd = generic_dialog_new(_("Search for keywords"),
3034 "search_for_keywords",
3037 gtk_window_set_default_size(GTK_WINDOW(kfd->gd->dialog), KEYWORD_DIALOG_WIDTH, -1);
3038 kfd->gd->cancel_cb = keywords_find_close_cb;
3039 kfd->button_close = generic_dialog_add_button(kfd->gd, GTK_STOCK_CLOSE, NULL,
3040 keywords_find_close_cb, FALSE);
3041 kfd->button_start = generic_dialog_add_button(kfd->gd, GTK_STOCK_OK, _("S_tart"),
3042 keywords_find_start_cb, FALSE);
3043 kfd->button_stop = generic_dialog_add_button(kfd->gd, GTK_STOCK_STOP, NULL,
3044 keywords_find_stop_cb, FALSE);
3045 gtk_widget_set_sensitive(kfd->button_stop, FALSE);
3047 generic_dialog_add_message(kfd->gd, NULL, _("Search for keywords"), NULL, FALSE);
3049 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
3050 pref_spacer(hbox, PREF_PAD_INDENT);
3051 kfd->group = pref_box_new(hbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
3053 hbox = pref_box_new(kfd->group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3054 pref_label_new(hbox, _("Folder:"));
3056 label = tab_completion_new(&kfd->entry, path, NULL, NULL, NULL, NULL);
3057 tab_completion_add_select_button(kfd->entry,_("Select folder") , TRUE);
3058 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
3059 gtk_widget_show(label);
3061 pref_checkbox_new_int(kfd->group, _("Include subfolders"), FALSE, &kfd->recurse);
3063 pref_line(kfd->gd->vbox, PREF_PAD_SPACE);
3064 hbox = pref_box_new(kfd->gd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3066 kfd->progress = gtk_entry_new();
3067 gtk_widget_set_can_focus(kfd->progress, FALSE);
3068 gtk_editable_set_editable(GTK_EDITABLE(kfd->progress), FALSE);
3069 gtk_entry_set_text(GTK_ENTRY(kfd->progress), _("click start to begin"));
3070 gtk_box_pack_start(GTK_BOX(hbox), kfd->progress, TRUE, TRUE, 0);
3071 gtk_widget_show(kfd->progress);
3073 kfd->spinner = spinner_new(NULL, -1);
3074 gtk_box_pack_start(GTK_BOX(hbox), kfd->spinner, FALSE, FALSE, 0);
3075 gtk_widget_show(kfd->spinner);
3079 gtk_widget_show(kfd->gd->dialog);
3082 static void keywords_find_cb(GtkWidget *widget, gpointer data)
3084 const gchar *path = layout_get_path(NULL);
3086 if (!path || !*path) path = homedir();
3087 keywords_find_dialog(widget, path);
3090 static void config_tab_keywords_save()
3092 GtkTextIter start, end;
3093 GtkTextBuffer *buffer;
3094 GList *kw_list = NULL;
3100 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3101 gtk_text_buffer_get_bounds(buffer, &start, &end);
3103 buffer_text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
3105 kw_split = strtok(buffer_text, "\n");
3106 while (kw_split != NULL)
3112 if (g_strcmp0(work->data, kw_split) == 0)
3121 kw_list = g_list_append(kw_list, g_strdup(kw_split));
3123 kw_split = strtok(NULL, "\n");
3126 keyword_list_set(kw_list);
3128 string_list_free(kw_list);
3129 g_free(buffer_text);
3132 static void config_tab_keywords(GtkWidget *notebook)
3138 GtkWidget *scrolled;
3140 GtkTextBuffer *buffer;
3143 vbox = scrolled_notebook_page(notebook, _("Keywords"));
3145 group = pref_group_new(vbox, TRUE, _("Edit keywords autocompletion list"), GTK_ORIENTATION_VERTICAL);
3147 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3149 button = pref_button_new(hbox, GTK_STOCK_EXECUTE, _("Search"), FALSE,
3150 G_CALLBACK(keywords_find_cb), keyword_text);
3151 gtk_widget_set_tooltip_text(button, "Search for existing keywords");
3154 keyword_text = gtk_text_view_new();
3155 gtk_widget_set_size_request(keyword_text, 20, 20);
3156 scrolled = gtk_scrolled_window_new(NULL, NULL);
3157 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3158 gtk_widget_show(scrolled);
3160 gtk_container_add(GTK_CONTAINER(scrolled), keyword_text);
3161 gtk_widget_show(keyword_text);
3163 gtk_text_view_set_editable(GTK_TEXT_VIEW(keyword_text), TRUE);
3165 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(keyword_text));
3166 gtk_text_buffer_create_tag(buffer, "monospace",
3167 "family", "monospace", NULL);
3169 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(keyword_text), GTK_WRAP_WORD);
3170 gtk_text_buffer_get_start_iter(buffer, &iter);
3171 gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
3174 path = g_build_filename(get_rc_dir(), "keywords", NULL);
3176 GList *kwl = keyword_list_get();
3177 kwl = g_list_first(kwl);
3180 gtk_text_buffer_get_end_iter (buffer, &iter);
3181 tmp = g_strconcat(kwl->data, "\n", NULL);
3182 gtk_text_buffer_insert(buffer, &iter, tmp, -1);
3187 gtk_text_buffer_set_modified(buffer, FALSE);
3194 static void intent_menu_cb(GtkWidget *combo, gpointer data)
3196 gint *option = data;
3198 switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
3202 *option = INTENT_PERCEPTUAL;
3205 *option = INTENT_RELATIVE_COLORIMETRIC;
3208 *option = INTENT_SATURATION;
3211 *option = INTENT_ABSOLUTE_COLORIMETRIC;
3216 static void add_intent_menu(GtkWidget *table, gint column, gint row, const gchar *text,
3217 gint option, gint *option_c)
3224 pref_table_label(table, column, row, text, 0.0);
3226 combo = gtk_combo_box_text_new();
3228 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Perceptual"));
3229 if (option == INTENT_PERCEPTUAL) current = 0;
3230 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Relative Colorimetric"));
3231 if (option == INTENT_RELATIVE_COLORIMETRIC) current = 1;
3232 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Saturation"));
3233 if (option == INTENT_SATURATION) current = 2;
3234 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Absolute Colorimetric"));
3235 if (option == INTENT_ABSOLUTE_COLORIMETRIC) current = 3;
3237 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), current);
3239 gtk_widget_set_tooltip_text(combo,"Refer to the lcms documentation for the defaults used when the selected Intent is not available");
3241 g_signal_connect(G_OBJECT(combo), "changed",
3242 G_CALLBACK(intent_menu_cb), option_c);
3244 gtk_table_attach(GTK_TABLE(table), combo, column + 1, column + 2, row, row + 1, GTK_SHRINK, 0, 0, 0);
3245 gtk_widget_show(combo);
3249 static void config_tab_color(GtkWidget *notebook)
3258 vbox = scrolled_notebook_page(notebook, _("Color management"));
3260 group = pref_group_new(vbox, FALSE, _("Input profiles"), GTK_ORIENTATION_VERTICAL);
3262 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3265 table = pref_table_new(group, 3, COLOR_PROFILE_INPUTS + 1, FALSE, FALSE);
3266 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
3268 label = pref_table_label(table, 0, 0, _("Type"), 0.0);
3269 pref_label_bold(label, TRUE, FALSE);
3271 label = pref_table_label(table, 1, 0, _("Menu name"), 0.0);
3272 pref_label_bold(label, TRUE, FALSE);
3274 label = pref_table_label(table, 2, 0, _("File"), 0.0);
3275 pref_label_bold(label, TRUE, FALSE);
3277 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
3282 buf = g_strdup_printf(_("Input %d:"), i + COLOR_PROFILE_FILE);
3283 pref_table_label(table, 0, i + 1, buf, 1.0);
3286 entry = gtk_entry_new();
3287 gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH);
3288 if (options->color_profile.input_name[i])
3290 gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]);
3292 gtk_table_attach(GTK_TABLE(table), entry, 1, 2, i + 1, i + 2,
3293 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3294 gtk_widget_show(entry);
3295 color_profile_input_name_entry[i] = entry;
3297 tabcomp = tab_completion_new(&entry, options->color_profile.input_file[i], NULL, ".icc", "ICC Files", NULL);
3298 tab_completion_add_select_button(entry, _("Select color profile"), FALSE);
3299 gtk_widget_set_size_request(entry, 160, -1);
3300 gtk_table_attach(GTK_TABLE(table), tabcomp, 2, 3, i + 1, i + 2,
3301 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3302 gtk_widget_show(tabcomp);
3303 color_profile_input_file_entry[i] = entry;
3306 group = pref_group_new(vbox, FALSE, _("Screen profile"), GTK_ORIENTATION_VERTICAL);
3308 gtk_widget_set_sensitive(pref_group_parent(group), FALSE);
3310 pref_checkbox_new_int(group, _("Use system screen profile if available"),
3311 options->color_profile.use_x11_screen_profile, &c_options->color_profile.use_x11_screen_profile);
3313 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3315 pref_table_label(table, 0, 0, _("Screen:"), 1.0);
3316 tabcomp = tab_completion_new(&color_profile_screen_file_entry,
3317 options->color_profile.screen_file, NULL, ".icc", "ICC Files", NULL);
3318 tab_completion_add_select_button(color_profile_screen_file_entry, _("Select color profile"), FALSE);
3319 gtk_widget_set_size_request(color_profile_screen_file_entry, 160, -1);
3321 add_intent_menu(table, 0, 1, _("Render Intent:"), options->color_profile.render_intent, &c_options->color_profile.render_intent);
3323 gtk_table_attach(GTK_TABLE(table), tabcomp, 1, 2,
3325 GTK_FILL | GTK_EXPAND, 0, 0, 0);
3327 gtk_widget_show(tabcomp);
3330 /* advanced entry tab */
3331 static void use_geeqie_trash_cb(GtkWidget *widget, gpointer data)
3333 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3335 c_options->file_ops.use_system_trash = FALSE;
3336 c_options->file_ops.no_trash = FALSE;
3340 static void use_system_trash_cb(GtkWidget *widget, gpointer data)
3342 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3344 c_options->file_ops.use_system_trash = TRUE;
3345 c_options->file_ops.no_trash = FALSE;
3349 static void use_no_cache_cb(GtkWidget *widget, gpointer data)
3351 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
3353 c_options->file_ops.no_trash = TRUE;
3357 static void config_tab_behavior(GtkWidget *notebook)
3364 GtkWidget *ct_button;
3368 GtkWidget *with_rename;
3369 GtkWidget *collections_on_top;
3370 GtkWidget *hide_window_in_fullscreen;
3371 GtkWidget *checkbox;
3374 vbox = scrolled_notebook_page(notebook, _("Behavior"));
3376 group = pref_group_new(vbox, FALSE, _("Delete"), GTK_ORIENTATION_VERTICAL);
3378 pref_checkbox_new_int(group, _("Confirm permanent file delete"),
3379 options->file_ops.confirm_delete, &c_options->file_ops.confirm_delete);
3380 pref_checkbox_new_int(group, _("Confirm move file to Trash"),
3381 options->file_ops.confirm_move_to_trash, &c_options->file_ops.confirm_move_to_trash);
3382 pref_checkbox_new_int(group, _("Enable Delete key"),
3383 options->file_ops.enable_delete_key, &c_options->file_ops.enable_delete_key);
3385 ct_button = pref_radiobutton_new(group, NULL, _("Use Geeqie trash location"),
3386 !options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_geeqie_trash_cb),NULL);
3388 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE);
3389 pref_checkbox_link_sensitivity(ct_button, hbox);
3391 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_SPACE);
3392 pref_label_new(hbox, _("Folder:"));
3394 tabcomp = tab_completion_new(&safe_delete_path_entry, options->file_ops.safe_delete_path, NULL, NULL, NULL, NULL);
3395 tab_completion_add_select_button(safe_delete_path_entry, NULL, TRUE);
3396 gtk_box_pack_start(GTK_BOX(hbox), tabcomp, TRUE, TRUE, 0);
3397 gtk_widget_show(tabcomp);
3399 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3400 pref_checkbox_link_sensitivity(ct_button, hbox);
3402 pref_spacer(hbox, PREF_PAD_INDENT - PREF_PAD_GAP);
3403 spin = pref_spin_new_int(hbox, _("Maximum size:"), _("MiB"),
3404 0, 2048, 1, options->file_ops.safe_delete_folder_maxsize, &c_options->file_ops.safe_delete_folder_maxsize);
3405 gtk_widget_set_tooltip_markup(spin, _("Set to 0 for unlimited size"));
3406 button = pref_button_new(NULL, NULL, _("View"), FALSE,
3407 G_CALLBACK(safe_delete_view_cb), NULL);
3408 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3409 gtk_widget_show(button);
3411 button = pref_button_new(NULL, GTK_STOCK_CLEAR, NULL, FALSE,
3412 G_CALLBACK(safe_delete_clear_cb), NULL);
3413 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3414 pref_radiobutton_new(group, ct_button, _("Use system Trash bin"),
3415 options->file_ops.use_system_trash && !options->file_ops.no_trash, G_CALLBACK(use_system_trash_cb), NULL);
3417 pref_radiobutton_new(group, ct_button, _("Use no trash at all"),
3418 options->file_ops.no_trash, G_CALLBACK(use_no_cache_cb), NULL);
3420 gtk_widget_show(button);
3422 pref_spacer(group, PREF_PAD_GROUP);
3425 group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
3427 pref_checkbox_new_int(group, _("Descend folders in tree view"),
3428 options->tree_descend_subdirs, &c_options->tree_descend_subdirs);
3430 pref_checkbox_new_int(group, _("In place renaming"),
3431 options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
3433 pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
3434 options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
3436 tmp = pref_checkbox_new_int(group, _("Circular selection lists"),
3437 options->circular_selection_lists, &c_options->circular_selection_lists);
3438 gtk_widget_set_tooltip_text(tmp, _("Traverse selection lists in a circular manner"));
3440 marks = pref_checkbox_new_int(group, _("Save marks on exit"),
3441 options->marks_save, &c_options->marks_save);
3442 gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
3444 with_rename = pref_checkbox_new_int(group, _("Use \"With Rename\" as default for Copy/Move dialogs"),
3445 options->with_rename, &c_options->with_rename);
3446 gtk_widget_set_tooltip_text(with_rename,"Change the default button for Copy/Move dialogs");
3448 collections_on_top = pref_checkbox_new_int(group, _("Open collections on top"),
3449 options->collections_on_top, &c_options->collections_on_top);
3450 gtk_widget_set_tooltip_text(collections_on_top,"Open collections window on top");
3452 hide_window_in_fullscreen = pref_checkbox_new_int(group, _("Hide window in fullscreen"),
3453 options->hide_window_in_fullscreen, &c_options->hide_window_in_fullscreen);
3454 gtk_widget_set_tooltip_text(hide_window_in_fullscreen,"When alt-tabbing, prevent Geeqie window showing twice");
3456 pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
3457 1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
3459 pref_spin_new_int(group, _("Drag'n drop icon size"), NULL,
3460 16, 256, 16, options->dnd_icon_size, &c_options->dnd_icon_size);
3462 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3463 add_dnd_default_action_selection_menu(table, 0, 0, _("Drag`n drop default action:"), options->dnd_default_action, &c_options->dnd_default_action);
3465 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3466 add_clipboard_selection_menu(table, 0, 0, _("Copy path clipboard selection:"), options->clipboard_selection, &c_options->clipboard_selection);
3468 pref_spacer(group, PREF_PAD_GROUP);
3470 group = pref_group_new(vbox, FALSE, _("Navigation"), GTK_ORIENTATION_VERTICAL);
3472 pref_checkbox_new_int(group, _("Progressive keyboard scrolling"),
3473 options->progressive_key_scrolling, &c_options->progressive_key_scrolling);
3474 pref_spin_new_int(group, _("Keyboard scrolling step multiplier:"), NULL,
3475 1, 32, 1, options->keyboard_scroll_step, (int *)&c_options->keyboard_scroll_step);
3476 pref_checkbox_new_int(group, _("Mouse wheel scrolls image"),
3477 options->mousewheel_scrolls, &c_options->mousewheel_scrolls);
3478 pref_checkbox_new_int(group, _("Navigation by left or middle click on image"),
3479 options->image_lm_click_nav, &c_options->image_lm_click_nav);
3480 pref_checkbox_new_int(group, _("Play video by left click on image"),
3481 options->image_l_click_video, &c_options->image_l_click_video);
3482 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3483 add_video_menu(table, 0, 0, _("Play with:"), options->image_l_click_video_editor, &c_options->image_l_click_video_editor);
3485 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3486 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3487 add_mouse_selection_menu(table, 0, 0, _("Mouse button Back:"), options->mouse_button_8, &c_options->mouse_button_8);
3488 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3489 add_mouse_selection_menu(table, 0, 0, _("Mouse button Forward:"), options->mouse_button_9, &c_options->mouse_button_9);
3491 pref_spacer(group, PREF_PAD_GROUP);
3493 group = pref_group_new(vbox, FALSE, _("GPU"), GTK_ORIENTATION_VERTICAL);
3495 checkbox = pref_checkbox_new_int(group, _("Override disable GPU"),
3496 options->override_disable_gpu, &c_options->override_disable_gpu);
3497 gtk_widget_set_tooltip_text(checkbox, "Contact the developers for usage");
3500 pref_spacer(group, PREF_PAD_GROUP);
3502 group = pref_group_new(vbox, FALSE, _("Debugging"), GTK_ORIENTATION_VERTICAL);
3504 pref_spin_new_int(group, _("Debug level:"), NULL,
3505 DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX, 1, get_debug_level(), &debug_c);
3507 pref_checkbox_new_int(group, _("Timer data"),
3508 options->log_window.timer_data, &c_options->log_window.timer_data);
3510 pref_spin_new_int(group, _("Log Window max. lines:"), NULL,
3511 1, 99999, 1, options->log_window_lines, &options->log_window_lines);
3515 /* accelerators tab */
3516 static void config_tab_accelerators(GtkWidget *notebook)
3522 GtkWidget *scrolled;
3523 GtkWidget *accel_view;
3524 GtkCellRenderer *renderer;
3525 GtkTreeSelection *selection;
3526 GtkTreeViewColumn *column;
3528 vbox = scrolled_notebook_page(notebook, _("Keyboard"));
3530 group = pref_group_new(vbox, TRUE, _("Accelerators"), GTK_ORIENTATION_VERTICAL);
3532 scrolled = gtk_scrolled_window_new(NULL, NULL);
3533 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
3534 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3535 gtk_box_pack_start(GTK_BOX(group), scrolled, TRUE, TRUE, 0);
3536 gtk_widget_show(scrolled);
3538 accel_store = gtk_tree_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
3540 accel_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(accel_store));
3541 g_object_unref(accel_store);
3542 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(accel_view));
3543 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
3545 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(accel_view), FALSE);
3547 renderer = gtk_cell_renderer_text_new();
3549 column = gtk_tree_view_column_new_with_attributes(_("Action"),
3554 gtk_tree_view_column_set_sort_column_id(column, AE_ACTION);
3555 gtk_tree_view_column_set_resizable(column, TRUE);
3556 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3559 renderer = gtk_cell_renderer_accel_new();
3560 g_signal_connect(G_OBJECT(renderer), "accel-cleared",
3561 G_CALLBACK(accel_store_cleared_cb), accel_store);
3562 g_signal_connect(G_OBJECT(renderer), "accel-edited",
3563 G_CALLBACK(accel_store_edited_cb), accel_store);
3566 g_object_set (renderer,
3568 "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
3571 column = gtk_tree_view_column_new_with_attributes(_("KEY"),
3576 gtk_tree_view_column_set_sort_column_id(column, AE_KEY);
3577 gtk_tree_view_column_set_resizable(column, TRUE);
3578 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3580 renderer = gtk_cell_renderer_text_new();
3582 column = gtk_tree_view_column_new_with_attributes(_("Tooltip"),
3587 gtk_tree_view_column_set_sort_column_id(column, AE_TOOLTIP);
3588 gtk_tree_view_column_set_resizable(column, TRUE);
3589 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3591 renderer = gtk_cell_renderer_text_new();
3593 column = gtk_tree_view_column_new_with_attributes("Accel",
3598 gtk_tree_view_column_set_sort_column_id(column, AE_ACCEL);
3599 gtk_tree_view_column_set_resizable(column, TRUE);
3600 gtk_tree_view_append_column(GTK_TREE_VIEW(accel_view), column);
3602 accel_store_populate();
3603 gtk_container_add(GTK_CONTAINER(scrolled), accel_view);
3604 gtk_widget_show(accel_view);
3606 hbox = pref_box_new(group, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_BUTTON_GAP);
3608 button = pref_button_new(NULL, NULL, _("Defaults"), FALSE,
3609 G_CALLBACK(accel_default_cb), accel_view);
3610 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3611 gtk_widget_show(button);
3613 button = pref_button_new(NULL, NULL, _("Reset selected"), FALSE,
3614 G_CALLBACK(accel_reset_cb), accel_view);
3615 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
3616 gtk_widget_show(button);
3619 /* toolbar main tab */
3620 static void config_tab_toolbar_main(GtkWidget *notebook)
3623 GtkWidget *toolbardata;
3626 lw = layout_window_list->data;
3628 vbox = scrolled_notebook_page(notebook, _("Toolbar Main"));
3630 toolbardata = toolbar_select_new(lw, TOOLBAR_MAIN);
3631 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3632 gtk_widget_show(vbox);
3635 /* toolbar status tab */
3636 static void config_tab_toolbar_status(GtkWidget *notebook)
3639 GtkWidget *toolbardata;
3642 lw = layout_window_list->data;
3644 vbox = scrolled_notebook_page(notebook, _("Toolbar Status"));
3646 toolbardata = toolbar_select_new(lw, TOOLBAR_STATUS);
3647 gtk_box_pack_start(GTK_BOX(vbox), toolbardata, TRUE, TRUE, 0);
3648 gtk_widget_show(vbox);
3652 static gint extension_sort_cb(gconstpointer a, gconstpointer b)
3654 return g_strcmp0((gchar *)a, (gchar *)b);
3657 static void config_tab_advanced(GtkWidget *notebook)
3661 GSList *formats_list;
3662 GList *extensions_list = NULL;
3665 GdkPixbufFormat *fm;
3667 GString *types_string = g_string_new(NULL);
3668 GtkWidget *types_string_label;
3669 GtkWidget *threads_string_label;
3670 GtkWidget *dupes_threads_spin;
3672 vbox = scrolled_notebook_page(notebook, _("Advanced"));
3673 group = pref_group_new(vbox, FALSE, _("External preview extraction"), GTK_ORIENTATION_VERTICAL);
3675 pref_checkbox_new_int(group, _("Use external preview extraction - Requires restart"), options->external_preview.enable, &c_options->external_preview.enable);
3677 pref_spacer(group, PREF_PAD_GROUP);
3679 formats_list = gdk_pixbuf_get_formats();
3681 while (formats_list)
3683 fm = formats_list->data;
3684 extensions = gdk_pixbuf_format_get_extensions(fm);
3687 while (extensions[i])
3689 extensions_list = g_list_insert_sorted(extensions_list, g_strdup(extensions[i]), extension_sort_cb);
3693 g_strfreev(extensions);
3694 formats_list = formats_list->next;
3697 while (extensions_list)
3699 if (types_string->len == 0)
3701 types_string = g_string_append(types_string, extensions_list->data);
3705 types_string = g_string_append(types_string, ", ");
3706 types_string = g_string_append(types_string, extensions_list->data);
3709 extensions_list = extensions_list->next;
3712 types_string = g_string_prepend(types_string, _("Usable file types:\n"));
3713 types_string_label = pref_label_new(group, types_string->str);
3714 gtk_label_set_line_wrap(GTK_LABEL(types_string_label), TRUE);
3716 pref_spacer(group, PREF_PAD_GROUP);
3718 group = pref_group_new(vbox, FALSE, _("File identification tool"), GTK_ORIENTATION_VERTICAL);
3719 external_preview_select_entry = gtk_entry_new();
3720 tabcomp = tab_completion_new(&external_preview_select_entry, options->external_preview.select, NULL, NULL, NULL, NULL);
3721 tab_completion_add_select_button(external_preview_select_entry, _("Select file identification tool"), FALSE);
3722 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3723 gtk_widget_show(tabcomp);
3725 group = pref_group_new(vbox, FALSE, _("Preview extraction tool"), GTK_ORIENTATION_VERTICAL);
3726 external_preview_extract_entry = gtk_entry_new();
3727 tabcomp = tab_completion_new(&external_preview_extract_entry, options->external_preview.extract, NULL, NULL, NULL, NULL);
3728 tab_completion_add_select_button(external_preview_extract_entry, _("Select preview extraction tool"), FALSE);
3729 gtk_box_pack_start(GTK_BOX(group), tabcomp, TRUE, TRUE, 0);
3730 gtk_widget_show(tabcomp);
3732 gtk_widget_show(vbox);
3734 g_slist_free(formats_list);
3735 string_list_free(extensions_list);
3736 g_string_free(types_string, TRUE);
3738 pref_spacer(group, PREF_PAD_GROUP);
3740 pref_line(vbox, PREF_PAD_SPACE);
3741 group = pref_group_new(vbox, FALSE, _("Thread pool limits"), GTK_ORIENTATION_VERTICAL);
3743 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.");
3744 gtk_label_set_line_wrap(GTK_LABEL(threads_string_label), TRUE);
3746 pref_spacer(vbox, PREF_PAD_GROUP);
3748 dupes_threads_spin = pref_spin_new_int(vbox, _("Duplicate check:"), _("max. threads"), 0, get_cpu_cores(), 1, options->threads.duplicates, &c_options->threads.duplicates);
3749 gtk_widget_set_tooltip_markup(dupes_threads_spin, _("Set to 0 for unlimited"));
3753 static void config_tab_stereo(GtkWidget *notebook)
3761 GtkWidget *fs_button;
3762 vbox = scrolled_notebook_page(notebook, _("Stereo"));
3764 group = pref_group_new(vbox, FALSE, _("Windowed stereo mode"), GTK_ORIENTATION_VERTICAL);
3766 table = pref_table_new(group, 2, 1, FALSE, FALSE);
3767 add_stereo_mode_menu(table, 0, 0, _("Windowed stereo mode"), options->stereo.mode, &c_options->stereo.mode, FALSE);
3769 table = pref_table_new(group, 2, 2, TRUE, FALSE);
3770 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3771 pref_checkbox_new_int(box, _("Mirror left image"),
3772 options->stereo.mode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.mirror_left);
3773 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3774 pref_checkbox_new_int(box, _("Flip left image"),
3775 options->stereo.mode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.flip_left);
3776 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3777 pref_checkbox_new_int(box, _("Mirror right image"),
3778 options->stereo.mode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.mirror_right);
3779 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3780 pref_checkbox_new_int(box, _("Flip right image"),
3781 options->stereo.mode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.flip_right);
3782 pref_checkbox_new_int(group, _("Swap left and right images"),
3783 options->stereo.mode & PR_STEREO_SWAP, &c_options->stereo.tmp.swap);
3784 pref_checkbox_new_int(group, _("Disable stereo mode on single image source"),
3785 options->stereo.mode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.temp_disable);
3787 group = pref_group_new(vbox, FALSE, _("Fullscreen stereo mode"), GTK_ORIENTATION_VERTICAL);
3788 fs_button = pref_checkbox_new_int(group, _("Use different settings for fullscreen"),
3789 options->stereo.enable_fsmode, &c_options->stereo.enable_fsmode);
3790 box2 = pref_box_new(group, FALSE, GTK_ORIENTATION_VERTICAL, PREF_PAD_SPACE);
3791 pref_checkbox_link_sensitivity(fs_button, box2);
3792 table = pref_table_new(box2, 2, 1, FALSE, FALSE);
3793 add_stereo_mode_menu(table, 0, 0, _("Fullscreen stereo mode"), options->stereo.fsmode, &c_options->stereo.fsmode, TRUE);
3794 table = pref_table_new(box2, 2, 2, TRUE, FALSE);
3795 box = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3796 pref_checkbox_new_int(box, _("Mirror left image"),
3797 options->stereo.fsmode & PR_STEREO_MIRROR_LEFT, &c_options->stereo.tmp.fs_mirror_left);
3798 box = pref_table_box(table, 1, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
3799 pref_checkbox_new_int(box, _("Flip left image"),
3800 options->stereo.fsmode & PR_STEREO_FLIP_LEFT, &c_options->stereo.tmp.fs_flip_left);
3801 box = pref_table_box(table, 0, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3802 pref_checkbox_new_int(box, _("Mirror right image"),
3803 options->stereo.fsmode & PR_STEREO_MIRROR_RIGHT, &c_options->stereo.tmp.fs_mirror_right);
3804 box = pref_table_box(table, 1, 1, GTK_ORIENTATION_HORIZONTAL, NULL);
3805 pref_checkbox_new_int(box, _("Flip right image"),
3806 options->stereo.fsmode & PR_STEREO_FLIP_RIGHT, &c_options->stereo.tmp.fs_flip_right);
3807 pref_checkbox_new_int(box2, _("Swap left and right images"),
3808 options->stereo.fsmode & PR_STEREO_SWAP, &c_options->stereo.tmp.fs_swap);
3809 pref_checkbox_new_int(box2, _("Disable stereo mode on single image source"),
3810 options->stereo.fsmode & PR_STEREO_TEMP_DISABLE, &c_options->stereo.tmp.fs_temp_disable);
3812 group2 = pref_group_new(box2, FALSE, _("Fixed position"), GTK_ORIENTATION_VERTICAL);
3813 table = pref_table_new(group2, 5, 3, FALSE, FALSE);
3814 pref_table_spin_new_int(table, 0, 0, _("Width"), NULL,
3815 1, 5000, 1, options->stereo.fixed_w, &c_options->stereo.fixed_w);
3816 pref_table_spin_new_int(table, 3, 0, _("Height"), NULL,
3817 1, 5000, 1, options->stereo.fixed_h, &c_options->stereo.fixed_h);
3818 pref_table_spin_new_int(table, 0, 1, _("Left X"), NULL,
3819 0, 5000, 1, options->stereo.fixed_x1, &c_options->stereo.fixed_x1);
3820 pref_table_spin_new_int(table, 3, 1, _("Left Y"), NULL,
3821 0, 5000, 1, options->stereo.fixed_y1, &c_options->stereo.fixed_y1);
3822 pref_table_spin_new_int(table, 0, 2, _("Right X"), NULL,
3823 0, 5000, 1, options->stereo.fixed_x2, &c_options->stereo.fixed_x2);
3824 pref_table_spin_new_int(table, 3, 2, _("Right Y"), NULL,
3825 0, 5000, 1, options->stereo.fixed_y2, &c_options->stereo.fixed_y2);
3829 /* Main preferences window */
3830 static void config_window_create(LayoutWindow *lw)
3832 GtkWidget *win_vbox;
3834 GtkWidget *notebook;
3836 GtkWidget *ct_button;
3838 if (!c_options) c_options = init_options(NULL);
3840 configwindow = window_new(GTK_WINDOW_TOPLEVEL, "preferences", PIXBUF_INLINE_ICON_CONFIG, NULL, _("Preferences"));
3841 DEBUG_NAME(configwindow);
3842 gtk_window_set_type_hint(GTK_WINDOW(configwindow), GDK_WINDOW_TYPE_HINT_DIALOG);
3843 g_signal_connect(G_OBJECT(configwindow), "delete_event",
3844 G_CALLBACK(config_window_delete), NULL);
3845 if (options->save_dialog_window_positions)
3847 gtk_window_resize(GTK_WINDOW(configwindow), lw->options.preferences_window.w, lw->options.preferences_window.h);
3848 gtk_window_move(GTK_WINDOW(configwindow), lw->options.preferences_window.x, lw->options.preferences_window.y);
3852 gtk_window_set_default_size(GTK_WINDOW(configwindow), CONFIG_WINDOW_DEF_WIDTH, CONFIG_WINDOW_DEF_HEIGHT);
3854 gtk_window_set_resizable(GTK_WINDOW(configwindow), TRUE);
3855 gtk_container_set_border_width(GTK_CONTAINER(configwindow), PREF_PAD_BORDER);
3857 win_vbox = gtk_vbox_new(FALSE, PREF_PAD_SPACE);
3858 gtk_container_add(GTK_CONTAINER(configwindow), win_vbox);
3859 gtk_widget_show(win_vbox);
3861 notebook = gtk_notebook_new();
3862 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_LEFT);
3863 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
3864 gtk_box_pack_start(GTK_BOX(win_vbox), notebook, TRUE, TRUE, 0);
3866 config_tab_general(notebook);
3867 config_tab_image(notebook);
3868 config_tab_osd(notebook);
3869 config_tab_windows(notebook);
3870 config_tab_accelerators(notebook);
3871 config_tab_files(notebook);
3872 config_tab_metadata(notebook);
3873 config_tab_keywords(notebook);
3874 config_tab_color(notebook);
3875 config_tab_stereo(notebook);
3876 config_tab_behavior(notebook);
3877 config_tab_toolbar_main(notebook);
3878 config_tab_toolbar_status(notebook);
3879 config_tab_advanced(notebook);
3881 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), lw->options.preferences_window.page_number);
3883 hbox = gtk_hbutton_box_new();
3884 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
3885 gtk_box_set_spacing(GTK_BOX(hbox), PREF_PAD_BUTTON_GAP);
3886 gtk_box_pack_end(GTK_BOX(win_vbox), hbox, FALSE, FALSE, 0);
3887 gtk_widget_show(hbox);
3889 button = pref_button_new(NULL, GTK_STOCK_HELP, NULL, FALSE,
3890 G_CALLBACK(config_window_help_cb), notebook);
3891 gtk_container_add(GTK_CONTAINER(hbox), button);
3892 gtk_widget_set_can_default(button, TRUE);
3893 gtk_widget_show(button);
3895 button = pref_button_new(NULL, GTK_STOCK_OK, NULL, FALSE,
3896 G_CALLBACK(config_window_ok_cb), notebook);
3897 gtk_container_add(GTK_CONTAINER(hbox), button);
3898 gtk_widget_set_can_default(button, TRUE);
3899 gtk_widget_grab_default(button);
3900 gtk_widget_show(button);
3904 button = pref_button_new(NULL, GTK_STOCK_CANCEL, NULL, FALSE,
3905 G_CALLBACK(config_window_close_cb), NULL);
3906 gtk_container_add(GTK_CONTAINER(hbox), button);
3907 gtk_widget_set_can_default(button, TRUE);
3908 gtk_widget_show(button);
3910 if (!generic_dialog_get_alternative_button_order(configwindow))
3912 gtk_box_reorder_child(GTK_BOX(hbox), ct_button, -1);
3915 gtk_widget_show(notebook);
3917 gtk_widget_show(configwindow);
3921 *-----------------------------------------------------------------------------
3922 * config window show (public)
3923 *-----------------------------------------------------------------------------
3926 void show_config_window(LayoutWindow *lw)
3930 gtk_window_present(GTK_WINDOW(configwindow));
3934 config_window_create(lw);
3943 void show_about_window(LayoutWindow *lw)
3945 GdkPixbuf *pixbuf_logo;
3946 GdkPixbuf *pixbuf_icon;
3947 gchar *authors[1000];
3952 gchar *timezone_path;
3956 #define LINE_LENGTH 1000
3957 gchar line[LINE_LENGTH];
3959 copyright = g_string_new(NULL);
3960 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");
3962 path = path_from_utf8(TIMEZONE_DATABASE);
3963 basename = g_path_get_basename(path);
3964 timezone_path = g_build_filename(get_rc_dir(), basename, NULL);
3965 if (g_file_test(timezone_path, G_FILE_TEST_EXISTS))
3967 cd = ZDOpenDatabase(timezone_path);
3970 copyright = g_string_append(copyright, ZDGetNotice(cd));
3971 ZDCloseDatabase(cd);
3975 g_free(timezone_path);
3979 path = g_build_filename(gq_helpdir, "AUTHORS", NULL);
3980 fp = fopen(path, "r");
3983 while(fgets(line, LINE_LENGTH, fp))
3985 /* get rid of ending \n from fgets */
3986 line[strlen(line) - 1] = '\0';
3987 authors[i_authors] = g_strdup(line);
3990 authors[i_authors] = NULL;
3995 comment = g_strconcat("Development and bug reports:\n", GQ_EMAIL_ADDRESS,
3996 "\nhttps://github.com/BestImageViewer/geeqie/issues",NULL);
3998 pixbuf_logo = pixbuf_inline(PIXBUF_INLINE_LOGO);
3999 pixbuf_icon = pixbuf_inline(PIXBUF_INLINE_ICON);
4000 gtk_show_about_dialog(GTK_WINDOW(lw->window),
4001 "title", _("About Geeqie"),
4003 "program-name", GQ_APPNAME,
4005 "logo", pixbuf_logo,
4006 "icon", pixbuf_icon,
4007 "website", GQ_WEBSITE,
4008 "website-label", "Website",
4009 "comments", comment,
4011 "translator-credits", _("translator-credits"),
4012 "wrap-license", TRUE,
4013 "license", copyright->str,
4016 g_string_free(copyright, TRUE);
4019 while(n < i_authors)
4029 static void image_overlay_set_text_colours()
4031 c_options->image_overlay.text_red = options->image_overlay.text_red;
4032 c_options->image_overlay.text_green = options->image_overlay.text_green;
4033 c_options->image_overlay.text_blue = options->image_overlay.text_blue;
4034 c_options->image_overlay.text_alpha = options->image_overlay.text_alpha;
4035 c_options->image_overlay.background_red = options->image_overlay.background_red;
4036 c_options->image_overlay.background_green = options->image_overlay.background_green;
4037 c_options->image_overlay.background_blue = options->image_overlay.background_blue;
4038 c_options->image_overlay.background_alpha = options->image_overlay.background_alpha;
4042 *-----------------------------------------------------------------------------
4043 * timezone database routines
4044 *-----------------------------------------------------------------------------
4047 static void timezone_async_ready_cb(GObject *source_object, GAsyncResult *res, gpointer data)
4049 GError *error = NULL;
4051 gchar *tmp_filename;
4053 if (!g_cancellable_is_cancelled(tz->cancellable))
4055 generic_dialog_close(tz->gd);
4059 if (g_file_copy_finish(G_FILE(source_object), res, &error))
4061 tmp_filename = g_file_get_parse_name(tz->tmp_g_file);
4062 move_file(tmp_filename, tz->timezone_database_user);
4063 g_free(tmp_filename);
4067 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4070 g_file_delete(tz->tmp_g_file, NULL, &error);
4071 g_object_unref(tz->tmp_g_file);
4072 tz->tmp_g_file = NULL;
4073 g_object_unref(tz->cancellable);
4074 g_object_unref(tz->timezone_database_gq);
4077 static void timezone_progress_cb(goffset current_num_bytes, goffset total_num_bytes, gpointer data)
4081 if (!g_cancellable_is_cancelled(tz->cancellable))
4083 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(tz->progress), (gdouble)current_num_bytes / total_num_bytes);
4087 static void timezone_cancel_button_cb(GenericDialog *gd, gpointer data)
4091 g_cancellable_cancel(tz->cancellable);
4094 static void timezone_database_install_cb(GtkWidget *widget, gpointer data)
4097 GError *error = NULL;
4098 GFileIOStream *io_stream;
4105 tz->tmp_g_file = g_file_new_tmp("geeqie_timezone_XXXXXX", &io_stream, &error);
4109 file_util_warning_dialog(_("Timezone database download failed"), error->message, GTK_STOCK_DIALOG_ERROR, NULL);
4110 log_printf("Error: Download timezone database failed:\n%s", error->message);
4111 g_error_free(error);
4112 g_object_unref(tz->tmp_g_file);
4116 tz->timezone_database_gq = g_file_new_for_uri(TIMEZONE_DATABASE);
4118 tz->gd = generic_dialog_new(_("Timezone database"), "download_timezone_database", NULL, TRUE, timezone_cancel_button_cb, tz);
4120 generic_dialog_add_message(tz->gd, GTK_STOCK_DIALOG_INFO, _("Downloading timezone database"), NULL, FALSE);
4122 tz->progress = gtk_progress_bar_new();
4123 gtk_box_pack_start(GTK_BOX(tz->gd->vbox), tz->progress, FALSE, FALSE, 0);
4124 gtk_widget_show(tz->progress);
4126 gtk_widget_show(tz->gd->dialog);
4127 tz->cancellable = g_cancellable_new();
4128 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);
4130 gtk_button_set_label(GTK_BUTTON(widget), _("Update"));
4133 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */