5dd1f5a179683908b4f53eca51dc44114f4f9a4a
[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                 gchar *buf;
277
278                 buf = g_strdup_printf(_("error saving config file: %s\n"), rc_path);
279                 print_term(buf);
280                 g_free(buf);
281
282                 g_free(rc_path);
283                 return;
284                 }
285         
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_)
292
293 #define WRITE_SEPARATOR() secure_fputc(ssi, '\n')
294 #define WRITE_SUBTITLE(_title_) secure_fprintf(ssi, "\n\n##### "_title_" #####\n\n")
295
296         secure_fprintf(ssi, "######################################################################\n");
297         secure_fprintf(ssi, "# %30s config file         version %7s #\n", GQ_APPNAME, VERSION);
298         secure_fprintf(ssi, "######################################################################\n");
299         WRITE_SEPARATOR();
300
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");
303         WRITE_SEPARATOR();
304
305         WRITE_SUBTITLE("General Options");
306
307         WRITE_BOOL(show_icon_names);
308         WRITE_SEPARATOR();
309
310         WRITE_BOOL(tree_descend_subdirs);
311         WRITE_BOOL(lazy_image_sync);
312         WRITE_BOOL(update_on_time_change);
313         WRITE_SEPARATOR();
314
315         WRITE_BOOL(startup_path_enable);
316         WRITE_CHAR(startup_path);
317
318         WRITE_BOOL(progressive_key_scrolling);
319         WRITE_BOOL(enable_metadata_dirs);
320
321         WRITE_INT(duplicates_similarity_threshold);
322         WRITE_SEPARATOR();
323
324         WRITE_BOOL(mousewheel_scrolls);
325         WRITE_INT(open_recent_list_maxsize);
326         WRITE_BOOL(place_dialogs_under_mouse);
327
328
329         WRITE_SUBTITLE("File operations Options");
330
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);
337
338         
339         WRITE_SUBTITLE("Layout Options");
340
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);
346         WRITE_SEPARATOR();
347
348         WRITE_BOOL(layout.save_window_positions);
349         WRITE_SEPARATOR();
350
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);
358         WRITE_SEPARATOR();
359
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);
365         WRITE_SEPARATOR();
366
367         WRITE_BOOL(layout.tools_float);
368         WRITE_BOOL(layout.tools_hidden);
369         WRITE_BOOL(layout.tools_restore_state);
370         WRITE_SEPARATOR();
371
372         WRITE_BOOL(layout.toolbar_hidden);
373
374
375         WRITE_SUBTITLE("Image Options");
376         
377         secure_fprintf(ssi, "# image.zoom_mode possible values are:\n"
378                             "#   original\n"
379                             "#   fit\n"
380                             "#   dont_change\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");
388         WRITE_SEPARATOR();
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);
405
406
407         WRITE_SUBTITLE("Thumbnails Options");
408
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);
417
418
419         WRITE_SUBTITLE("File sorting Options");
420
421         WRITE_INT(file_sort.method);
422         WRITE_BOOL(file_sort.ascending);
423         WRITE_BOOL(file_sort.case_sensitive);
424
425         
426         WRITE_SUBTITLE("Fullscreen Options");
427
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);
434
435         WRITE_SUBTITLE("Slideshow Options");
436
437         WRITE_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
438         WRITE_BOOL(slideshow.random);
439         WRITE_BOOL(slideshow.repeat);
440
441
442         WRITE_SUBTITLE("Collection Options");
443
444         WRITE_BOOL(collections.rectangular_selection);
445
446
447         WRITE_SUBTITLE("Filtering Options");
448
449         WRITE_BOOL(file_filter.show_hidden_files);
450         WRITE_BOOL(file_filter.show_dot_directory);
451         WRITE_BOOL(file_filter.disable);
452         WRITE_SEPARATOR();
453
454         filter_write_list(ssi);
455         
456
457         WRITE_SUBTITLE("Sidecars Options");
458
459         sidecar_ext_write(ssi);
460
461
462         WRITE_SUBTITLE("Color Profiles");
463
464 #ifndef HAVE_LCMS
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);
467 #endif
468
469         WRITE_BOOL(color_profile.enabled);
470         WRITE_BOOL(color_profile.use_image);
471         WRITE_INT(color_profile.input_type);
472         WRITE_SEPARATOR();
473
474         for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
475                 {
476                 gchar *buf;
477
478                 buf = g_strdup_printf("color_profile.input_file_%d", i + 1);
479                 write_char_option(ssi, buf, options->color_profile.input_file[i]);
480                 g_free(buf);
481
482                 buf = g_strdup_printf("color_profile.input_name_%d", i + 1);
483                 write_char_option(ssi, buf, options->color_profile.input_name[i]);
484                 g_free(buf);
485                 }
486
487         WRITE_SEPARATOR();
488         WRITE_INT(color_profile.screen_type);
489         WRITE_CHAR(color_profile.screen_file);
490
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");
495
496         for (i = 0; i < GQ_EDITOR_SLOTS; i++)
497                 {
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);
502                 g_free(qname);
503                 g_free(qcommand);
504                 }
505
506
507         WRITE_SUBTITLE("Exif Options");
508         secure_fprintf(ssi, "# Display: 0: never\n"
509                             "#          1: if set\n"
510                             "#          2: always\n\n");
511         for (i = 0; ExifUIList[i].key; i++)
512                 {
513                 secure_fprintf(ssi, "exif.display.");
514                 write_int_option(ssi, (gchar *)ExifUIList[i].key, ExifUIList[i].current);
515                 }
516
517         WRITE_SEPARATOR();
518         WRITE_SEPARATOR();
519
520         secure_fprintf(ssi, "######################################################################\n");
521         secure_fprintf(ssi, "#                         end of config file                         #\n");
522         secure_fprintf(ssi, "######################################################################\n");
523
524         
525         if (secure_close(ssi))
526                 {
527                 gchar *buf;
528
529                 buf = g_strdup_printf(_("error saving config file: %s\nerror: %s\n"), rc_path,
530                                       secsave_strerror(secsave_errno));
531                 print_term(buf);
532                 g_free(buf);
533
534                 g_free(rc_path);
535                 return;
536                 }
537
538         g_free(rc_path);
539 }
540
541 /*
542  *-----------------------------------------------------------------------------
543  * load configuration (public)
544  *-----------------------------------------------------------------------------
545  */ 
546
547 void load_options(void)
548 {
549         FILE *f;
550         gchar *rc_path;
551         gchar *rc_pathl;
552         gchar s_buf[1024];
553         gchar option[1024];
554         gchar value[1024];
555         gchar value_all[1024];
556         gint i;
557
558         for (i = 0; ExifUIList[i].key; i++)
559                 ExifUIList[i].current = ExifUIList[i].default_value;
560
561         rc_path = g_strconcat(homedir(), "/", GQ_RC_DIR, "/", RC_FILE_NAME, NULL);
562
563         rc_pathl = path_from_utf8(rc_path);
564         f = fopen(rc_pathl,"r");
565         g_free(rc_pathl);
566         if (!f)
567                 {
568                 g_free(rc_path);
569                 return;
570                 }
571
572         while (fgets(s_buf, sizeof(s_buf), f))
573                 {
574                 gchar *option_start, *value_start;
575                 gchar *p = s_buf;
576
577                 while(g_ascii_isspace(*p)) p++;
578                 if (!*p || *p == '\n' || *p == '#') continue;
579                 option_start = p;
580                 while(*p && *p != ':') p++;
581                 if (!*p) continue;
582                 *p = '\0';
583                 p++;
584                 strncpy(option, option_start, sizeof(option));
585                 while(g_ascii_isspace(*p)) p++;
586                 value_start = p;
587                 strncpy(value_all, value_start, sizeof(value_all));
588                 while(*p && !g_ascii_isspace(*p) && *p != '\n') p++;
589                 *p = '\0';
590                 strncpy(value, value_start, sizeof(value));
591
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_)
599
600                 /* general options */
601                 READ_BOOL(show_icon_names);
602
603                 READ_BOOL(tree_descend_subdirs);
604                 READ_BOOL(lazy_image_sync);
605                 READ_BOOL(update_on_time_change);
606         
607                 READ_BOOL(startup_path_enable);
608                 READ_CHAR(startup_path);
609
610                 READ_INT(duplicates_similarity_threshold);
611
612                 READ_BOOL(progressive_key_scrolling);
613
614                 READ_BOOL(enable_metadata_dirs);
615
616                 READ_BOOL(mousewheel_scrolls);
617         
618                 READ_INT(open_recent_list_maxsize);
619
620                 READ_BOOL(place_dialogs_under_mouse);
621
622
623                 /* layout options */
624
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);
630
631                 /* window positions */
632
633                 READ_BOOL(layout.save_window_positions);
634
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);
651
652
653                 /* image options */
654                 if (strcasecmp(option, "image.zoom_mode") == 0)
655                         {
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;
662                         }
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);
679
680
681                 /* thumbnails options */
682                 READ_INT_CLAMP(thumbnails.max_width, 16, 512);
683                 READ_INT_CLAMP(thumbnails.max_height, 16, 512);
684
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);
691
692                 /* file sorting options */
693                 READ_UINT(file_sort.method);
694                 READ_BOOL(file_sort.ascending);
695                 READ_BOOL(file_sort.case_sensitive);
696
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);
704
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);
712
713                 /* slideshow options */
714
715                 READ_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
716                 READ_BOOL(slideshow.random);
717                 READ_BOOL(slideshow.repeat);
718
719                 /* collection options */
720
721                 READ_BOOL(collections.rectangular_selection);
722
723                 /* filtering options */
724
725                 READ_BOOL(file_filter.show_hidden_files);
726                 READ_BOOL(file_filter.show_dot_directory);
727                 READ_BOOL(file_filter.disable);
728
729                 if (strcasecmp(option, "file_filter.ext") == 0)
730                         {
731                         filter_parse(value_all);
732                         }
733
734                 if (strcasecmp(option, "sidecar.ext") == 0)
735                         {
736                         sidecar_ext_parse(value_all, TRUE);
737                         }
738                 
739                 /* Color Profiles */
740
741                 READ_BOOL(color_profile.enabled);
742                 READ_BOOL(color_profile.use_image);
743                 READ_INT(color_profile.input_type);
744
745                 if (strncasecmp(option, "color_profile.input_file_", 25) == 0)
746                         {
747                         i = strtol(option + 25, NULL, 0) - 1;
748                         if (i >= 0 && i < COLOR_PROFILE_INPUTS)
749                                 {
750                                 read_char_option(f, option, option, value, &options->color_profile.input_file[i]);
751                                 }
752                         }
753                 if (strncasecmp(option, "color_profile.input_name_", 25) == 0)
754                         {
755                         i = strtol(option + 25, NULL, 0) - 1;
756                         if (i >= 0 && i < COLOR_PROFILE_INPUTS)
757                                 {
758                                 read_char_option(f, option, option, value, &options->color_profile.input_name[i]);
759                                 }
760                         }
761
762                 READ_INT(color_profile.screen_type);
763                 READ_CHAR(color_profile.screen_file);
764
765                 /* External Programs */
766
767                 if (strncasecmp(option, "external_", 9) == 0)
768                         {
769                         i = strtol(option + 9, NULL, 0);
770                         if (i > 0 && i <= GQ_EDITOR_SLOTS)
771                                 {
772                                 const gchar *ptr;
773                                 i--;
774                                 g_free(options->editor_name[i]);
775                                 g_free(options->editor_command[i]);
776                                 
777                                 options->editor_name[i] = quoted_value(value_all, &ptr);
778                                 options->editor_command[i] = quoted_value(ptr, NULL);
779                                 }
780                         }
781
782                 /* Exif */
783                 if (0 == strncasecmp(option, "exif.display.", 13))
784                         {
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);
788                         }
789                 }
790
791         fclose(f);
792         g_free(rc_path);
793 }
794