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);
278 buf = g_strdup_printf(_("error saving config file: %s\n"), rc_path);
286 #define WRITE_BOOL(_name_) write_bool_option(ssi, #_name_, options->_name_)
287 #define WRITE_INT(_name_) write_int_option(ssi, #_name_, options->_name_)
288 #define WRITE_UINT(_name_) write_uint_option(ssi, #_name_, options->_name_)
289 #define WRITE_INT_UNIT(_name_, _unit_) write_int_unit_option(ssi, #_name_, options->_name_, _unit_)
290 #define WRITE_CHAR(_name_) write_char_option(ssi, #_name_, options->_name_)
291 #define WRITE_COLOR(_name_) write_color_option(ssi, #_name_, &options->_name_)
293 #define WRITE_SEPARATOR() secure_fputc(ssi, '\n')
294 #define WRITE_SUBTITLE(_title_) secure_fprintf(ssi, "\n\n##### "_title_" #####\n\n")
296 secure_fprintf(ssi, "######################################################################\n");
297 secure_fprintf(ssi, "# %30s config file version %7s #\n", GQ_APPNAME, VERSION);
298 secure_fprintf(ssi, "######################################################################\n");
301 secure_fprintf(ssi, "# Note: This file is autogenerated. Options can be changed here,\n");
302 secure_fprintf(ssi, "# but user comments and formatting will be lost.\n");
305 WRITE_SUBTITLE("General Options");
307 WRITE_BOOL(show_icon_names);
310 WRITE_BOOL(tree_descend_subdirs);
311 WRITE_BOOL(lazy_image_sync);
312 WRITE_BOOL(update_on_time_change);
315 WRITE_BOOL(startup_path_enable);
316 WRITE_CHAR(startup_path);
318 WRITE_BOOL(progressive_key_scrolling);
319 WRITE_BOOL(enable_metadata_dirs);
321 WRITE_INT(duplicates_similarity_threshold);
324 WRITE_BOOL(mousewheel_scrolls);
325 WRITE_INT(open_recent_list_maxsize);
326 WRITE_BOOL(place_dialogs_under_mouse);
329 WRITE_SUBTITLE("File operations Options");
331 WRITE_BOOL(file_ops.enable_in_place_rename);
332 WRITE_BOOL(file_ops.confirm_delete);
333 WRITE_BOOL(file_ops.enable_delete_key);
334 WRITE_BOOL(file_ops.safe_delete_enable);
335 WRITE_CHAR(file_ops.safe_delete_path);
336 WRITE_INT(file_ops.safe_delete_folder_maxsize);
339 WRITE_SUBTITLE("Layout Options");
341 WRITE_INT(layout.style);
342 WRITE_CHAR(layout.order);
343 WRITE_BOOL(layout.view_as_icons);
344 WRITE_UINT(layout.dir_view_type);
345 WRITE_BOOL(layout.show_thumbnails);
348 WRITE_BOOL(layout.save_window_positions);
351 WRITE_INT(layout.main_window.x);
352 WRITE_INT(layout.main_window.y);
353 WRITE_INT(layout.main_window.w);
354 WRITE_INT(layout.main_window.h);
355 WRITE_BOOL(layout.main_window.maximized);
356 WRITE_INT(layout.main_window.hdivider_pos);
357 WRITE_INT(layout.main_window.vdivider_pos);
360 WRITE_INT(layout.float_window.x);
361 WRITE_INT(layout.float_window.y);
362 WRITE_INT(layout.float_window.w);
363 WRITE_INT(layout.float_window.h);
364 WRITE_INT(layout.float_window.vdivider_pos);
367 WRITE_BOOL(layout.tools_float);
368 WRITE_BOOL(layout.tools_hidden);
369 WRITE_BOOL(layout.tools_restore_state);
372 WRITE_BOOL(layout.toolbar_hidden);
375 WRITE_SUBTITLE("Image Options");
377 secure_fprintf(ssi, "# image.zoom_mode possible values are:\n"
381 secure_fprintf(ssi, "image.zoom_mode: ");
382 if (options->image.zoom_mode == ZOOM_RESET_ORIGINAL)
383 secure_fprintf(ssi, "original\n");
384 else if (options->image.zoom_mode == ZOOM_RESET_FIT_WINDOW)
385 secure_fprintf(ssi, "fit\n");
386 else if (options->image.zoom_mode == ZOOM_RESET_NONE)
387 secure_fprintf(ssi, "dont_change\n");
389 WRITE_BOOL(image.zoom_2pass);
390 WRITE_BOOL(image.zoom_to_fit_allow_expand);
391 WRITE_INT(image.zoom_quality);
392 WRITE_INT(image.zoom_increment);
393 WRITE_BOOL(image.fit_window_to_image);
394 WRITE_BOOL(image.limit_window_size);
395 WRITE_INT(image.max_window_size);
396 WRITE_BOOL(image.limit_autofit_size);
397 WRITE_INT(image.max_autofit_size);
398 WRITE_INT(image.scroll_reset_method);
399 WRITE_INT(image.tile_cache_max);
400 WRITE_INT(image.dither_quality);
401 WRITE_BOOL(image.enable_read_ahead);
402 WRITE_BOOL(image.exif_rotate_enable);
403 WRITE_BOOL(image.use_custom_border_color);
404 WRITE_COLOR(image.border_color);
407 WRITE_SUBTITLE("Thumbnails Options");
409 WRITE_INT(thumbnails.max_width);
410 WRITE_INT(thumbnails.max_height);
411 WRITE_BOOL(thumbnails.enable_caching);
412 WRITE_BOOL(thumbnails.cache_into_dirs);
413 WRITE_BOOL(thumbnails.fast);
414 WRITE_BOOL(thumbnails.use_xvpics);
415 WRITE_BOOL(thumbnails.spec_standard);
416 WRITE_INT(thumbnails.quality);
419 WRITE_SUBTITLE("File sorting Options");
421 WRITE_INT(file_sort.method);
422 WRITE_BOOL(file_sort.ascending);
423 WRITE_BOOL(file_sort.case_sensitive);
426 WRITE_SUBTITLE("Fullscreen Options");
428 WRITE_INT(fullscreen.screen);
429 WRITE_BOOL(fullscreen.clean_flip);
430 WRITE_BOOL(fullscreen.disable_saver);
431 WRITE_BOOL(fullscreen.above);
432 WRITE_BOOL(fullscreen.show_info);
433 WRITE_CHAR(fullscreen.info);
435 WRITE_SUBTITLE("Slideshow Options");
437 WRITE_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
438 WRITE_BOOL(slideshow.random);
439 WRITE_BOOL(slideshow.repeat);
442 WRITE_SUBTITLE("Collection Options");
444 WRITE_BOOL(collections.rectangular_selection);
447 WRITE_SUBTITLE("Filtering Options");
449 WRITE_BOOL(file_filter.show_hidden_files);
450 WRITE_BOOL(file_filter.show_dot_directory);
451 WRITE_BOOL(file_filter.disable);
454 filter_write_list(ssi);
457 WRITE_SUBTITLE("Sidecars Options");
459 sidecar_ext_write(ssi);
462 WRITE_SUBTITLE("Color Profiles");
465 secure_fprintf(ssi, "# NOTICE: %s was not built with support for color profiles,\n"
466 "# color profile options will have no effect.\n\n", GQ_APPNAME);
469 WRITE_BOOL(color_profile.enabled);
470 WRITE_BOOL(color_profile.use_image);
471 WRITE_INT(color_profile.input_type);
474 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
478 buf = g_strdup_printf("color_profile.input_file_%d", i + 1);
479 write_char_option(ssi, buf, options->color_profile.input_file[i]);
482 buf = g_strdup_printf("color_profile.input_name_%d", i + 1);
483 write_char_option(ssi, buf, options->color_profile.input_name[i]);
488 WRITE_INT(color_profile.screen_type);
489 WRITE_CHAR(color_profile.screen_file);
491 WRITE_SUBTITLE("External Programs");
492 secure_fprintf(ssi, "# Maximum of %d programs (external_1 through external_%d)\n", GQ_EDITOR_GENERIC_SLOTS, GQ_EDITOR_GENERIC_SLOTS);
493 secure_fprintf(ssi, "# external_%d through external_%d are used for file ops\n", GQ_EDITOR_GENERIC_SLOTS + 1, GQ_EDITOR_SLOTS);
494 secure_fprintf(ssi, "# format: external_n: \"menu name\" \"command line\"\n\n");
496 for (i = 0; i < GQ_EDITOR_SLOTS; i++)
498 if (i == GQ_EDITOR_GENERIC_SLOTS) secure_fputc(ssi, '\n');
499 gchar *qname = escquote_value(options->editor_name[i]);
500 gchar *qcommand = escquote_value(options->editor_command[i]);
501 secure_fprintf(ssi, "external_%d: %s %s\n", i+1, qname, qcommand);
507 WRITE_SUBTITLE("Exif Options");
508 secure_fprintf(ssi, "# Display: 0: never\n"
511 for (i = 0; ExifUIList[i].key; i++)
513 secure_fprintf(ssi, "exif.display.");
514 write_int_option(ssi, (gchar *)ExifUIList[i].key, ExifUIList[i].current);
520 secure_fprintf(ssi, "######################################################################\n");
521 secure_fprintf(ssi, "# end of config file #\n");
522 secure_fprintf(ssi, "######################################################################\n");
525 if (secure_close(ssi))
529 buf = g_strdup_printf(_("error saving config file: %s\nerror: %s\n"), rc_path,
530 secsave_strerror(secsave_errno));
542 *-----------------------------------------------------------------------------
543 * load configuration (public)
544 *-----------------------------------------------------------------------------
547 void load_options(void)
555 gchar value_all[1024];
558 for (i = 0; ExifUIList[i].key; i++)
559 ExifUIList[i].current = ExifUIList[i].default_value;
561 rc_path = g_strconcat(homedir(), "/", GQ_RC_DIR, "/", RC_FILE_NAME, NULL);
563 rc_pathl = path_from_utf8(rc_path);
564 f = fopen(rc_pathl,"r");
572 while (fgets(s_buf, sizeof(s_buf), f))
574 gchar *option_start, *value_start;
577 while(g_ascii_isspace(*p)) p++;
578 if (!*p || *p == '\n' || *p == '#') continue;
580 while(*p && *p != ':') p++;
584 strncpy(option, option_start, sizeof(option));
585 while(g_ascii_isspace(*p)) p++;
587 strncpy(value_all, value_start, sizeof(value_all));
588 while(*p && !g_ascii_isspace(*p) && *p != '\n') p++;
590 strncpy(value, value_start, sizeof(value));
592 #define READ_BOOL(_name_) read_bool_option(f, option, #_name_, value, &options->_name_)
593 #define READ_INT(_name_) read_int_option(f, option, #_name_, value, &options->_name_)
594 #define READ_UINT(_name_) read_uint_option(f, option, #_name_, value, &options->_name_)
595 #define READ_INT_CLAMP(_name_, _min_, _max_) read_int_option_clamp(f, option, #_name_, value, &options->_name_, _min_, _max_)
596 #define READ_INT_UNIT(_name_, _unit_) read_int_unit_option(f, option, #_name_, value, &options->_name_, _unit_)
597 #define READ_CHAR(_name_) read_char_option(f, option, #_name_, value_all, &options->_name_)
598 #define READ_COLOR(_name_) read_color_option(f, option, #_name_, value, &options->_name_)
600 /* general options */
601 READ_BOOL(show_icon_names);
603 READ_BOOL(tree_descend_subdirs);
604 READ_BOOL(lazy_image_sync);
605 READ_BOOL(update_on_time_change);
607 READ_BOOL(startup_path_enable);
608 READ_CHAR(startup_path);
610 READ_INT(duplicates_similarity_threshold);
612 READ_BOOL(progressive_key_scrolling);
614 READ_BOOL(enable_metadata_dirs);
616 READ_BOOL(mousewheel_scrolls);
618 READ_INT(open_recent_list_maxsize);
620 READ_BOOL(place_dialogs_under_mouse);
625 READ_INT(layout.style);
626 READ_CHAR(layout.order);
627 READ_BOOL(layout.view_as_icons);
628 READ_UINT(layout.dir_view_type);
629 READ_BOOL(layout.show_thumbnails);
631 /* window positions */
633 READ_BOOL(layout.save_window_positions);
635 READ_INT(layout.main_window.x);
636 READ_INT(layout.main_window.y);
637 READ_INT(layout.main_window.w);
638 READ_INT(layout.main_window.h);
639 READ_BOOL(layout.main_window.maximized);
640 READ_INT(layout.float_window.x);
641 READ_INT(layout.float_window.y);
642 READ_INT(layout.float_window.w);
643 READ_INT(layout.float_window.h);
644 READ_INT(layout.float_window.vdivider_pos);
645 READ_INT(layout.main_window.hdivider_pos);
646 READ_INT(layout.main_window.vdivider_pos);
647 READ_BOOL(layout.tools_float);
648 READ_BOOL(layout.tools_hidden);
649 READ_BOOL(layout.tools_restore_state);
650 READ_BOOL(layout.toolbar_hidden);
654 if (strcasecmp(option, "image.zoom_mode") == 0)
656 if (strcasecmp(value, "original") == 0)
657 options->image.zoom_mode = ZOOM_RESET_ORIGINAL;
658 else if (strcasecmp(value, "fit") == 0)
659 options->image.zoom_mode = ZOOM_RESET_FIT_WINDOW;
660 else if (strcasecmp(value, "dont_change") == 0)
661 options->image.zoom_mode = ZOOM_RESET_NONE;
663 READ_BOOL(image.zoom_2pass);
664 READ_BOOL(image.zoom_to_fit_allow_expand);
665 READ_BOOL(image.fit_window_to_image);
666 READ_BOOL(image.limit_window_size);
667 READ_INT(image.max_window_size);
668 READ_BOOL(image.limit_autofit_size);
669 READ_INT(image.max_autofit_size);
670 READ_INT(image.scroll_reset_method);
671 READ_INT(image.tile_cache_max);
672 READ_INT_CLAMP(image.zoom_quality, GDK_INTERP_NEAREST, GDK_INTERP_HYPER);
673 READ_INT_CLAMP(image.dither_quality, GDK_RGB_DITHER_NONE, GDK_RGB_DITHER_MAX);
674 READ_INT(image.zoom_increment);
675 READ_BOOL(image.enable_read_ahead);
676 READ_BOOL(image.exif_rotate_enable);
677 READ_BOOL(image.use_custom_border_color);
678 READ_COLOR(image.border_color);
681 /* thumbnails options */
682 READ_INT_CLAMP(thumbnails.max_width, 16, 512);
683 READ_INT_CLAMP(thumbnails.max_height, 16, 512);
685 READ_BOOL(thumbnails.enable_caching);
686 READ_BOOL(thumbnails.cache_into_dirs);
687 READ_BOOL(thumbnails.fast);
688 READ_BOOL(thumbnails.use_xvpics);
689 READ_BOOL(thumbnails.spec_standard);
690 READ_INT_CLAMP(thumbnails.quality, GDK_INTERP_NEAREST, GDK_INTERP_HYPER);
692 /* file sorting options */
693 READ_UINT(file_sort.method);
694 READ_BOOL(file_sort.ascending);
695 READ_BOOL(file_sort.case_sensitive);
697 /* file operations options */
698 READ_BOOL(file_ops.enable_in_place_rename);
699 READ_BOOL(file_ops.confirm_delete);
700 READ_BOOL(file_ops.enable_delete_key);
701 READ_BOOL(file_ops.safe_delete_enable);
702 READ_CHAR(file_ops.safe_delete_path);
703 READ_INT(file_ops.safe_delete_folder_maxsize);
705 /* fullscreen options */
706 READ_INT(fullscreen.screen);
707 READ_BOOL(fullscreen.clean_flip);
708 READ_BOOL(fullscreen.disable_saver);
709 READ_BOOL(fullscreen.above);
710 READ_BOOL(fullscreen.show_info);
711 READ_CHAR(fullscreen.info);
713 /* slideshow options */
715 READ_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
716 READ_BOOL(slideshow.random);
717 READ_BOOL(slideshow.repeat);
719 /* collection options */
721 READ_BOOL(collections.rectangular_selection);
723 /* filtering options */
725 READ_BOOL(file_filter.show_hidden_files);
726 READ_BOOL(file_filter.show_dot_directory);
727 READ_BOOL(file_filter.disable);
729 if (strcasecmp(option, "file_filter.ext") == 0)
731 filter_parse(value_all);
734 if (strcasecmp(option, "sidecar.ext") == 0)
736 sidecar_ext_parse(value_all, TRUE);
741 READ_BOOL(color_profile.enabled);
742 READ_BOOL(color_profile.use_image);
743 READ_INT(color_profile.input_type);
745 if (strncasecmp(option, "color_profile.input_file_", 25) == 0)
747 i = strtol(option + 25, NULL, 0) - 1;
748 if (i >= 0 && i < COLOR_PROFILE_INPUTS)
750 read_char_option(f, option, option, value, &options->color_profile.input_file[i]);
753 if (strncasecmp(option, "color_profile.input_name_", 25) == 0)
755 i = strtol(option + 25, NULL, 0) - 1;
756 if (i >= 0 && i < COLOR_PROFILE_INPUTS)
758 read_char_option(f, option, option, value, &options->color_profile.input_name[i]);
762 READ_INT(color_profile.screen_type);
763 READ_CHAR(color_profile.screen_file);
765 /* External Programs */
767 if (strncasecmp(option, "external_", 9) == 0)
769 i = strtol(option + 9, NULL, 0);
770 if (i > 0 && i <= GQ_EDITOR_SLOTS)
774 g_free(options->editor_name[i]);
775 g_free(options->editor_command[i]);
777 options->editor_name[i] = quoted_value(value_all, &ptr);
778 options->editor_command[i] = quoted_value(ptr, NULL);
783 if (0 == strncasecmp(option, "exif.display.", 13))
785 for (i = 0; ExifUIList[i].key; i++)
786 if (0 == strcasecmp(option + 13, ExifUIList[i].key))
787 ExifUIList[i].current = strtol(value, NULL, 10);