7 * This software is released under the GNU General Public License (GNU GPL).
8 * Please read the included file COPYING for more information.
9 * This software comes with no warranty of any kind, use at your own risk!
12 #include <glib/gstdio.h>
20 #include "secure_save.h"
21 #include "slideshow.h"
22 #include "ui_fileops.h"
26 *-----------------------------------------------------------------------------
27 * line write/parse routines (private)
28 *-----------------------------------------------------------------------------
32 returns text without quotes or NULL for empty or broken string
33 any text up to first '"' is skipped
34 tail is set to point at the char after the second '"'
39 gchar *quoted_value(const gchar *text, const gchar **tail)
43 gint l = strlen(text);
46 if (tail) *tail = text;
48 if (l == 0) return retval;
50 while (c < l && text[c] !='"') c++;
59 if (text[e-1] != '\\' && text[e] == '"') break;
66 gchar *substring = g_strndup(ptr, e - c);
70 retval = g_strcompress(substring);
75 if (tail) *tail = text + e + 1;
78 /* for compatibility with older formats (<0.3.7)
79 * read a line without quotes too */
82 while (c < l && text[c] !=' ' && text[c] !=8 && text[c] != '\n') c++;
85 retval = g_strndup(text, c);
87 if (tail) *tail = text + c;
93 gchar *escquote_value(const gchar *text)
97 if (!text) return g_strdup("\"\"");
99 e = g_strescape(text, "");
102 gchar *retval = g_strdup_printf("\"%s\"", e);
106 return g_strdup("\"\"");
109 static void write_char_option(SecureSaveInfo *ssi, gchar *label, gchar *text)
111 gchar *escval = escquote_value(text);
113 secure_fprintf(ssi, "%s: %s\n", label, escval);
117 static void read_char_option(FILE *f, gchar *option, gchar *label, gchar *value, gchar **text)
119 if (text && strcasecmp(option, label) == 0)
122 *text = quoted_value(value, NULL);
126 /* Since gdk_color_to_string() is only available since gtk 2.12
127 * here is an equivalent stub function. */
128 static gchar *color_to_string(GdkColor *color)
130 return g_strdup_printf("#%04X%04X%04X", color->red, color->green, color->blue);
133 static void write_color_option(SecureSaveInfo *ssi, gchar *label, GdkColor *color)
137 gchar *colorstring = color_to_string(color);
139 write_char_option(ssi, label, colorstring);
143 secure_fprintf(ssi, "%s: \n", label);
146 static void read_color_option(FILE *f, gchar *option, gchar *label, gchar *value, GdkColor *color)
148 if (color && strcasecmp(option, label) == 0)
150 gchar *colorstr = quoted_value(value, NULL);
151 if (colorstr) gdk_color_parse(colorstr, color);
157 static void write_int_option(SecureSaveInfo *ssi, gchar *label, gint n)
159 secure_fprintf(ssi, "%s: %d\n", label, n);
162 static void read_int_option(FILE *f, gchar *option, gchar *label, gchar *value, gint *n)
164 if (n && strcasecmp(option, label) == 0)
166 *n = strtol(value, NULL, 10);
170 static void write_uint_option(SecureSaveInfo *ssi, gchar *label, guint n)
172 secure_fprintf(ssi, "%s: %u\n", label, n);
175 static void read_uint_option(FILE *f, gchar *option, gchar *label, gchar *value, guint *n)
177 if (n && strcasecmp(option, label) == 0)
179 *n = strtoul(value, NULL, 10);
185 static void read_int_option_clamp(FILE *f, gchar *option, gchar *label, gchar *value, gint *n, gint min, gint max)
187 if (n && strcasecmp(option, label) == 0)
189 *n = CLAMP(strtol(value, NULL, 10), min, max);
194 static void write_int_unit_option(SecureSaveInfo *ssi, gchar *label, gint n, gint subunits)
209 secure_fprintf(ssi, "%s: %d.%d\n", label, l, r);
212 static void read_int_unit_option(FILE *f, gchar *option, gchar *label, gchar *value, gint *n, gint subunits)
214 if (n && strcasecmp(option, label) == 0)
220 while (*ptr != '\0' && *ptr != '.') ptr++;
224 l = strtol(value, NULL, 10);
227 r = strtol(ptr, NULL, 10);
231 l = strtol(value, NULL, 10);
235 *n = l * subunits + r;
239 static void write_bool_option(SecureSaveInfo *ssi, gchar *label, gint n)
241 secure_fprintf(ssi, "%s: ", label);
242 if (n) secure_fprintf(ssi, "true\n"); else secure_fprintf(ssi, "false\n");
245 static void read_bool_option(FILE *f, gchar *option, gchar *label, gchar *value, gint *n)
247 if (n && strcasecmp(option, label) == 0)
249 if (strcasecmp(value, "true") == 0 || strcmp(value, "1") == 0)
257 *-----------------------------------------------------------------------------
258 * save configuration (public)
259 *-----------------------------------------------------------------------------
262 void save_options(void)
269 rc_path = g_strconcat(homedir(), "/", GQ_RC_DIR, "/", RC_FILE_NAME, NULL);
271 rc_pathl = path_from_utf8(rc_path);
272 ssi = secure_open(rc_pathl);
276 printf_term(_("error saving config file: %s\n"), rc_path);
281 #define WRITE_BOOL(_name_) write_bool_option(ssi, #_name_, options->_name_)
282 #define WRITE_INT(_name_) write_int_option(ssi, #_name_, options->_name_)
283 #define WRITE_UINT(_name_) write_uint_option(ssi, #_name_, options->_name_)
284 #define WRITE_INT_UNIT(_name_, _unit_) write_int_unit_option(ssi, #_name_, options->_name_, _unit_)
285 #define WRITE_CHAR(_name_) write_char_option(ssi, #_name_, options->_name_)
286 #define WRITE_COLOR(_name_) write_color_option(ssi, #_name_, &options->_name_)
288 #define WRITE_SEPARATOR() secure_fputc(ssi, '\n')
289 #define WRITE_SUBTITLE(_title_) secure_fprintf(ssi, "\n\n##### "_title_" #####\n\n")
291 secure_fprintf(ssi, "######################################################################\n");
292 secure_fprintf(ssi, "# %30s config file version %7s #\n", GQ_APPNAME, VERSION);
293 secure_fprintf(ssi, "######################################################################\n");
296 secure_fprintf(ssi, "# Note: This file is autogenerated. Options can be changed here,\n");
297 secure_fprintf(ssi, "# but user comments and formatting will be lost.\n");
300 WRITE_SUBTITLE("General Options");
302 WRITE_BOOL(show_icon_names);
305 WRITE_BOOL(tree_descend_subdirs);
306 WRITE_BOOL(lazy_image_sync);
307 WRITE_BOOL(update_on_time_change);
310 WRITE_BOOL(startup_path_enable);
311 WRITE_CHAR(startup_path);
313 WRITE_BOOL(progressive_key_scrolling);
314 WRITE_BOOL(enable_metadata_dirs);
316 WRITE_INT(duplicates_similarity_threshold);
319 WRITE_BOOL(mousewheel_scrolls);
320 WRITE_INT(open_recent_list_maxsize);
321 WRITE_BOOL(place_dialogs_under_mouse);
324 WRITE_SUBTITLE("File operations Options");
326 WRITE_BOOL(file_ops.enable_in_place_rename);
327 WRITE_BOOL(file_ops.confirm_delete);
328 WRITE_BOOL(file_ops.enable_delete_key);
329 WRITE_BOOL(file_ops.safe_delete_enable);
330 WRITE_CHAR(file_ops.safe_delete_path);
331 WRITE_INT(file_ops.safe_delete_folder_maxsize);
334 WRITE_SUBTITLE("Layout Options");
336 WRITE_INT(layout.style);
337 WRITE_CHAR(layout.order);
338 WRITE_BOOL(layout.view_as_icons);
339 WRITE_UINT(layout.dir_view_type);
340 WRITE_BOOL(layout.show_thumbnails);
343 WRITE_BOOL(layout.save_window_positions);
346 WRITE_INT(layout.main_window.x);
347 WRITE_INT(layout.main_window.y);
348 WRITE_INT(layout.main_window.w);
349 WRITE_INT(layout.main_window.h);
350 WRITE_BOOL(layout.main_window.maximized);
351 WRITE_INT(layout.main_window.hdivider_pos);
352 WRITE_INT(layout.main_window.vdivider_pos);
355 WRITE_INT(layout.float_window.x);
356 WRITE_INT(layout.float_window.y);
357 WRITE_INT(layout.float_window.w);
358 WRITE_INT(layout.float_window.h);
359 WRITE_INT(layout.float_window.vdivider_pos);
362 WRITE_BOOL(layout.tools_float);
363 WRITE_BOOL(layout.tools_hidden);
364 WRITE_BOOL(layout.tools_restore_state);
367 WRITE_BOOL(layout.toolbar_hidden);
370 WRITE_SUBTITLE("Image Options");
372 secure_fprintf(ssi, "# image.zoom_mode possible values are:\n"
376 secure_fprintf(ssi, "image.zoom_mode: ");
377 if (options->image.zoom_mode == ZOOM_RESET_ORIGINAL)
378 secure_fprintf(ssi, "original\n");
379 else if (options->image.zoom_mode == ZOOM_RESET_FIT_WINDOW)
380 secure_fprintf(ssi, "fit\n");
381 else if (options->image.zoom_mode == ZOOM_RESET_NONE)
382 secure_fprintf(ssi, "dont_change\n");
384 WRITE_BOOL(image.zoom_2pass);
385 WRITE_BOOL(image.zoom_to_fit_allow_expand);
386 WRITE_INT(image.zoom_quality);
387 WRITE_INT(image.zoom_increment);
388 WRITE_BOOL(image.fit_window_to_image);
389 WRITE_BOOL(image.limit_window_size);
390 WRITE_INT(image.max_window_size);
391 WRITE_BOOL(image.limit_autofit_size);
392 WRITE_INT(image.max_autofit_size);
393 WRITE_INT(image.scroll_reset_method);
394 WRITE_INT(image.tile_cache_max);
395 WRITE_INT(image.dither_quality);
396 WRITE_BOOL(image.enable_read_ahead);
397 WRITE_BOOL(image.exif_rotate_enable);
398 WRITE_BOOL(image.use_custom_border_color);
399 WRITE_COLOR(image.border_color);
402 WRITE_SUBTITLE("Thumbnails Options");
404 WRITE_INT(thumbnails.max_width);
405 WRITE_INT(thumbnails.max_height);
406 WRITE_BOOL(thumbnails.enable_caching);
407 WRITE_BOOL(thumbnails.cache_into_dirs);
408 WRITE_BOOL(thumbnails.fast);
409 WRITE_BOOL(thumbnails.use_xvpics);
410 WRITE_BOOL(thumbnails.spec_standard);
411 WRITE_INT(thumbnails.quality);
414 WRITE_SUBTITLE("File sorting Options");
416 WRITE_INT(file_sort.method);
417 WRITE_BOOL(file_sort.ascending);
418 WRITE_BOOL(file_sort.case_sensitive);
421 WRITE_SUBTITLE("Fullscreen Options");
423 WRITE_INT(fullscreen.screen);
424 WRITE_BOOL(fullscreen.clean_flip);
425 WRITE_BOOL(fullscreen.disable_saver);
426 WRITE_BOOL(fullscreen.above);
427 WRITE_BOOL(fullscreen.show_info);
428 WRITE_CHAR(fullscreen.info);
430 WRITE_SUBTITLE("Slideshow Options");
432 WRITE_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
433 WRITE_BOOL(slideshow.random);
434 WRITE_BOOL(slideshow.repeat);
437 WRITE_SUBTITLE("Collection Options");
439 WRITE_BOOL(collections.rectangular_selection);
442 WRITE_SUBTITLE("Filtering Options");
444 WRITE_BOOL(file_filter.show_hidden_files);
445 WRITE_BOOL(file_filter.show_dot_directory);
446 WRITE_BOOL(file_filter.disable);
449 filter_write_list(ssi);
452 WRITE_SUBTITLE("Sidecars Options");
454 sidecar_ext_write(ssi);
457 WRITE_SUBTITLE("Color Profiles");
460 secure_fprintf(ssi, "# NOTICE: %s was not built with support for color profiles,\n"
461 "# color profile options will have no effect.\n\n", GQ_APPNAME);
464 WRITE_BOOL(color_profile.enabled);
465 WRITE_BOOL(color_profile.use_image);
466 WRITE_INT(color_profile.input_type);
469 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
473 buf = g_strdup_printf("color_profile.input_file_%d", i + 1);
474 write_char_option(ssi, buf, options->color_profile.input_file[i]);
477 buf = g_strdup_printf("color_profile.input_name_%d", i + 1);
478 write_char_option(ssi, buf, options->color_profile.input_name[i]);
483 WRITE_INT(color_profile.screen_type);
484 WRITE_CHAR(color_profile.screen_file);
486 WRITE_SUBTITLE("External Programs");
487 secure_fprintf(ssi, "# Maximum of %d programs (external_1 through external_%d)\n", GQ_EDITOR_GENERIC_SLOTS, GQ_EDITOR_GENERIC_SLOTS);
488 secure_fprintf(ssi, "# external_%d through external_%d are used for file ops\n", GQ_EDITOR_GENERIC_SLOTS + 1, GQ_EDITOR_SLOTS);
489 secure_fprintf(ssi, "# format: external_n: \"menu name\" \"command line\"\n\n");
491 for (i = 0; i < GQ_EDITOR_SLOTS; i++)
493 if (i == GQ_EDITOR_GENERIC_SLOTS) secure_fputc(ssi, '\n');
494 gchar *qname = escquote_value(options->editor_name[i]);
495 gchar *qcommand = escquote_value(options->editor_command[i]);
496 secure_fprintf(ssi, "external_%d: %s %s\n", i+1, qname, qcommand);
502 WRITE_SUBTITLE("Exif Options");
503 secure_fprintf(ssi, "# Display: 0: never\n"
506 for (i = 0; ExifUIList[i].key; i++)
508 secure_fprintf(ssi, "exif.display.");
509 write_int_option(ssi, (gchar *)ExifUIList[i].key, ExifUIList[i].current);
515 secure_fprintf(ssi, "######################################################################\n");
516 secure_fprintf(ssi, "# end of config file #\n");
517 secure_fprintf(ssi, "######################################################################\n");
520 if (secure_close(ssi))
522 printf_term(_("error saving config file: %s\nerror: %s\n"), rc_path,
523 secsave_strerror(secsave_errno));
532 *-----------------------------------------------------------------------------
533 * load configuration (public)
534 *-----------------------------------------------------------------------------
537 void load_options(void)
545 gchar value_all[1024];
548 for (i = 0; ExifUIList[i].key; i++)
549 ExifUIList[i].current = ExifUIList[i].default_value;
551 rc_path = g_strconcat(homedir(), "/", GQ_RC_DIR, "/", RC_FILE_NAME, NULL);
553 rc_pathl = path_from_utf8(rc_path);
554 f = fopen(rc_pathl,"r");
562 while (fgets(s_buf, sizeof(s_buf), f))
564 gchar *option_start, *value_start;
567 while(g_ascii_isspace(*p)) p++;
568 if (!*p || *p == '\n' || *p == '#') continue;
570 while(*p && *p != ':') p++;
574 strncpy(option, option_start, sizeof(option));
575 while(g_ascii_isspace(*p)) p++;
577 strncpy(value_all, value_start, sizeof(value_all));
578 while(*p && !g_ascii_isspace(*p) && *p != '\n') p++;
580 strncpy(value, value_start, sizeof(value));
582 #define READ_BOOL(_name_) read_bool_option(f, option, #_name_, value, &options->_name_)
583 #define READ_INT(_name_) read_int_option(f, option, #_name_, value, &options->_name_)
584 #define READ_UINT(_name_) read_uint_option(f, option, #_name_, value, &options->_name_)
585 #define READ_INT_CLAMP(_name_, _min_, _max_) read_int_option_clamp(f, option, #_name_, value, &options->_name_, _min_, _max_)
586 #define READ_INT_UNIT(_name_, _unit_) read_int_unit_option(f, option, #_name_, value, &options->_name_, _unit_)
587 #define READ_CHAR(_name_) read_char_option(f, option, #_name_, value_all, &options->_name_)
588 #define READ_COLOR(_name_) read_color_option(f, option, #_name_, value, &options->_name_)
590 /* general options */
591 READ_BOOL(show_icon_names);
593 READ_BOOL(tree_descend_subdirs);
594 READ_BOOL(lazy_image_sync);
595 READ_BOOL(update_on_time_change);
597 READ_BOOL(startup_path_enable);
598 READ_CHAR(startup_path);
600 READ_INT(duplicates_similarity_threshold);
602 READ_BOOL(progressive_key_scrolling);
604 READ_BOOL(enable_metadata_dirs);
606 READ_BOOL(mousewheel_scrolls);
608 READ_INT(open_recent_list_maxsize);
610 READ_BOOL(place_dialogs_under_mouse);
615 READ_INT(layout.style);
616 READ_CHAR(layout.order);
617 READ_BOOL(layout.view_as_icons);
618 READ_UINT(layout.dir_view_type);
619 READ_BOOL(layout.show_thumbnails);
621 /* window positions */
623 READ_BOOL(layout.save_window_positions);
625 READ_INT(layout.main_window.x);
626 READ_INT(layout.main_window.y);
627 READ_INT(layout.main_window.w);
628 READ_INT(layout.main_window.h);
629 READ_BOOL(layout.main_window.maximized);
630 READ_INT(layout.float_window.x);
631 READ_INT(layout.float_window.y);
632 READ_INT(layout.float_window.w);
633 READ_INT(layout.float_window.h);
634 READ_INT(layout.float_window.vdivider_pos);
635 READ_INT(layout.main_window.hdivider_pos);
636 READ_INT(layout.main_window.vdivider_pos);
637 READ_BOOL(layout.tools_float);
638 READ_BOOL(layout.tools_hidden);
639 READ_BOOL(layout.tools_restore_state);
640 READ_BOOL(layout.toolbar_hidden);
644 if (strcasecmp(option, "image.zoom_mode") == 0)
646 if (strcasecmp(value, "original") == 0)
647 options->image.zoom_mode = ZOOM_RESET_ORIGINAL;
648 else if (strcasecmp(value, "fit") == 0)
649 options->image.zoom_mode = ZOOM_RESET_FIT_WINDOW;
650 else if (strcasecmp(value, "dont_change") == 0)
651 options->image.zoom_mode = ZOOM_RESET_NONE;
653 READ_BOOL(image.zoom_2pass);
654 READ_BOOL(image.zoom_to_fit_allow_expand);
655 READ_BOOL(image.fit_window_to_image);
656 READ_BOOL(image.limit_window_size);
657 READ_INT(image.max_window_size);
658 READ_BOOL(image.limit_autofit_size);
659 READ_INT(image.max_autofit_size);
660 READ_INT(image.scroll_reset_method);
661 READ_INT(image.tile_cache_max);
662 READ_INT_CLAMP(image.zoom_quality, GDK_INTERP_NEAREST, GDK_INTERP_HYPER);
663 READ_INT_CLAMP(image.dither_quality, GDK_RGB_DITHER_NONE, GDK_RGB_DITHER_MAX);
664 READ_INT(image.zoom_increment);
665 READ_BOOL(image.enable_read_ahead);
666 READ_BOOL(image.exif_rotate_enable);
667 READ_BOOL(image.use_custom_border_color);
668 READ_COLOR(image.border_color);
671 /* thumbnails options */
672 READ_INT_CLAMP(thumbnails.max_width, 16, 512);
673 READ_INT_CLAMP(thumbnails.max_height, 16, 512);
675 READ_BOOL(thumbnails.enable_caching);
676 READ_BOOL(thumbnails.cache_into_dirs);
677 READ_BOOL(thumbnails.fast);
678 READ_BOOL(thumbnails.use_xvpics);
679 READ_BOOL(thumbnails.spec_standard);
680 READ_INT_CLAMP(thumbnails.quality, GDK_INTERP_NEAREST, GDK_INTERP_HYPER);
682 /* file sorting options */
683 READ_UINT(file_sort.method);
684 READ_BOOL(file_sort.ascending);
685 READ_BOOL(file_sort.case_sensitive);
687 /* file operations options */
688 READ_BOOL(file_ops.enable_in_place_rename);
689 READ_BOOL(file_ops.confirm_delete);
690 READ_BOOL(file_ops.enable_delete_key);
691 READ_BOOL(file_ops.safe_delete_enable);
692 READ_CHAR(file_ops.safe_delete_path);
693 READ_INT(file_ops.safe_delete_folder_maxsize);
695 /* fullscreen options */
696 READ_INT(fullscreen.screen);
697 READ_BOOL(fullscreen.clean_flip);
698 READ_BOOL(fullscreen.disable_saver);
699 READ_BOOL(fullscreen.above);
700 READ_BOOL(fullscreen.show_info);
701 READ_CHAR(fullscreen.info);
703 /* slideshow options */
705 READ_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
706 READ_BOOL(slideshow.random);
707 READ_BOOL(slideshow.repeat);
709 /* collection options */
711 READ_BOOL(collections.rectangular_selection);
713 /* filtering options */
715 READ_BOOL(file_filter.show_hidden_files);
716 READ_BOOL(file_filter.show_dot_directory);
717 READ_BOOL(file_filter.disable);
719 if (strcasecmp(option, "file_filter.ext") == 0)
721 filter_parse(value_all);
724 if (strcasecmp(option, "sidecar.ext") == 0)
726 sidecar_ext_parse(value_all, TRUE);
731 READ_BOOL(color_profile.enabled);
732 READ_BOOL(color_profile.use_image);
733 READ_INT(color_profile.input_type);
735 if (strncasecmp(option, "color_profile.input_file_", 25) == 0)
737 i = strtol(option + 25, NULL, 0) - 1;
738 if (i >= 0 && i < COLOR_PROFILE_INPUTS)
740 read_char_option(f, option, option, value, &options->color_profile.input_file[i]);
743 if (strncasecmp(option, "color_profile.input_name_", 25) == 0)
745 i = strtol(option + 25, NULL, 0) - 1;
746 if (i >= 0 && i < COLOR_PROFILE_INPUTS)
748 read_char_option(f, option, option, value, &options->color_profile.input_name[i]);
752 READ_INT(color_profile.screen_type);
753 READ_CHAR(color_profile.screen_file);
755 /* External Programs */
757 if (strncasecmp(option, "external_", 9) == 0)
759 i = strtol(option + 9, NULL, 0);
760 if (i > 0 && i <= GQ_EDITOR_SLOTS)
764 g_free(options->editor_name[i]);
765 g_free(options->editor_command[i]);
767 options->editor_name[i] = quoted_value(value_all, &ptr);
768 options->editor_command[i] = quoted_value(ptr, NULL);
773 if (0 == strncasecmp(option, "exif.display.", 13))
775 for (i = 0; ExifUIList[i].key; i++)
776 if (0 == strcasecmp(option + 13, ExifUIList[i].key))
777 ExifUIList[i].current = strtol(value, NULL, 10);