Save Show Marks state to rc file and display current state in menu.
[geeqie.git] / src / rcfile.c
1 /*
2  * Geeqie
3  * (C) 2006 John Ellis
4  *
5  * Author: John Ellis
6  *
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!
10  */
11
12 #include <glib/gstdio.h>
13 #include <errno.h>
14
15 #include "main.h"
16 #include "rcfile.h"
17
18 #include "bar_exif.h"
19 #include "filelist.h"
20 #include "secure_save.h"
21 #include "slideshow.h"
22 #include "ui_fileops.h"
23
24
25 /*
26  *-----------------------------------------------------------------------------
27  * line write/parse routines (private)
28  *-----------------------------------------------------------------------------
29  */ 
30  
31 /* 
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 '"'
35    or at the ending \0 
36    
37 */
38
39 gchar *quoted_value(const gchar *text, const gchar **tail)
40 {
41         const gchar *ptr;
42         gint c = 0;
43         gint l = strlen(text);
44         gchar *retval = NULL;
45         
46         if (tail) *tail = text;
47         
48         if (l == 0) return retval;
49
50         while (c < l && text[c] !='"') c++;
51         if (text[c] == '"')
52                 {
53                 gint e;
54                 c++;
55                 ptr = text + c;
56                 e = c;
57                 while (e < l)
58                         {
59                         if (text[e-1] != '\\' && text[e] == '"') break;
60                         e++;
61                         }
62                 if (text[e] == '"')
63                         {
64                         if (e - c > 0)
65                                 {
66                                 gchar *substring = g_strndup(ptr, e - c);
67                                 
68                                 if (substring)
69                                         {
70                                         retval = g_strcompress(substring);
71                                         g_free(substring);
72                                         }
73                                 }
74                         }
75                 if (tail) *tail = text + e + 1;
76                 }
77         else
78                 /* for compatibility with older formats (<0.3.7)
79                  * read a line without quotes too */
80                 {
81                 c = 0;
82                 while (c < l && text[c] !=' ' && text[c] !=8 && text[c] != '\n') c++;
83                 if (c != 0)
84                         {
85                         retval = g_strndup(text, c);
86                         }
87                 if (tail) *tail = text + c;
88                 }
89
90         return retval;
91 }
92
93 gchar *escquote_value(const gchar *text)
94 {
95         gchar *e;
96         
97         if (!text) return g_strdup("\"\"");
98
99         e = g_strescape(text, "");
100         if (e)
101                 {
102                 gchar *retval = g_strdup_printf("\"%s\"", e);
103                 g_free(e);
104                 return retval;
105                 }
106         return g_strdup("\"\"");
107 }
108
109 static void write_char_option(SecureSaveInfo *ssi, gchar *label, gchar *text)
110 {
111         gchar *escval = escquote_value(text);
112
113         secure_fprintf(ssi, "%s: %s\n", label, escval);
114         g_free(escval);
115 }
116
117 static void read_char_option(FILE *f, gchar *option, gchar *label, gchar *value, gchar **text)
118 {
119         if (text && strcasecmp(option, label) == 0)
120                 {
121                 g_free(*text);
122                 *text = quoted_value(value, NULL);
123                 }
124 }
125
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)
129 {
130         return g_strdup_printf("#%04X%04X%04X", color->red, color->green, color->blue);
131 }
132
133 static void write_color_option(SecureSaveInfo *ssi, gchar *label, GdkColor *color)
134 {
135         if (color)
136                 {
137                 gchar *colorstring = color_to_string(color);
138
139                 write_char_option(ssi, label, colorstring);
140                 g_free(colorstring);
141                 }
142         else
143                 secure_fprintf(ssi, "%s: \n", label);
144 }
145
146 static void read_color_option(FILE *f, gchar *option, gchar *label, gchar *value, GdkColor *color)
147 {
148         if (color && strcasecmp(option, label) == 0)
149                 {
150                 gchar *colorstr = quoted_value(value, NULL);
151                 if (colorstr) gdk_color_parse(colorstr, color);
152                 g_free(colorstr);
153                 }
154 }
155
156
157 static void write_int_option(SecureSaveInfo *ssi, gchar *label, gint n)
158 {
159         secure_fprintf(ssi, "%s: %d\n", label, n);
160 }
161
162 static void read_int_option(FILE *f, gchar *option, gchar *label, gchar *value, gint *n)
163 {
164         if (n && strcasecmp(option, label) == 0)
165                 {
166                 *n = strtol(value, NULL, 10);
167                 }
168 }
169
170 static void write_uint_option(SecureSaveInfo *ssi, gchar *label, guint n)
171 {
172         secure_fprintf(ssi, "%s: %u\n", label, n);
173 }
174
175 static void read_uint_option(FILE *f, gchar *option, gchar *label, gchar *value, guint *n)
176 {
177         if (n && strcasecmp(option, label) == 0)
178                 {
179                 *n = strtoul(value, NULL, 10);
180                 }
181 }
182
183
184
185 static void read_int_option_clamp(FILE *f, gchar *option, gchar *label, gchar *value, gint *n, gint min, gint max)
186 {
187         if (n && strcasecmp(option, label) == 0)
188                 {
189                 *n = CLAMP(strtol(value, NULL, 10), min, max);
190                 }
191 }
192
193
194 static void write_int_unit_option(SecureSaveInfo *ssi, gchar *label, gint n, gint subunits)
195 {
196         gint l, r;
197
198         if (subunits > 0)
199                 {
200                 l = n / subunits;
201                 r = n % subunits;
202                 }
203         else
204                 {
205                 l = n;
206                 r = 0;
207                 }
208
209         secure_fprintf(ssi, "%s: %d.%d\n", label, l, r);
210 }
211
212 static void read_int_unit_option(FILE *f, gchar *option, gchar *label, gchar *value, gint *n, gint subunits)
213 {
214         if (n && strcasecmp(option, label) == 0)
215                 {
216                 gint l, r;
217                 gchar *ptr;
218
219                 ptr = value;
220                 while (*ptr != '\0' && *ptr != '.') ptr++;
221                 if (*ptr == '.')
222                         {
223                         *ptr = '\0';
224                         l = strtol(value, NULL, 10);
225                         *ptr = '.';
226                         ptr++;
227                         r = strtol(ptr, NULL, 10);
228                         }
229                 else
230                         {
231                         l = strtol(value, NULL, 10);
232                         r = 0;
233                         }
234
235                 *n = l * subunits + r;
236                 }
237 }
238
239 static void write_bool_option(SecureSaveInfo *ssi, gchar *label, gint n)
240 {
241         secure_fprintf(ssi, "%s: ", label);
242         if (n) secure_fprintf(ssi, "true\n"); else secure_fprintf(ssi, "false\n");
243 }
244
245 static void read_bool_option(FILE *f, gchar *option, gchar *label, gchar *value, gint *n)
246 {
247         if (n && strcasecmp(option, label) == 0)
248                 {
249                 if (strcasecmp(value, "true") == 0 || strcmp(value, "1") == 0)
250                         *n = TRUE;
251                 else
252                         *n = FALSE;
253                 }
254 }
255
256 /*
257  *-----------------------------------------------------------------------------
258  * save configuration (public)
259  *-----------------------------------------------------------------------------
260  */ 
261
262 void save_options(void)
263 {
264         SecureSaveInfo *ssi;
265         gchar *rc_path;
266         gchar *rc_pathl;
267         gint i;
268
269         rc_path = g_strconcat(homedir(), "/", GQ_RC_DIR, "/", RC_FILE_NAME, NULL);
270
271         rc_pathl = path_from_utf8(rc_path);
272         ssi = secure_open(rc_pathl);
273         g_free(rc_pathl);
274         if (!ssi)
275                 {
276                 printf_term(_("error saving config file: %s\n"), rc_path);
277                 g_free(rc_path);
278                 return;
279                 }
280         
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_)
287
288 #define WRITE_SEPARATOR() secure_fputc(ssi, '\n')
289 #define WRITE_SUBTITLE(_title_) secure_fprintf(ssi, "\n\n##### "_title_" #####\n\n")
290
291         secure_fprintf(ssi, "######################################################################\n");
292         secure_fprintf(ssi, "# %30s config file         version %7s #\n", GQ_APPNAME, VERSION);
293         secure_fprintf(ssi, "######################################################################\n");
294         WRITE_SEPARATOR();
295
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");
298         WRITE_SEPARATOR();
299
300         WRITE_SUBTITLE("General Options");
301
302         WRITE_BOOL(show_icon_names);
303         WRITE_SEPARATOR();
304
305         WRITE_BOOL(tree_descend_subdirs);
306         WRITE_BOOL(lazy_image_sync);
307         WRITE_BOOL(update_on_time_change);
308         WRITE_SEPARATOR();
309
310         WRITE_BOOL(startup_path_enable);
311         WRITE_CHAR(startup_path);
312
313         WRITE_BOOL(progressive_key_scrolling);
314         WRITE_BOOL(enable_metadata_dirs);
315
316         WRITE_INT(duplicates_similarity_threshold);
317         WRITE_SEPARATOR();
318
319         WRITE_BOOL(mousewheel_scrolls);
320         WRITE_INT(open_recent_list_maxsize);
321         WRITE_BOOL(place_dialogs_under_mouse);
322
323
324         WRITE_SUBTITLE("File operations Options");
325
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);
332
333         
334         WRITE_SUBTITLE("Layout Options");
335
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);
342         WRITE_SEPARATOR();
343
344         WRITE_BOOL(layout.save_window_positions);
345         WRITE_SEPARATOR();
346
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);
354         WRITE_SEPARATOR();
355
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);
361         WRITE_SEPARATOR();
362
363         WRITE_BOOL(layout.tools_float);
364         WRITE_BOOL(layout.tools_hidden);
365         WRITE_BOOL(layout.tools_restore_state);
366         WRITE_SEPARATOR();
367
368         WRITE_BOOL(layout.toolbar_hidden);
369
370
371         WRITE_SUBTITLE("Image Options");
372         
373         secure_fprintf(ssi, "# image.zoom_mode possible values are:\n"
374                             "#   original\n"
375                             "#   fit\n"
376                             "#   dont_change\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");
384         WRITE_SEPARATOR();
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);
403
404         WRITE_SUBTITLE("Thumbnails Options");
405
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);
414
415
416         WRITE_SUBTITLE("File sorting Options");
417
418         WRITE_INT(file_sort.method);
419         WRITE_BOOL(file_sort.ascending);
420         WRITE_BOOL(file_sort.case_sensitive);
421
422         
423         WRITE_SUBTITLE("Fullscreen Options");
424
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);
431
432         WRITE_SUBTITLE("Slideshow Options");
433
434         WRITE_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
435         WRITE_BOOL(slideshow.random);
436         WRITE_BOOL(slideshow.repeat);
437
438
439         WRITE_SUBTITLE("Collection Options");
440
441         WRITE_BOOL(collections.rectangular_selection);
442
443
444         WRITE_SUBTITLE("Filtering Options");
445
446         WRITE_BOOL(file_filter.show_hidden_files);
447         WRITE_BOOL(file_filter.show_dot_directory);
448         WRITE_BOOL(file_filter.disable);
449         WRITE_SEPARATOR();
450
451         filter_write_list(ssi);
452         
453
454         WRITE_SUBTITLE("Sidecars Options");
455
456         sidecar_ext_write(ssi);
457
458
459         WRITE_SUBTITLE("Color Profiles");
460
461 #ifndef HAVE_LCMS
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);
464 #endif
465
466         WRITE_BOOL(color_profile.enabled);
467         WRITE_BOOL(color_profile.use_image);
468         WRITE_INT(color_profile.input_type);
469         WRITE_SEPARATOR();
470
471         for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
472                 {
473                 gchar *buf;
474
475                 buf = g_strdup_printf("color_profile.input_file_%d", i + 1);
476                 write_char_option(ssi, buf, options->color_profile.input_file[i]);
477                 g_free(buf);
478
479                 buf = g_strdup_printf("color_profile.input_name_%d", i + 1);
480                 write_char_option(ssi, buf, options->color_profile.input_name[i]);
481                 g_free(buf);
482                 }
483
484         WRITE_SEPARATOR();
485         WRITE_INT(color_profile.screen_type);
486         WRITE_CHAR(color_profile.screen_file);
487
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");
492
493         for (i = 0; i < GQ_EDITOR_SLOTS; i++)
494                 {
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);
499                 g_free(qname);
500                 g_free(qcommand);
501                 }
502
503
504         WRITE_SUBTITLE("Exif Options");
505         secure_fprintf(ssi, "# Display: 0: never\n"
506                             "#          1: if set\n"
507                             "#          2: always\n\n");
508         for (i = 0; ExifUIList[i].key; i++)
509                 {
510                 secure_fprintf(ssi, "exif.display.");
511                 write_int_option(ssi, (gchar *)ExifUIList[i].key, ExifUIList[i].current);
512                 }
513
514         WRITE_SEPARATOR();
515         WRITE_SEPARATOR();
516
517         secure_fprintf(ssi, "######################################################################\n");
518         secure_fprintf(ssi, "#                         end of config file                         #\n");
519         secure_fprintf(ssi, "######################################################################\n");
520
521         
522         if (secure_close(ssi))
523                 {
524                 printf_term(_("error saving config file: %s\nerror: %s\n"), rc_path,
525                             secsave_strerror(secsave_errno));
526                 g_free(rc_path);
527                 return;
528                 }
529
530         g_free(rc_path);
531 }
532
533 /*
534  *-----------------------------------------------------------------------------
535  * load configuration (public)
536  *-----------------------------------------------------------------------------
537  */ 
538
539 void load_options(void)
540 {
541         FILE *f;
542         gchar *rc_path;
543         gchar *rc_pathl;
544         gchar s_buf[1024];
545         gchar option[1024];
546         gchar value[1024];
547         gchar value_all[1024];
548         gint i;
549
550         for (i = 0; ExifUIList[i].key; i++)
551                 ExifUIList[i].current = ExifUIList[i].default_value;
552
553         rc_path = g_strconcat(homedir(), "/", GQ_RC_DIR, "/", RC_FILE_NAME, NULL);
554
555         rc_pathl = path_from_utf8(rc_path);
556         f = fopen(rc_pathl,"r");
557         g_free(rc_pathl);
558         if (!f)
559                 {
560                 g_free(rc_path);
561                 return;
562                 }
563
564         while (fgets(s_buf, sizeof(s_buf), f))
565                 {
566                 gchar *option_start, *value_start;
567                 gchar *p = s_buf;
568
569                 while(g_ascii_isspace(*p)) p++;
570                 if (!*p || *p == '\n' || *p == '#') continue;
571                 option_start = p;
572                 while(*p && *p != ':') p++;
573                 if (!*p) continue;
574                 *p = '\0';
575                 p++;
576                 strncpy(option, option_start, sizeof(option));
577                 while(g_ascii_isspace(*p)) p++;
578                 value_start = p;
579                 strncpy(value_all, value_start, sizeof(value_all));
580                 while(*p && !g_ascii_isspace(*p) && *p != '\n') p++;
581                 *p = '\0';
582                 strncpy(value, value_start, sizeof(value));
583
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_)
591
592                 /* general options */
593                 READ_BOOL(show_icon_names);
594
595                 READ_BOOL(tree_descend_subdirs);
596                 READ_BOOL(lazy_image_sync);
597                 READ_BOOL(update_on_time_change);
598         
599                 READ_BOOL(startup_path_enable);
600                 READ_CHAR(startup_path);
601
602                 READ_INT(duplicates_similarity_threshold);
603
604                 READ_BOOL(progressive_key_scrolling);
605
606                 READ_BOOL(enable_metadata_dirs);
607
608                 READ_BOOL(mousewheel_scrolls);
609         
610                 READ_INT(open_recent_list_maxsize);
611
612                 READ_BOOL(place_dialogs_under_mouse);
613
614
615                 /* layout options */
616
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);
623
624                 /* window positions */
625
626                 READ_BOOL(layout.save_window_positions);
627
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);
644
645
646                 /* image options */
647                 if (strcasecmp(option, "image.zoom_mode") == 0)
648                         {
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;
655                         }
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);
674                 
675
676                 /* thumbnails options */
677                 READ_INT_CLAMP(thumbnails.max_width, 16, 512);
678                 READ_INT_CLAMP(thumbnails.max_height, 16, 512);
679
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);
686
687                 /* file sorting options */
688                 READ_UINT(file_sort.method);
689                 READ_BOOL(file_sort.ascending);
690                 READ_BOOL(file_sort.case_sensitive);
691
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);
699
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);
707
708                 /* slideshow options */
709
710                 READ_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
711                 READ_BOOL(slideshow.random);
712                 READ_BOOL(slideshow.repeat);
713
714                 /* collection options */
715
716                 READ_BOOL(collections.rectangular_selection);
717
718                 /* filtering options */
719
720                 READ_BOOL(file_filter.show_hidden_files);
721                 READ_BOOL(file_filter.show_dot_directory);
722                 READ_BOOL(file_filter.disable);
723
724                 if (strcasecmp(option, "file_filter.ext") == 0)
725                         {
726                         filter_parse(value_all);
727                         }
728
729                 if (strcasecmp(option, "sidecar.ext") == 0)
730                         {
731                         sidecar_ext_parse(value_all, TRUE);
732                         }
733                 
734                 /* Color Profiles */
735
736                 READ_BOOL(color_profile.enabled);
737                 READ_BOOL(color_profile.use_image);
738                 READ_INT(color_profile.input_type);
739
740                 if (strncasecmp(option, "color_profile.input_file_", 25) == 0)
741                         {
742                         i = strtol(option + 25, NULL, 0) - 1;
743                         if (i >= 0 && i < COLOR_PROFILE_INPUTS)
744                                 {
745                                 read_char_option(f, option, option, value, &options->color_profile.input_file[i]);
746                                 }
747                         }
748                 if (strncasecmp(option, "color_profile.input_name_", 25) == 0)
749                         {
750                         i = strtol(option + 25, NULL, 0) - 1;
751                         if (i >= 0 && i < COLOR_PROFILE_INPUTS)
752                                 {
753                                 read_char_option(f, option, option, value, &options->color_profile.input_name[i]);
754                                 }
755                         }
756
757                 READ_INT(color_profile.screen_type);
758                 READ_CHAR(color_profile.screen_file);
759
760                 /* External Programs */
761
762                 if (strncasecmp(option, "external_", 9) == 0)
763                         {
764                         i = strtol(option + 9, NULL, 0);
765                         if (i > 0 && i <= GQ_EDITOR_SLOTS)
766                                 {
767                                 const gchar *ptr;
768                                 i--;
769                                 g_free(options->editor_name[i]);
770                                 g_free(options->editor_command[i]);
771                                 
772                                 options->editor_name[i] = quoted_value(value_all, &ptr);
773                                 options->editor_command[i] = quoted_value(ptr, NULL);
774                                 }
775                         }
776
777                 /* Exif */
778                 if (0 == strncasecmp(option, "exif.display.", 13))
779                         {
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);
783                         }
784                 }
785
786         fclose(f);
787         g_free(rc_path);
788 }
789