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_marks);
341 WRITE_BOOL(layout.show_thumbnails);
344 WRITE_BOOL(layout.save_window_positions);
347 WRITE_INT(layout.main_window.x);
348 WRITE_INT(layout.main_window.y);
349 WRITE_INT(layout.main_window.w);
350 WRITE_INT(layout.main_window.h);
351 WRITE_BOOL(layout.main_window.maximized);
352 WRITE_INT(layout.main_window.hdivider_pos);
353 WRITE_INT(layout.main_window.vdivider_pos);
356 WRITE_INT(layout.float_window.x);
357 WRITE_INT(layout.float_window.y);
358 WRITE_INT(layout.float_window.w);
359 WRITE_INT(layout.float_window.h);
360 WRITE_INT(layout.float_window.vdivider_pos);
363 WRITE_BOOL(layout.tools_float);
364 WRITE_BOOL(layout.tools_hidden);
365 WRITE_BOOL(layout.tools_restore_state);
368 WRITE_BOOL(layout.toolbar_hidden);
371 WRITE_SUBTITLE("Image Options");
373 secure_fprintf(ssi, "# image.zoom_mode possible values are:\n"
377 secure_fprintf(ssi, "image.zoom_mode: ");
378 if (options->image.zoom_mode == ZOOM_RESET_ORIGINAL)
379 secure_fprintf(ssi, "original\n");
380 else if (options->image.zoom_mode == ZOOM_RESET_FIT_WINDOW)
381 secure_fprintf(ssi, "fit\n");
382 else if (options->image.zoom_mode == ZOOM_RESET_NONE)
383 secure_fprintf(ssi, "dont_change\n");
385 WRITE_BOOL(image.zoom_2pass);
386 WRITE_BOOL(image.zoom_to_fit_allow_expand);
387 WRITE_INT(image.zoom_quality);
388 WRITE_INT(image.zoom_increment);
389 WRITE_BOOL(image.fit_window_to_image);
390 WRITE_BOOL(image.limit_window_size);
391 WRITE_INT(image.max_window_size);
392 WRITE_BOOL(image.limit_autofit_size);
393 WRITE_INT(image.max_autofit_size);
394 WRITE_INT(image.scroll_reset_method);
395 WRITE_INT(image.tile_cache_max);
396 WRITE_INT(image.dither_quality);
397 WRITE_BOOL(image.enable_read_ahead);
398 WRITE_BOOL(image.exif_rotate_enable);
399 WRITE_BOOL(image.use_custom_border_color);
400 WRITE_COLOR(image.border_color);
401 WRITE_INT(image.read_buffer_size);
402 WRITE_INT(image.idle_read_loop_count);
404 WRITE_SUBTITLE("Thumbnails Options");
406 WRITE_INT(thumbnails.max_width);
407 WRITE_INT(thumbnails.max_height);
408 WRITE_BOOL(thumbnails.enable_caching);
409 WRITE_BOOL(thumbnails.cache_into_dirs);
410 WRITE_BOOL(thumbnails.fast);
411 WRITE_BOOL(thumbnails.use_xvpics);
412 WRITE_BOOL(thumbnails.spec_standard);
413 WRITE_INT(thumbnails.quality);
416 WRITE_SUBTITLE("File sorting Options");
418 WRITE_INT(file_sort.method);
419 WRITE_BOOL(file_sort.ascending);
420 WRITE_BOOL(file_sort.case_sensitive);
423 WRITE_SUBTITLE("Fullscreen Options");
425 WRITE_INT(fullscreen.screen);
426 WRITE_BOOL(fullscreen.clean_flip);
427 WRITE_BOOL(fullscreen.disable_saver);
428 WRITE_BOOL(fullscreen.above);
429 WRITE_BOOL(fullscreen.show_info);
430 WRITE_CHAR(fullscreen.info);
432 WRITE_SUBTITLE("Slideshow Options");
434 WRITE_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
435 WRITE_BOOL(slideshow.random);
436 WRITE_BOOL(slideshow.repeat);
439 WRITE_SUBTITLE("Collection Options");
441 WRITE_BOOL(collections.rectangular_selection);
444 WRITE_SUBTITLE("Filtering Options");
446 WRITE_BOOL(file_filter.show_hidden_files);
447 WRITE_BOOL(file_filter.show_dot_directory);
448 WRITE_BOOL(file_filter.disable);
451 filter_write_list(ssi);
454 WRITE_SUBTITLE("Sidecars Options");
456 sidecar_ext_write(ssi);
459 WRITE_SUBTITLE("Color Profiles");
462 secure_fprintf(ssi, "# NOTICE: %s was not built with support for color profiles,\n"
463 "# color profile options will have no effect.\n\n", GQ_APPNAME);
466 WRITE_BOOL(color_profile.enabled);
467 WRITE_BOOL(color_profile.use_image);
468 WRITE_INT(color_profile.input_type);
471 for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
475 buf = g_strdup_printf("color_profile.input_file_%d", i + 1);
476 write_char_option(ssi, buf, options->color_profile.input_file[i]);
479 buf = g_strdup_printf("color_profile.input_name_%d", i + 1);
480 write_char_option(ssi, buf, options->color_profile.input_name[i]);
485 WRITE_INT(color_profile.screen_type);
486 WRITE_CHAR(color_profile.screen_file);
488 WRITE_SUBTITLE("External Programs");
489 secure_fprintf(ssi, "# Maximum of %d programs (external_1 through external_%d)\n", GQ_EDITOR_GENERIC_SLOTS, GQ_EDITOR_GENERIC_SLOTS);
490 secure_fprintf(ssi, "# external_%d through external_%d are used for file ops\n", GQ_EDITOR_GENERIC_SLOTS + 1, GQ_EDITOR_SLOTS);
491 secure_fprintf(ssi, "# format: external_n: \"menu name\" \"command line\"\n\n");
493 for (i = 0; i < GQ_EDITOR_SLOTS; i++)
495 if (i == GQ_EDITOR_GENERIC_SLOTS) secure_fputc(ssi, '\n');
496 gchar *qname = escquote_value(options->editor_name[i]);
497 gchar *qcommand = escquote_value(options->editor_command[i]);
498 secure_fprintf(ssi, "external_%d: %s %s\n", i+1, qname, qcommand);
504 WRITE_SUBTITLE("Exif Options");
505 secure_fprintf(ssi, "# Display: 0: never\n"
508 for (i = 0; ExifUIList[i].key; i++)
510 secure_fprintf(ssi, "exif.display.");
511 write_int_option(ssi, (gchar *)ExifUIList[i].key, ExifUIList[i].current);
517 secure_fprintf(ssi, "######################################################################\n");
518 secure_fprintf(ssi, "# end of config file #\n");
519 secure_fprintf(ssi, "######################################################################\n");
522 if (secure_close(ssi))
524 printf_term(_("error saving config file: %s\nerror: %s\n"), rc_path,
525 secsave_strerror(secsave_errno));
534 *-----------------------------------------------------------------------------
535 * load configuration (public)
536 *-----------------------------------------------------------------------------
539 void load_options(void)
547 gchar value_all[1024];
550 for (i = 0; ExifUIList[i].key; i++)
551 ExifUIList[i].current = ExifUIList[i].default_value;
553 rc_path = g_strconcat(homedir(), "/", GQ_RC_DIR, "/", RC_FILE_NAME, NULL);
555 rc_pathl = path_from_utf8(rc_path);
556 f = fopen(rc_pathl,"r");
564 while (fgets(s_buf, sizeof(s_buf), f))
566 gchar *option_start, *value_start;
569 while(g_ascii_isspace(*p)) p++;
570 if (!*p || *p == '\n' || *p == '#') continue;
572 while(*p && *p != ':') p++;
576 strncpy(option, option_start, sizeof(option));
577 while(g_ascii_isspace(*p)) p++;
579 strncpy(value_all, value_start, sizeof(value_all));
580 while(*p && !g_ascii_isspace(*p) && *p != '\n') p++;
582 strncpy(value, value_start, sizeof(value));
584 #define READ_BOOL(_name_) read_bool_option(f, option, #_name_, value, &options->_name_)
585 #define READ_INT(_name_) read_int_option(f, option, #_name_, value, &options->_name_)
586 #define READ_UINT(_name_) read_uint_option(f, option, #_name_, value, &options->_name_)
587 #define READ_INT_CLAMP(_name_, _min_, _max_) read_int_option_clamp(f, option, #_name_, value, &options->_name_, _min_, _max_)
588 #define READ_INT_UNIT(_name_, _unit_) read_int_unit_option(f, option, #_name_, value, &options->_name_, _unit_)
589 #define READ_CHAR(_name_) read_char_option(f, option, #_name_, value_all, &options->_name_)
590 #define READ_COLOR(_name_) read_color_option(f, option, #_name_, value, &options->_name_)
592 /* general options */
593 READ_BOOL(show_icon_names);
595 READ_BOOL(tree_descend_subdirs);
596 READ_BOOL(lazy_image_sync);
597 READ_BOOL(update_on_time_change);
599 READ_BOOL(startup_path_enable);
600 READ_CHAR(startup_path);
602 READ_INT(duplicates_similarity_threshold);
604 READ_BOOL(progressive_key_scrolling);
606 READ_BOOL(enable_metadata_dirs);
608 READ_BOOL(mousewheel_scrolls);
610 READ_INT(open_recent_list_maxsize);
612 READ_BOOL(place_dialogs_under_mouse);
617 READ_INT(layout.style);
618 READ_CHAR(layout.order);
619 READ_BOOL(layout.view_as_icons);
620 READ_UINT(layout.dir_view_type);
621 READ_BOOL(layout.show_marks);
622 READ_BOOL(layout.show_thumbnails);
624 /* window positions */
626 READ_BOOL(layout.save_window_positions);
628 READ_INT(layout.main_window.x);
629 READ_INT(layout.main_window.y);
630 READ_INT(layout.main_window.w);
631 READ_INT(layout.main_window.h);
632 READ_BOOL(layout.main_window.maximized);
633 READ_INT(layout.float_window.x);
634 READ_INT(layout.float_window.y);
635 READ_INT(layout.float_window.w);
636 READ_INT(layout.float_window.h);
637 READ_INT(layout.float_window.vdivider_pos);
638 READ_INT(layout.main_window.hdivider_pos);
639 READ_INT(layout.main_window.vdivider_pos);
640 READ_BOOL(layout.tools_float);
641 READ_BOOL(layout.tools_hidden);
642 READ_BOOL(layout.tools_restore_state);
643 READ_BOOL(layout.toolbar_hidden);
647 if (strcasecmp(option, "image.zoom_mode") == 0)
649 if (strcasecmp(value, "original") == 0)
650 options->image.zoom_mode = ZOOM_RESET_ORIGINAL;
651 else if (strcasecmp(value, "fit") == 0)
652 options->image.zoom_mode = ZOOM_RESET_FIT_WINDOW;
653 else if (strcasecmp(value, "dont_change") == 0)
654 options->image.zoom_mode = ZOOM_RESET_NONE;
656 READ_BOOL(image.zoom_2pass);
657 READ_BOOL(image.zoom_to_fit_allow_expand);
658 READ_BOOL(image.fit_window_to_image);
659 READ_BOOL(image.limit_window_size);
660 READ_INT(image.max_window_size);
661 READ_BOOL(image.limit_autofit_size);
662 READ_INT(image.max_autofit_size);
663 READ_INT(image.scroll_reset_method);
664 READ_INT(image.tile_cache_max);
665 READ_INT_CLAMP(image.zoom_quality, GDK_INTERP_NEAREST, GDK_INTERP_HYPER);
666 READ_INT_CLAMP(image.dither_quality, GDK_RGB_DITHER_NONE, GDK_RGB_DITHER_MAX);
667 READ_INT(image.zoom_increment);
668 READ_BOOL(image.enable_read_ahead);
669 READ_BOOL(image.exif_rotate_enable);
670 READ_BOOL(image.use_custom_border_color);
671 READ_COLOR(image.border_color);
672 READ_INT_CLAMP(image.read_buffer_size, IMAGE_LOADER_READ_BUFFER_SIZE_MIN, IMAGE_LOADER_READ_BUFFER_SIZE_MAX);
673 READ_INT_CLAMP(image.idle_read_loop_count, IMAGE_LOADER_IDLE_READ_LOOP_COUNT_MIN, IMAGE_LOADER_IDLE_READ_LOOP_COUNT_MAX);
676 /* thumbnails options */
677 READ_INT_CLAMP(thumbnails.max_width, 16, 512);
678 READ_INT_CLAMP(thumbnails.max_height, 16, 512);
680 READ_BOOL(thumbnails.enable_caching);
681 READ_BOOL(thumbnails.cache_into_dirs);
682 READ_BOOL(thumbnails.fast);
683 READ_BOOL(thumbnails.use_xvpics);
684 READ_BOOL(thumbnails.spec_standard);
685 READ_INT_CLAMP(thumbnails.quality, GDK_INTERP_NEAREST, GDK_INTERP_HYPER);
687 /* file sorting options */
688 READ_UINT(file_sort.method);
689 READ_BOOL(file_sort.ascending);
690 READ_BOOL(file_sort.case_sensitive);
692 /* file operations options */
693 READ_BOOL(file_ops.enable_in_place_rename);
694 READ_BOOL(file_ops.confirm_delete);
695 READ_BOOL(file_ops.enable_delete_key);
696 READ_BOOL(file_ops.safe_delete_enable);
697 READ_CHAR(file_ops.safe_delete_path);
698 READ_INT(file_ops.safe_delete_folder_maxsize);
700 /* fullscreen options */
701 READ_INT(fullscreen.screen);
702 READ_BOOL(fullscreen.clean_flip);
703 READ_BOOL(fullscreen.disable_saver);
704 READ_BOOL(fullscreen.above);
705 READ_BOOL(fullscreen.show_info);
706 READ_CHAR(fullscreen.info);
708 /* slideshow options */
710 READ_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
711 READ_BOOL(slideshow.random);
712 READ_BOOL(slideshow.repeat);
714 /* collection options */
716 READ_BOOL(collections.rectangular_selection);
718 /* filtering options */
720 READ_BOOL(file_filter.show_hidden_files);
721 READ_BOOL(file_filter.show_dot_directory);
722 READ_BOOL(file_filter.disable);
724 if (strcasecmp(option, "file_filter.ext") == 0)
726 filter_parse(value_all);
729 if (strcasecmp(option, "sidecar.ext") == 0)
731 sidecar_ext_parse(value_all, TRUE);
736 READ_BOOL(color_profile.enabled);
737 READ_BOOL(color_profile.use_image);
738 READ_INT(color_profile.input_type);
740 if (strncasecmp(option, "color_profile.input_file_", 25) == 0)
742 i = strtol(option + 25, NULL, 0) - 1;
743 if (i >= 0 && i < COLOR_PROFILE_INPUTS)
745 read_char_option(f, option, option, value, &options->color_profile.input_file[i]);
748 if (strncasecmp(option, "color_profile.input_name_", 25) == 0)
750 i = strtol(option + 25, NULL, 0) - 1;
751 if (i >= 0 && i < COLOR_PROFILE_INPUTS)
753 read_char_option(f, option, option, value, &options->color_profile.input_name[i]);
757 READ_INT(color_profile.screen_type);
758 READ_CHAR(color_profile.screen_file);
760 /* External Programs */
762 if (strncasecmp(option, "external_", 9) == 0)
764 i = strtol(option + 9, NULL, 0);
765 if (i > 0 && i <= GQ_EDITOR_SLOTS)
769 g_free(options->editor_name[i]);
770 g_free(options->editor_command[i]);
772 options->editor_name[i] = quoted_value(value_all, &ptr);
773 options->editor_command[i] = quoted_value(ptr, NULL);
778 if (0 == strncasecmp(option, "exif.display.", 13))
780 for (i = 0; ExifUIList[i].key; i++)
781 if (0 == strcasecmp(option + 13, ExifUIList[i].key))
782 ExifUIList[i].current = strtol(value, NULL, 10);