save_options(): minor code simplification.
[geeqie.git] / src / rcfile.c
1 /*
2  * Geeqie
3  * (C) 2006 John Ellis
4  * Copyright (C) 2008 The Geeqie Team
5  *
6  * Author: John Ellis
7  *
8  * This software is released under the GNU General Public License (GNU GPL).
9  * Please read the included file COPYING for more information.
10  * This software comes with no warranty of any kind, use at your own risk!
11  */
12
13 #include <glib/gstdio.h>
14 #include <errno.h>
15
16 #include "main.h"
17 #include "rcfile.h"
18
19 #include "bar_exif.h"
20 #include "filelist.h"
21 #include "secure_save.h"
22 #include "slideshow.h"
23 #include "ui_fileops.h"
24
25
26 /*
27  *-----------------------------------------------------------------------------
28  * line write/parse routines (private)
29  *-----------------------------------------------------------------------------
30  */
31
32 /*
33    returns text without quotes or NULL for empty or broken string
34    any text up to first '"' is skipped
35    tail is set to point at the char after the second '"'
36    or at the ending \0
37
38 */
39
40 gchar *quoted_value(const gchar *text, const gchar **tail)
41 {
42         const gchar *ptr;
43         gint c = 0;
44         gint l = strlen(text);
45         gchar *retval = NULL;
46
47         if (tail) *tail = text;
48
49         if (l == 0) return retval;
50
51         while (c < l && text[c] !='"') c++;
52         if (text[c] == '"')
53                 {
54                 gint e;
55                 c++;
56                 ptr = text + c;
57                 e = c;
58                 while (e < l)
59                         {
60                         if (text[e-1] != '\\' && text[e] == '"') break;
61                         e++;
62                         }
63                 if (text[e] == '"')
64                         {
65                         if (e - c > 0)
66                                 {
67                                 gchar *substring = g_strndup(ptr, e - c);
68
69                                 if (substring)
70                                         {
71                                         retval = g_strcompress(substring);
72                                         g_free(substring);
73                                         }
74                                 }
75                         }
76                 if (tail) *tail = text + e + 1;
77                 }
78         else
79                 /* for compatibility with older formats (<0.3.7)
80                  * read a line without quotes too */
81                 {
82                 c = 0;
83                 while (c < l && text[c] !=' ' && text[c] !=8 && text[c] != '\n') c++;
84                 if (c != 0)
85                         {
86                         retval = g_strndup(text, c);
87                         }
88                 if (tail) *tail = text + c;
89                 }
90
91         return retval;
92 }
93
94 gchar *escquote_value(const gchar *text)
95 {
96         gchar *e;
97
98         if (!text) return g_strdup("\"\"");
99
100         e = g_strescape(text, "");
101         if (e)
102                 {
103                 gchar *retval = g_strdup_printf("\"%s\"", e);
104                 g_free(e);
105                 return retval;
106                 }
107         return g_strdup("\"\"");
108 }
109
110 static void write_char_option(SecureSaveInfo *ssi, gchar *label, gchar *text)
111 {
112         gchar *escval = escquote_value(text);
113
114         secure_fprintf(ssi, "%s: %s\n", label, escval);
115         g_free(escval);
116 }
117
118 static void read_char_option(FILE *f, gchar *option, gchar *label, gchar *value, gchar **text)
119 {
120         if (text && strcasecmp(option, label) == 0)
121                 {
122                 g_free(*text);
123                 *text = quoted_value(value, NULL);
124                 }
125 }
126
127 /* Since gdk_color_to_string() is only available since gtk 2.12
128  * here is an equivalent stub function. */
129 static gchar *color_to_string(GdkColor *color)
130 {
131         return g_strdup_printf("#%04X%04X%04X", color->red, color->green, color->blue);
132 }
133
134 static void write_color_option(SecureSaveInfo *ssi, gchar *label, GdkColor *color)
135 {
136         if (color)
137                 {
138                 gchar *colorstring = color_to_string(color);
139
140                 write_char_option(ssi, label, colorstring);
141                 g_free(colorstring);
142                 }
143         else
144                 secure_fprintf(ssi, "%s: \n", label);
145 }
146
147 static void read_color_option(FILE *f, gchar *option, gchar *label, gchar *value, GdkColor *color)
148 {
149         if (color && strcasecmp(option, label) == 0)
150                 {
151                 gchar *colorstr = quoted_value(value, NULL);
152                 if (colorstr) gdk_color_parse(colorstr, color);
153                 g_free(colorstr);
154                 }
155 }
156
157
158 static void write_int_option(SecureSaveInfo *ssi, gchar *label, gint n)
159 {
160         secure_fprintf(ssi, "%s: %d\n", label, n);
161 }
162
163 static void read_int_option(FILE *f, gchar *option, gchar *label, gchar *value, gint *n)
164 {
165         if (n && strcasecmp(option, label) == 0)
166                 {
167                 *n = strtol(value, NULL, 10);
168                 }
169 }
170
171 static void write_uint_option(SecureSaveInfo *ssi, gchar *label, guint n)
172 {
173         secure_fprintf(ssi, "%s: %u\n", label, n);
174 }
175
176 static void read_uint_option(FILE *f, gchar *option, gchar *label, gchar *value, guint *n)
177 {
178         if (n && strcasecmp(option, label) == 0)
179                 {
180                 *n = strtoul(value, NULL, 10);
181                 }
182 }
183
184
185
186 static void read_int_option_clamp(FILE *f, gchar *option, gchar *label, gchar *value, gint *n, gint min, gint max)
187 {
188         if (n && strcasecmp(option, label) == 0)
189                 {
190                 *n = CLAMP(strtol(value, NULL, 10), min, max);
191                 }
192 }
193
194
195 static void write_int_unit_option(SecureSaveInfo *ssi, gchar *label, gint n, gint subunits)
196 {
197         gint l, r;
198
199         if (subunits > 0)
200                 {
201                 l = n / subunits;
202                 r = n % subunits;
203                 }
204         else
205                 {
206                 l = n;
207                 r = 0;
208                 }
209
210         secure_fprintf(ssi, "%s: %d.%d\n", label, l, r);
211 }
212
213 static void read_int_unit_option(FILE *f, gchar *option, gchar *label, gchar *value, gint *n, gint subunits)
214 {
215         if (n && strcasecmp(option, label) == 0)
216                 {
217                 gint l, r;
218                 gchar *ptr;
219
220                 ptr = value;
221                 while (*ptr != '\0' && *ptr != '.') ptr++;
222                 if (*ptr == '.')
223                         {
224                         *ptr = '\0';
225                         l = strtol(value, NULL, 10);
226                         *ptr = '.';
227                         ptr++;
228                         r = strtol(ptr, NULL, 10);
229                         }
230                 else
231                         {
232                         l = strtol(value, NULL, 10);
233                         r = 0;
234                         }
235
236                 *n = l * subunits + r;
237                 }
238 }
239
240 static void write_bool_option(SecureSaveInfo *ssi, gchar *label, gint n)
241 {
242         secure_fprintf(ssi, "%s: ", label);
243         if (n) secure_fprintf(ssi, "true\n"); else secure_fprintf(ssi, "false\n");
244 }
245
246 static void read_bool_option(FILE *f, gchar *option, gchar *label, gchar *value, gint *n)
247 {
248         if (n && strcasecmp(option, label) == 0)
249                 {
250                 if (strcasecmp(value, "true") == 0 || strcmp(value, "1") == 0)
251                         *n = TRUE;
252                 else
253                         *n = FALSE;
254                 }
255 }
256
257 /*
258  *-----------------------------------------------------------------------------
259  * save configuration (public)
260  *-----------------------------------------------------------------------------
261  */
262
263 void save_options(void)
264 {
265         SecureSaveInfo *ssi;
266         gchar *rc_path;
267         gchar *rc_pathl;
268         gint i;
269
270         rc_path = g_strconcat(homedir(), "/", GQ_RC_DIR, "/", RC_FILE_NAME, NULL);
271
272         rc_pathl = path_from_utf8(rc_path);
273         ssi = secure_open(rc_pathl);
274         g_free(rc_pathl);
275         if (!ssi)
276                 {
277                 printf_term(_("error saving config file: %s\n"), rc_path);
278                 g_free(rc_path);
279                 return;
280                 }
281
282 #define WRITE_BOOL(_name_) write_bool_option(ssi, #_name_, options->_name_)
283 #define WRITE_INT(_name_) write_int_option(ssi, #_name_, options->_name_)
284 #define WRITE_UINT(_name_) write_uint_option(ssi, #_name_, options->_name_)
285 #define WRITE_INT_UNIT(_name_, _unit_) write_int_unit_option(ssi, #_name_, options->_name_, _unit_)
286 #define WRITE_CHAR(_name_) write_char_option(ssi, #_name_, options->_name_)
287 #define WRITE_COLOR(_name_) write_color_option(ssi, #_name_, &options->_name_)
288
289 #define WRITE_SEPARATOR() secure_fputc(ssi, '\n')
290 #define WRITE_SUBTITLE(_title_) secure_fprintf(ssi, "\n\n##### "_title_" #####\n\n")
291
292         secure_fprintf(ssi, "######################################################################\n");
293         secure_fprintf(ssi, "# %30s config file         version %7s #\n", GQ_APPNAME, VERSION);
294         secure_fprintf(ssi, "######################################################################\n");
295         WRITE_SEPARATOR();
296
297         secure_fprintf(ssi, "# Note: This file is autogenerated. Options can be changed here,\n");
298         secure_fprintf(ssi, "#       but user comments and formatting will be lost.\n");
299         WRITE_SEPARATOR();
300
301         WRITE_SUBTITLE("General Options");
302
303         WRITE_BOOL(show_icon_names);
304         WRITE_BOOL(show_copy_path);
305         WRITE_SEPARATOR();
306
307         WRITE_BOOL(tree_descend_subdirs);
308         WRITE_BOOL(lazy_image_sync);
309         WRITE_BOOL(update_on_time_change);
310         WRITE_SEPARATOR();
311
312         WRITE_BOOL(startup_path_enable);
313         WRITE_CHAR(startup_path);
314
315         WRITE_BOOL(progressive_key_scrolling);
316         WRITE_BOOL(enable_metadata_dirs);
317
318         WRITE_INT(duplicates_similarity_threshold);
319         WRITE_SEPARATOR();
320
321         WRITE_BOOL(mousewheel_scrolls);
322         WRITE_INT(open_recent_list_maxsize);
323         WRITE_INT(dnd_icon_size);
324         WRITE_BOOL(place_dialogs_under_mouse);
325
326
327         WRITE_SUBTITLE("File operations Options");
328
329         WRITE_BOOL(file_ops.enable_in_place_rename);
330         WRITE_BOOL(file_ops.confirm_delete);
331         WRITE_BOOL(file_ops.enable_delete_key);
332         WRITE_BOOL(file_ops.safe_delete_enable);
333         WRITE_CHAR(file_ops.safe_delete_path);
334         WRITE_INT(file_ops.safe_delete_folder_maxsize);
335
336
337         WRITE_SUBTITLE("Layout Options");
338
339         WRITE_INT(layout.style);
340         WRITE_CHAR(layout.order);
341         WRITE_BOOL(layout.view_as_icons);
342         WRITE_UINT(layout.dir_view_type);
343         WRITE_BOOL(layout.show_marks);
344         WRITE_BOOL(layout.show_thumbnails);
345         WRITE_SEPARATOR();
346
347         WRITE_BOOL(layout.save_window_positions);
348         WRITE_SEPARATOR();
349
350         WRITE_INT(layout.main_window.x);
351         WRITE_INT(layout.main_window.y);
352         WRITE_INT(layout.main_window.w);
353         WRITE_INT(layout.main_window.h);
354         WRITE_BOOL(layout.main_window.maximized);
355         WRITE_INT(layout.main_window.hdivider_pos);
356         WRITE_INT(layout.main_window.vdivider_pos);
357         WRITE_SEPARATOR();
358
359         WRITE_INT(layout.float_window.x);
360         WRITE_INT(layout.float_window.y);
361         WRITE_INT(layout.float_window.w);
362         WRITE_INT(layout.float_window.h);
363         WRITE_INT(layout.float_window.vdivider_pos);
364         WRITE_SEPARATOR();
365
366         WRITE_BOOL(layout.tools_float);
367         WRITE_BOOL(layout.tools_hidden);
368         WRITE_BOOL(layout.tools_restore_state);
369         WRITE_SEPARATOR();
370
371         WRITE_BOOL(layout.toolbar_hidden);
372
373         WRITE_SUBTITLE("Panels Options");
374
375         WRITE_BOOL(panels.exif.enabled);
376         WRITE_INT(panels.exif.width);
377         WRITE_BOOL(panels.info.enabled);
378         WRITE_INT(panels.info.width);
379         WRITE_BOOL(panels.sort.enabled);
380         WRITE_INT(panels.sort.action_state);
381         WRITE_INT(panels.sort.mode_state);
382         WRITE_INT(panels.sort.selection_state);
383
384         WRITE_SUBTITLE("Image Options");
385
386         secure_fprintf(ssi, "# image.zoom_mode possible values are:\n"
387                             "#   original\n"
388                             "#   fit\n"
389                             "#   dont_change\n");
390         secure_fprintf(ssi, "image.zoom_mode: ");
391         if (options->image.zoom_mode == ZOOM_RESET_ORIGINAL)
392                 secure_fprintf(ssi, "original\n");
393         else if (options->image.zoom_mode == ZOOM_RESET_FIT_WINDOW)
394                 secure_fprintf(ssi, "fit\n");
395         else if (options->image.zoom_mode == ZOOM_RESET_NONE)
396                 secure_fprintf(ssi, "dont_change\n");
397         WRITE_SEPARATOR();
398         WRITE_BOOL(image.zoom_2pass);
399         WRITE_BOOL(image.zoom_to_fit_allow_expand);
400         WRITE_INT(image.zoom_quality);
401         WRITE_INT(image.zoom_increment);
402         WRITE_BOOL(image.fit_window_to_image);
403         WRITE_BOOL(image.limit_window_size);
404         WRITE_INT(image.max_window_size);
405         WRITE_BOOL(image.limit_autofit_size);
406         WRITE_INT(image.max_autofit_size);
407         WRITE_INT(image.scroll_reset_method);
408         WRITE_INT(image.tile_cache_max);
409         WRITE_INT(image.dither_quality);
410         WRITE_BOOL(image.enable_read_ahead);
411         WRITE_BOOL(image.exif_rotate_enable);
412         WRITE_BOOL(image.use_custom_border_color);
413         WRITE_COLOR(image.border_color);
414         WRITE_INT(image.read_buffer_size);
415         WRITE_INT(image.idle_read_loop_count);
416
417         WRITE_SUBTITLE("Thumbnails Options");
418
419         WRITE_INT(thumbnails.max_width);
420         WRITE_INT(thumbnails.max_height);
421         WRITE_BOOL(thumbnails.enable_caching);
422         WRITE_BOOL(thumbnails.cache_into_dirs);
423         WRITE_BOOL(thumbnails.fast);
424         WRITE_BOOL(thumbnails.use_xvpics);
425         WRITE_BOOL(thumbnails.spec_standard);
426         WRITE_INT(thumbnails.quality);
427
428
429         WRITE_SUBTITLE("File sorting Options");
430
431         WRITE_INT(file_sort.method);
432         WRITE_BOOL(file_sort.ascending);
433         WRITE_BOOL(file_sort.case_sensitive);
434
435
436         WRITE_SUBTITLE("Fullscreen Options");
437
438         WRITE_INT(fullscreen.screen);
439         WRITE_BOOL(fullscreen.clean_flip);
440         WRITE_BOOL(fullscreen.disable_saver);
441         WRITE_BOOL(fullscreen.above);
442
443         WRITE_SUBTITLE("Image Overlay Options");
444         WRITE_BOOL(image_overlay.common.enabled);
445         WRITE_BOOL(image_overlay.common.show_at_startup);
446         WRITE_CHAR(image_overlay.common.template_string);
447
448         WRITE_SUBTITLE("Slideshow Options");
449
450         WRITE_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
451         WRITE_BOOL(slideshow.random);
452         WRITE_BOOL(slideshow.repeat);
453
454
455         WRITE_SUBTITLE("Collection Options");
456
457         WRITE_BOOL(collections.rectangular_selection);
458
459
460         WRITE_SUBTITLE("Filtering Options");
461
462         WRITE_BOOL(file_filter.show_hidden_files);
463         WRITE_BOOL(file_filter.show_dot_directory);
464         WRITE_BOOL(file_filter.disable);
465         WRITE_SEPARATOR();
466
467         filter_write_list(ssi);
468
469
470         WRITE_SUBTITLE("Sidecars Options");
471
472         sidecar_ext_write(ssi);
473
474
475         WRITE_SUBTITLE("Color Profiles");
476
477 #ifndef HAVE_LCMS
478         secure_fprintf(ssi, "# NOTICE: %s was not built with support for color profiles,\n"
479                             "#         color profile options will have no effect.\n\n", GQ_APPNAME);
480 #endif
481
482         WRITE_BOOL(color_profile.enabled);
483         WRITE_BOOL(color_profile.use_image);
484         WRITE_INT(color_profile.input_type);
485         WRITE_SEPARATOR();
486
487         for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
488                 {
489                 gchar *buf;
490
491                 buf = g_strdup_printf("color_profile.input_file_%d", i + 1);
492                 write_char_option(ssi, buf, options->color_profile.input_file[i]);
493                 g_free(buf);
494
495                 buf = g_strdup_printf("color_profile.input_name_%d", i + 1);
496                 write_char_option(ssi, buf, options->color_profile.input_name[i]);
497                 g_free(buf);
498                 }
499
500         WRITE_SEPARATOR();
501         WRITE_INT(color_profile.screen_type);
502         WRITE_CHAR(color_profile.screen_file);
503
504         WRITE_SUBTITLE("External Programs");
505         secure_fprintf(ssi, "# Maximum of %d programs (external_1 through external_%d)\n", GQ_EDITOR_GENERIC_SLOTS, GQ_EDITOR_GENERIC_SLOTS);
506         secure_fprintf(ssi, "# external_%d through external_%d are used for file ops\n", GQ_EDITOR_GENERIC_SLOTS + 1, GQ_EDITOR_SLOTS);
507         secure_fprintf(ssi, "# format: external_n: \"menu name\" \"command line\"\n\n");
508
509         for (i = 0; i < GQ_EDITOR_SLOTS; i++)
510                 {
511                 if (i == GQ_EDITOR_GENERIC_SLOTS) secure_fputc(ssi, '\n');
512                 gchar *qname = escquote_value(options->editor_name[i]);
513                 gchar *qcommand = escquote_value(options->editor_command[i]);
514                 secure_fprintf(ssi, "external_%d: %s %s\n", i+1, qname, qcommand);
515                 g_free(qname);
516                 g_free(qcommand);
517                 }
518
519
520         WRITE_SUBTITLE("Exif Options");
521         secure_fprintf(ssi, "# Display: 0: never\n"
522                             "#          1: if set\n"
523                             "#          2: always\n\n");
524         for (i = 0; ExifUIList[i].key; i++)
525                 {
526                 secure_fprintf(ssi, "exif.display.");
527                 write_int_option(ssi, (gchar *)ExifUIList[i].key, ExifUIList[i].current);
528                 }
529
530         WRITE_SEPARATOR();
531         WRITE_SEPARATOR();
532
533         secure_fprintf(ssi, "######################################################################\n");
534         secure_fprintf(ssi, "#                         end of config file                         #\n");
535         secure_fprintf(ssi, "######################################################################\n");
536
537
538         if (secure_close(ssi))
539                 printf_term(_("error saving config file: %s\nerror: %s\n"), rc_path,
540                             secsave_strerror(secsave_errno));
541
542         g_free(rc_path);
543 }
544
545 /*
546  *-----------------------------------------------------------------------------
547  * load configuration (public)
548  *-----------------------------------------------------------------------------
549  */
550
551 void load_options(void)
552 {
553         FILE *f;
554         gchar *rc_path;
555         gchar *rc_pathl;
556         gchar s_buf[1024];
557         gchar option[1024];
558         gchar value[1024];
559         gchar value_all[1024];
560         gint i;
561
562         for (i = 0; ExifUIList[i].key; i++)
563                 ExifUIList[i].current = ExifUIList[i].default_value;
564
565         rc_path = g_strconcat(homedir(), "/", GQ_RC_DIR, "/", RC_FILE_NAME, NULL);
566
567         rc_pathl = path_from_utf8(rc_path);
568         f = fopen(rc_pathl,"r");
569         g_free(rc_pathl);
570         if (!f)
571                 {
572                 g_free(rc_path);
573                 return;
574                 }
575
576         while (fgets(s_buf, sizeof(s_buf), f))
577                 {
578                 gchar *option_start, *value_start;
579                 gchar *p = s_buf;
580
581                 while (g_ascii_isspace(*p)) p++;
582                 if (!*p || *p == '\n' || *p == '#') continue;
583                 option_start = p;
584                 while (*p && *p != ':') p++;
585                 if (!*p) continue;
586                 *p = '\0';
587                 p++;
588                 strncpy(option, option_start, sizeof(option));
589                 while (g_ascii_isspace(*p)) p++;
590                 value_start = p;
591                 strncpy(value_all, value_start, sizeof(value_all));
592                 while (*p && !g_ascii_isspace(*p) && *p != '\n') p++;
593                 *p = '\0';
594                 strncpy(value, value_start, sizeof(value));
595
596 #define READ_BOOL(_name_) read_bool_option(f, option, #_name_, value, &options->_name_)
597 #define READ_INT(_name_) read_int_option(f, option, #_name_, value, &options->_name_)
598 #define READ_UINT(_name_) read_uint_option(f, option, #_name_, value, &options->_name_)
599 #define READ_INT_CLAMP(_name_, _min_, _max_) read_int_option_clamp(f, option, #_name_, value, &options->_name_, _min_, _max_)
600 #define READ_INT_UNIT(_name_, _unit_) read_int_unit_option(f, option, #_name_, value, &options->_name_, _unit_)
601 #define READ_CHAR(_name_) read_char_option(f, option, #_name_, value_all, &options->_name_)
602 #define READ_COLOR(_name_) read_color_option(f, option, #_name_, value, &options->_name_)
603
604 #define COMPAT_READ_BOOL(_oldname_, _name_) read_bool_option(f, option, #_oldname_, value, &options->_name_)
605 #define COMPAT_READ_INT(_oldname_, _name_) read_int_option(f, option, #_oldname_, value, &options->_name_)
606 #define COMPAT_READ_UINT(_oldname_, _name_) read_uint_option(f, option, #_oldname_, value, &options->_name_)
607 #define COMPAT_READ_INT_CLAMP(_oldname_, _name_, _min_, _max_) read_int_option_clamp(f, option, #_oldname_, value, &options->_name_, _min_, _max_)
608 #define COMPAT_READ_INT_UNIT(_oldname_, _name_, _unit_) read_int_unit_option(f, option, #_oldname_, value, &options->_name_, _unit_)
609 #define COMPAT_READ_CHAR(_oldname_, _name_) read_char_option(f, option, #_oldname_, value_all, &options->_name_)
610 #define COMPAT_READ_COLOR(_oldname_, _name_) read_color_option(f, option, #_oldname_, value, &options->_name_)
611
612                 /* general options */
613                 READ_BOOL(show_icon_names);
614                 READ_BOOL(show_copy_path);
615
616                 READ_BOOL(tree_descend_subdirs);
617                 READ_BOOL(lazy_image_sync);
618                 READ_BOOL(update_on_time_change);
619
620                 READ_BOOL(startup_path_enable);
621                 READ_CHAR(startup_path);
622
623                 READ_INT(duplicates_similarity_threshold);
624
625                 READ_BOOL(progressive_key_scrolling);
626
627                 READ_BOOL(enable_metadata_dirs);
628
629                 READ_BOOL(mousewheel_scrolls);
630
631                 READ_INT(open_recent_list_maxsize);
632                 READ_INT(dnd_icon_size);
633                 READ_BOOL(place_dialogs_under_mouse);
634
635
636                 /* layout options */
637
638                 READ_INT(layout.style);
639                 READ_CHAR(layout.order);
640                 READ_BOOL(layout.view_as_icons);
641                 READ_UINT(layout.dir_view_type);
642                 READ_BOOL(layout.show_marks);
643                 READ_BOOL(layout.show_thumbnails);
644
645                 /* window positions */
646
647                 READ_BOOL(layout.save_window_positions);
648
649                 READ_INT(layout.main_window.x);
650                 READ_INT(layout.main_window.y);
651                 READ_INT(layout.main_window.w);
652                 READ_INT(layout.main_window.h);
653                 READ_BOOL(layout.main_window.maximized);
654                 READ_INT(layout.float_window.x);
655                 READ_INT(layout.float_window.y);
656                 READ_INT(layout.float_window.w);
657                 READ_INT(layout.float_window.h);
658                 READ_INT(layout.float_window.vdivider_pos);
659                 READ_INT(layout.main_window.hdivider_pos);
660                 READ_INT(layout.main_window.vdivider_pos);
661                 READ_BOOL(layout.tools_float);
662                 READ_BOOL(layout.tools_hidden);
663                 READ_BOOL(layout.tools_restore_state);
664                 READ_BOOL(layout.toolbar_hidden);
665
666                 /* panels */
667                 READ_BOOL(panels.exif.enabled);
668                 READ_INT_CLAMP(panels.exif.width, PANEL_MIN_WIDTH, PANEL_MAX_WIDTH);
669                 READ_BOOL(panels.info.enabled);
670                 READ_INT_CLAMP(panels.info.width, PANEL_MIN_WIDTH, PANEL_MAX_WIDTH);
671                 READ_BOOL(panels.sort.enabled);
672                 READ_INT(panels.sort.action_state);
673                 READ_INT(panels.sort.mode_state);
674                 READ_INT(panels.sort.selection_state);
675
676                 /* image options */
677                 if (strcasecmp(option, "image.zoom_mode") == 0)
678                         {
679                         if (strcasecmp(value, "original") == 0)
680                                 options->image.zoom_mode = ZOOM_RESET_ORIGINAL;
681                         else if (strcasecmp(value, "fit") == 0)
682                                 options->image.zoom_mode = ZOOM_RESET_FIT_WINDOW;
683                         else if (strcasecmp(value, "dont_change") == 0)
684                                 options->image.zoom_mode = ZOOM_RESET_NONE;
685                         }
686                 READ_BOOL(image.zoom_2pass);
687                 READ_BOOL(image.zoom_to_fit_allow_expand);
688                 READ_BOOL(image.fit_window_to_image);
689                 READ_BOOL(image.limit_window_size);
690                 READ_INT(image.max_window_size);
691                 READ_BOOL(image.limit_autofit_size);
692                 READ_INT(image.max_autofit_size);
693                 READ_INT(image.scroll_reset_method);
694                 READ_INT(image.tile_cache_max);
695                 READ_INT_CLAMP(image.zoom_quality, GDK_INTERP_NEAREST, GDK_INTERP_HYPER);
696                 READ_INT_CLAMP(image.dither_quality, GDK_RGB_DITHER_NONE, GDK_RGB_DITHER_MAX);
697                 READ_INT(image.zoom_increment);
698                 READ_BOOL(image.enable_read_ahead);
699                 READ_BOOL(image.exif_rotate_enable);
700                 READ_BOOL(image.use_custom_border_color);
701                 READ_COLOR(image.border_color);
702                 READ_INT_CLAMP(image.read_buffer_size, IMAGE_LOADER_READ_BUFFER_SIZE_MIN, IMAGE_LOADER_READ_BUFFER_SIZE_MAX);
703                 READ_INT_CLAMP(image.idle_read_loop_count, IMAGE_LOADER_IDLE_READ_LOOP_COUNT_MIN, IMAGE_LOADER_IDLE_READ_LOOP_COUNT_MAX);
704
705
706                 /* thumbnails options */
707                 READ_INT_CLAMP(thumbnails.max_width, 16, 512);
708                 READ_INT_CLAMP(thumbnails.max_height, 16, 512);
709
710                 READ_BOOL(thumbnails.enable_caching);
711                 READ_BOOL(thumbnails.cache_into_dirs);
712                 READ_BOOL(thumbnails.fast);
713                 READ_BOOL(thumbnails.use_xvpics);
714                 READ_BOOL(thumbnails.spec_standard);
715                 READ_INT_CLAMP(thumbnails.quality, GDK_INTERP_NEAREST, GDK_INTERP_HYPER);
716
717                 /* file sorting options */
718                 READ_UINT(file_sort.method);
719                 READ_BOOL(file_sort.ascending);
720                 READ_BOOL(file_sort.case_sensitive);
721
722                 /* file operations options */
723                 READ_BOOL(file_ops.enable_in_place_rename);
724                 READ_BOOL(file_ops.confirm_delete);
725                 READ_BOOL(file_ops.enable_delete_key);
726                 READ_BOOL(file_ops.safe_delete_enable);
727                 READ_CHAR(file_ops.safe_delete_path);
728                 READ_INT(file_ops.safe_delete_folder_maxsize);
729
730                 /* fullscreen options */
731                 READ_INT(fullscreen.screen);
732                 READ_BOOL(fullscreen.clean_flip);
733                 READ_BOOL(fullscreen.disable_saver);
734                 READ_BOOL(fullscreen.above);
735
736                 /* image overlay */
737                 COMPAT_READ_BOOL(fullscreen.show_info, image_overlay.common.show_at_startup);
738                 COMPAT_READ_CHAR(fullscreen.info, image_overlay.common.template_string);
739                 READ_BOOL(image_overlay.common.enabled);
740                 READ_BOOL(image_overlay.common.show_at_startup);
741                 READ_CHAR(image_overlay.common.template_string);
742         
743                 /* slideshow options */
744                 READ_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
745                 READ_BOOL(slideshow.random);
746                 READ_BOOL(slideshow.repeat);
747
748                 /* collection options */
749
750                 READ_BOOL(collections.rectangular_selection);
751
752                 /* filtering options */
753
754                 READ_BOOL(file_filter.show_hidden_files);
755                 READ_BOOL(file_filter.show_dot_directory);
756                 READ_BOOL(file_filter.disable);
757
758                 if (strcasecmp(option, "file_filter.ext") == 0)
759                         {
760                         filter_parse(value_all);
761                         }
762
763                 if (strcasecmp(option, "sidecar.ext") == 0)
764                         {
765                         sidecar_ext_parse(value_all, TRUE);
766                         }
767
768                 /* Color Profiles */
769
770                 READ_BOOL(color_profile.enabled);
771                 READ_BOOL(color_profile.use_image);
772                 READ_INT(color_profile.input_type);
773
774                 if (strncasecmp(option, "color_profile.input_file_", 25) == 0)
775                         {
776                         i = strtol(option + 25, NULL, 0) - 1;
777                         if (i >= 0 && i < COLOR_PROFILE_INPUTS)
778                                 {
779                                 read_char_option(f, option, option, value, &options->color_profile.input_file[i]);
780                                 }
781                         }
782                 if (strncasecmp(option, "color_profile.input_name_", 25) == 0)
783                         {
784                         i = strtol(option + 25, NULL, 0) - 1;
785                         if (i >= 0 && i < COLOR_PROFILE_INPUTS)
786                                 {
787                                 read_char_option(f, option, option, value, &options->color_profile.input_name[i]);
788                                 }
789                         }
790
791                 READ_INT(color_profile.screen_type);
792                 READ_CHAR(color_profile.screen_file);
793
794                 /* External Programs */
795
796                 if (strncasecmp(option, "external_", 9) == 0)
797                         {
798                         i = strtol(option + 9, NULL, 0);
799                         if (i > 0 && i <= GQ_EDITOR_SLOTS)
800                                 {
801                                 const gchar *ptr;
802                                 i--;
803                                 g_free(options->editor_name[i]);
804                                 g_free(options->editor_command[i]);
805
806                                 options->editor_name[i] = quoted_value(value_all, &ptr);
807                                 options->editor_command[i] = quoted_value(ptr, NULL);
808                                 }
809                         }
810
811                 /* Exif */
812                 if (0 == strncasecmp(option, "exif.display.", 13))
813                         {
814                         for (i = 0; ExifUIList[i].key; i++)
815                                 if (0 == strcasecmp(option + 13, ExifUIList[i].key))
816                                         ExifUIList[i].current = strtol(value, NULL, 10);
817                         }
818                 }
819
820         fclose(f);
821         g_free(rc_path);
822 }