Use g_ascii_strncasecmp() instead of strncasecmp() where applicable.
[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 "filefilter.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 && g_ascii_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 && g_ascii_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 && g_ascii_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 && g_ascii_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 && g_ascii_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 && g_ascii_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 && g_ascii_strcasecmp(option, label) == 0)
249                 {
250                 if (g_ascii_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         WRITE_BOOL(save_metadata_in_image_file);
318
319         WRITE_INT(duplicates_similarity_threshold);
320         WRITE_SEPARATOR();
321
322         WRITE_BOOL(mousewheel_scrolls);
323         WRITE_INT(open_recent_list_maxsize);
324         WRITE_INT(dnd_icon_size);
325         WRITE_BOOL(place_dialogs_under_mouse);
326
327
328         WRITE_SUBTITLE("File operations Options");
329
330         WRITE_BOOL(file_ops.enable_in_place_rename);
331         WRITE_BOOL(file_ops.confirm_delete);
332         WRITE_BOOL(file_ops.enable_delete_key);
333         WRITE_BOOL(file_ops.safe_delete_enable);
334         WRITE_CHAR(file_ops.safe_delete_path);
335         WRITE_INT(file_ops.safe_delete_folder_maxsize);
336
337
338         WRITE_SUBTITLE("Layout Options");
339
340         WRITE_INT(layout.style);
341         WRITE_CHAR(layout.order);
342         WRITE_UINT(layout.dir_view_type);
343         WRITE_UINT(layout.file_view_type);
344         WRITE_BOOL(layout.show_marks);
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         WRITE_SUBTITLE("Panels Options");
375
376         WRITE_BOOL(panels.exif.enabled);
377         WRITE_INT(panels.exif.width);
378         WRITE_BOOL(panels.info.enabled);
379         WRITE_INT(panels.info.width);
380         WRITE_BOOL(panels.sort.enabled);
381         WRITE_INT(panels.sort.action_state);
382         WRITE_INT(panels.sort.mode_state);
383         WRITE_INT(panels.sort.selection_state);
384
385         WRITE_SUBTITLE("Image Options");
386
387         secure_fprintf(ssi, "# image.zoom_mode possible values are:\n"
388                             "#   original\n"
389                             "#   fit\n"
390                             "#   dont_change\n");
391         secure_fprintf(ssi, "image.zoom_mode: ");
392         if (options->image.zoom_mode == ZOOM_RESET_ORIGINAL)
393                 secure_fprintf(ssi, "original\n");
394         else if (options->image.zoom_mode == ZOOM_RESET_FIT_WINDOW)
395                 secure_fprintf(ssi, "fit\n");
396         else if (options->image.zoom_mode == ZOOM_RESET_NONE)
397                 secure_fprintf(ssi, "dont_change\n");
398         WRITE_SEPARATOR();
399         WRITE_BOOL(image.zoom_2pass);
400         WRITE_BOOL(image.zoom_to_fit_allow_expand);
401         WRITE_INT(image.zoom_quality);
402         WRITE_INT(image.zoom_increment);
403         WRITE_BOOL(image.fit_window_to_image);
404         WRITE_BOOL(image.limit_window_size);
405         WRITE_INT(image.max_window_size);
406         WRITE_BOOL(image.limit_autofit_size);
407         WRITE_INT(image.max_autofit_size);
408         WRITE_INT(image.scroll_reset_method);
409         WRITE_INT(image.tile_cache_max);
410         WRITE_INT(image.dither_quality);
411         WRITE_BOOL(image.enable_read_ahead);
412         WRITE_BOOL(image.exif_rotate_enable);
413         WRITE_BOOL(image.use_custom_border_color);
414         WRITE_COLOR(image.border_color);
415         WRITE_INT(image.read_buffer_size);
416         WRITE_INT(image.idle_read_loop_count);
417
418         WRITE_SUBTITLE("Thumbnails Options");
419
420         WRITE_INT(thumbnails.max_width);
421         WRITE_INT(thumbnails.max_height);
422         WRITE_BOOL(thumbnails.enable_caching);
423         WRITE_BOOL(thumbnails.cache_into_dirs);
424         WRITE_BOOL(thumbnails.fast);
425         WRITE_BOOL(thumbnails.use_xvpics);
426         WRITE_BOOL(thumbnails.spec_standard);
427         WRITE_INT(thumbnails.quality);
428
429
430         WRITE_SUBTITLE("File sorting Options");
431
432         WRITE_INT(file_sort.method);
433         WRITE_BOOL(file_sort.ascending);
434         WRITE_BOOL(file_sort.case_sensitive);
435
436
437         WRITE_SUBTITLE("Fullscreen Options");
438
439         WRITE_INT(fullscreen.screen);
440         WRITE_BOOL(fullscreen.clean_flip);
441         WRITE_BOOL(fullscreen.disable_saver);
442         WRITE_BOOL(fullscreen.above);
443
444         WRITE_SUBTITLE("Image Overlay Options");
445         WRITE_BOOL(image_overlay.common.enabled);
446         WRITE_BOOL(image_overlay.common.show_at_startup);
447         WRITE_CHAR(image_overlay.common.template_string);
448
449         WRITE_SUBTITLE("Slideshow Options");
450
451         WRITE_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
452         WRITE_BOOL(slideshow.random);
453         WRITE_BOOL(slideshow.repeat);
454
455
456         WRITE_SUBTITLE("Collection Options");
457
458         WRITE_BOOL(collections.rectangular_selection);
459
460
461         WRITE_SUBTITLE("Filtering Options");
462
463         WRITE_BOOL(file_filter.show_hidden_files);
464         WRITE_BOOL(file_filter.show_dot_directory);
465         WRITE_BOOL(file_filter.disable);
466         WRITE_SEPARATOR();
467
468         filter_write_list(ssi);
469
470
471         WRITE_SUBTITLE("Sidecars Options");
472
473         sidecar_ext_write(ssi);
474
475
476         WRITE_SUBTITLE("Color Profiles");
477
478 #ifndef HAVE_LCMS
479         secure_fprintf(ssi, "# NOTICE: %s was not built with support for color profiles,\n"
480                             "#         color profile options will have no effect.\n\n", GQ_APPNAME);
481 #endif
482
483         WRITE_BOOL(color_profile.enabled);
484         WRITE_BOOL(color_profile.use_image);
485         WRITE_INT(color_profile.input_type);
486         WRITE_SEPARATOR();
487
488         for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
489                 {
490                 gchar *buf;
491
492                 buf = g_strdup_printf("color_profile.input_file_%d", i + 1);
493                 write_char_option(ssi, buf, options->color_profile.input_file[i]);
494                 g_free(buf);
495
496                 buf = g_strdup_printf("color_profile.input_name_%d", i + 1);
497                 write_char_option(ssi, buf, options->color_profile.input_name[i]);
498                 g_free(buf);
499                 }
500
501         WRITE_SEPARATOR();
502         WRITE_INT(color_profile.screen_type);
503         WRITE_CHAR(color_profile.screen_file);
504
505         WRITE_SUBTITLE("External Programs");
506         secure_fprintf(ssi, "# Maximum of %d programs (external_1 through external_%d)\n", GQ_EDITOR_GENERIC_SLOTS, GQ_EDITOR_GENERIC_SLOTS);
507         secure_fprintf(ssi, "# external_%d through external_%d are used for file ops\n", GQ_EDITOR_GENERIC_SLOTS + 1, GQ_EDITOR_SLOTS);
508         secure_fprintf(ssi, "# format: external_n: \"menu name\" \"command line\"\n\n");
509
510         for (i = 0; i < GQ_EDITOR_SLOTS; i++)
511                 {
512                 if (i == GQ_EDITOR_GENERIC_SLOTS) secure_fputc(ssi, '\n');
513                 gchar *qname = escquote_value(options->editor_name[i]);
514                 gchar *qcommand = escquote_value(options->editor_command[i]);
515                 secure_fprintf(ssi, "external_%d: %s %s\n", i+1, qname, qcommand);
516                 g_free(qname);
517                 g_free(qcommand);
518                 }
519
520
521         WRITE_SUBTITLE("Exif Options");
522         secure_fprintf(ssi, "# Display: 0: never\n"
523                             "#          1: if set\n"
524                             "#          2: always\n\n");
525         for (i = 0; ExifUIList[i].key; i++)
526                 {
527                 secure_fprintf(ssi, "exif.display.");
528                 write_int_option(ssi, (gchar *)ExifUIList[i].key, ExifUIList[i].current);
529                 }
530
531         WRITE_SEPARATOR();
532         WRITE_SEPARATOR();
533
534         secure_fprintf(ssi, "######################################################################\n");
535         secure_fprintf(ssi, "#                         end of config file                         #\n");
536         secure_fprintf(ssi, "######################################################################\n");
537
538
539         if (secure_close(ssi))
540                 printf_term(_("error saving config file: %s\nerror: %s\n"), rc_path,
541                             secsave_strerror(secsave_errno));
542
543         g_free(rc_path);
544 }
545
546 /*
547  *-----------------------------------------------------------------------------
548  * load configuration (public)
549  *-----------------------------------------------------------------------------
550  */
551
552 void load_options(void)
553 {
554         FILE *f;
555         gchar *rc_path;
556         gchar *rc_pathl;
557         gchar s_buf[1024];
558         gchar option[1024];
559         gchar value[1024];
560         gchar value_all[1024];
561         gint i;
562
563         for (i = 0; ExifUIList[i].key; i++)
564                 ExifUIList[i].current = ExifUIList[i].default_value;
565
566         rc_path = g_strconcat(homedir(), "/", GQ_RC_DIR, "/", RC_FILE_NAME, NULL);
567
568         rc_pathl = path_from_utf8(rc_path);
569         f = fopen(rc_pathl,"r");
570         g_free(rc_pathl);
571         if (!f)
572                 {
573                 g_free(rc_path);
574                 return;
575                 }
576
577         while (fgets(s_buf, sizeof(s_buf), f))
578                 {
579                 gchar *option_start, *value_start;
580                 gchar *p = s_buf;
581
582                 while (g_ascii_isspace(*p)) p++;
583                 if (!*p || *p == '\n' || *p == '#') continue;
584                 option_start = p;
585                 while (*p && *p != ':') p++;
586                 if (!*p) continue;
587                 *p = '\0';
588                 p++;
589                 strncpy(option, option_start, sizeof(option));
590                 while (g_ascii_isspace(*p)) p++;
591                 value_start = p;
592                 strncpy(value_all, value_start, sizeof(value_all));
593                 while (*p && !g_ascii_isspace(*p) && *p != '\n') p++;
594                 *p = '\0';
595                 strncpy(value, value_start, sizeof(value));
596
597 #define READ_BOOL(_name_) read_bool_option(f, option, #_name_, value, &options->_name_)
598 #define READ_INT(_name_) read_int_option(f, option, #_name_, value, &options->_name_)
599 #define READ_UINT(_name_) read_uint_option(f, option, #_name_, value, &options->_name_)
600 #define READ_INT_CLAMP(_name_, _min_, _max_) read_int_option_clamp(f, option, #_name_, value, &options->_name_, _min_, _max_)
601 #define READ_INT_UNIT(_name_, _unit_) read_int_unit_option(f, option, #_name_, value, &options->_name_, _unit_)
602 #define READ_CHAR(_name_) read_char_option(f, option, #_name_, value_all, &options->_name_)
603 #define READ_COLOR(_name_) read_color_option(f, option, #_name_, value, &options->_name_)
604
605 #define COMPAT_READ_BOOL(_oldname_, _name_) read_bool_option(f, option, #_oldname_, value, &options->_name_)
606 #define COMPAT_READ_INT(_oldname_, _name_) read_int_option(f, option, #_oldname_, value, &options->_name_)
607 #define COMPAT_READ_UINT(_oldname_, _name_) read_uint_option(f, option, #_oldname_, value, &options->_name_)
608 #define COMPAT_READ_INT_CLAMP(_oldname_, _name_, _min_, _max_) read_int_option_clamp(f, option, #_oldname_, value, &options->_name_, _min_, _max_)
609 #define COMPAT_READ_INT_UNIT(_oldname_, _name_, _unit_) read_int_unit_option(f, option, #_oldname_, value, &options->_name_, _unit_)
610 #define COMPAT_READ_CHAR(_oldname_, _name_) read_char_option(f, option, #_oldname_, value_all, &options->_name_)
611 #define COMPAT_READ_COLOR(_oldname_, _name_) read_color_option(f, option, #_oldname_, value, &options->_name_)
612
613                 /* general options */
614                 READ_BOOL(show_icon_names);
615                 READ_BOOL(show_copy_path);
616
617                 READ_BOOL(tree_descend_subdirs);
618                 READ_BOOL(lazy_image_sync);
619                 READ_BOOL(update_on_time_change);
620
621                 READ_BOOL(startup_path_enable);
622                 READ_CHAR(startup_path);
623
624                 READ_INT(duplicates_similarity_threshold);
625
626                 READ_BOOL(progressive_key_scrolling);
627
628                 READ_BOOL(enable_metadata_dirs);
629                 READ_BOOL(save_metadata_in_image_file);
630
631                 READ_BOOL(mousewheel_scrolls);
632
633                 READ_INT(open_recent_list_maxsize);
634                 READ_INT(dnd_icon_size);
635                 READ_BOOL(place_dialogs_under_mouse);
636
637
638                 /* layout options */
639
640                 READ_INT(layout.style);
641                 READ_CHAR(layout.order);
642                 
643                 COMPAT_READ_UINT(layout.view_as_icons, layout.file_view_type); /* 2008/05/03 */
644
645                 READ_UINT(layout.dir_view_type);
646                 READ_UINT(layout.file_view_type);
647                 READ_BOOL(layout.show_marks);
648                 READ_BOOL(layout.show_thumbnails);
649
650                 /* window positions */
651
652                 READ_BOOL(layout.save_window_positions);
653
654                 READ_INT(layout.main_window.x);
655                 READ_INT(layout.main_window.y);
656                 READ_INT(layout.main_window.w);
657                 READ_INT(layout.main_window.h);
658                 READ_BOOL(layout.main_window.maximized);
659                 READ_INT(layout.float_window.x);
660                 READ_INT(layout.float_window.y);
661                 READ_INT(layout.float_window.w);
662                 READ_INT(layout.float_window.h);
663                 READ_INT(layout.float_window.vdivider_pos);
664                 READ_INT(layout.main_window.hdivider_pos);
665                 READ_INT(layout.main_window.vdivider_pos);
666                 READ_BOOL(layout.tools_float);
667                 READ_BOOL(layout.tools_hidden);
668                 READ_BOOL(layout.tools_restore_state);
669                 READ_BOOL(layout.toolbar_hidden);
670
671                 /* panels */
672                 READ_BOOL(panels.exif.enabled);
673                 READ_INT_CLAMP(panels.exif.width, PANEL_MIN_WIDTH, PANEL_MAX_WIDTH);
674                 READ_BOOL(panels.info.enabled);
675                 READ_INT_CLAMP(panels.info.width, PANEL_MIN_WIDTH, PANEL_MAX_WIDTH);
676                 READ_BOOL(panels.sort.enabled);
677                 READ_INT(panels.sort.action_state);
678                 READ_INT(panels.sort.mode_state);
679                 READ_INT(panels.sort.selection_state);
680
681                 /* image options */
682                 if (g_ascii_strcasecmp(option, "image.zoom_mode") == 0)
683                         {
684                         if (g_ascii_strcasecmp(value, "original") == 0)
685                                 options->image.zoom_mode = ZOOM_RESET_ORIGINAL;
686                         else if (g_ascii_strcasecmp(value, "fit") == 0)
687                                 options->image.zoom_mode = ZOOM_RESET_FIT_WINDOW;
688                         else if (g_ascii_strcasecmp(value, "dont_change") == 0)
689                                 options->image.zoom_mode = ZOOM_RESET_NONE;
690                         }
691                 READ_BOOL(image.zoom_2pass);
692                 READ_BOOL(image.zoom_to_fit_allow_expand);
693                 READ_BOOL(image.fit_window_to_image);
694                 READ_BOOL(image.limit_window_size);
695                 READ_INT(image.max_window_size);
696                 READ_BOOL(image.limit_autofit_size);
697                 READ_INT(image.max_autofit_size);
698                 READ_INT(image.scroll_reset_method);
699                 READ_INT(image.tile_cache_max);
700                 READ_INT_CLAMP(image.zoom_quality, GDK_INTERP_NEAREST, GDK_INTERP_HYPER);
701                 READ_INT_CLAMP(image.dither_quality, GDK_RGB_DITHER_NONE, GDK_RGB_DITHER_MAX);
702                 READ_INT(image.zoom_increment);
703                 READ_BOOL(image.enable_read_ahead);
704                 READ_BOOL(image.exif_rotate_enable);
705                 READ_BOOL(image.use_custom_border_color);
706                 READ_COLOR(image.border_color);
707                 READ_INT_CLAMP(image.read_buffer_size, IMAGE_LOADER_READ_BUFFER_SIZE_MIN, IMAGE_LOADER_READ_BUFFER_SIZE_MAX);
708                 READ_INT_CLAMP(image.idle_read_loop_count, IMAGE_LOADER_IDLE_READ_LOOP_COUNT_MIN, IMAGE_LOADER_IDLE_READ_LOOP_COUNT_MAX);
709
710
711                 /* thumbnails options */
712                 READ_INT_CLAMP(thumbnails.max_width, 16, 512);
713                 READ_INT_CLAMP(thumbnails.max_height, 16, 512);
714
715                 READ_BOOL(thumbnails.enable_caching);
716                 READ_BOOL(thumbnails.cache_into_dirs);
717                 READ_BOOL(thumbnails.fast);
718                 READ_BOOL(thumbnails.use_xvpics);
719                 READ_BOOL(thumbnails.spec_standard);
720                 READ_INT_CLAMP(thumbnails.quality, GDK_INTERP_NEAREST, GDK_INTERP_HYPER);
721
722                 /* file sorting options */
723                 READ_UINT(file_sort.method);
724                 READ_BOOL(file_sort.ascending);
725                 READ_BOOL(file_sort.case_sensitive);
726
727                 /* file operations options */
728                 READ_BOOL(file_ops.enable_in_place_rename);
729                 READ_BOOL(file_ops.confirm_delete);
730                 READ_BOOL(file_ops.enable_delete_key);
731                 READ_BOOL(file_ops.safe_delete_enable);
732                 READ_CHAR(file_ops.safe_delete_path);
733                 READ_INT(file_ops.safe_delete_folder_maxsize);
734
735                 /* fullscreen options */
736                 READ_INT(fullscreen.screen);
737                 READ_BOOL(fullscreen.clean_flip);
738                 READ_BOOL(fullscreen.disable_saver);
739                 READ_BOOL(fullscreen.above);
740
741                 /* image overlay */
742                 COMPAT_READ_BOOL(fullscreen.show_info, image_overlay.common.show_at_startup);
743                 COMPAT_READ_CHAR(fullscreen.info, image_overlay.common.template_string);
744                 READ_BOOL(image_overlay.common.enabled);
745                 READ_BOOL(image_overlay.common.show_at_startup);
746                 READ_CHAR(image_overlay.common.template_string);
747         
748                 /* slideshow options */
749                 READ_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
750                 READ_BOOL(slideshow.random);
751                 READ_BOOL(slideshow.repeat);
752
753                 /* collection options */
754
755                 READ_BOOL(collections.rectangular_selection);
756
757                 /* filtering options */
758
759                 READ_BOOL(file_filter.show_hidden_files);
760                 READ_BOOL(file_filter.show_dot_directory);
761                 READ_BOOL(file_filter.disable);
762
763                 if (g_ascii_strcasecmp(option, "file_filter.ext") == 0)
764                         {
765                         filter_parse(value_all);
766                         }
767
768                 if (g_ascii_strcasecmp(option, "sidecar.ext") == 0)
769                         {
770                         sidecar_ext_parse(value_all, TRUE);
771                         }
772
773                 /* Color Profiles */
774
775                 READ_BOOL(color_profile.enabled);
776                 READ_BOOL(color_profile.use_image);
777                 READ_INT(color_profile.input_type);
778
779                 if (g_ascii_strncasecmp(option, "color_profile.input_file_", 25) == 0)
780                         {
781                         i = strtol(option + 25, NULL, 0) - 1;
782                         if (i >= 0 && i < COLOR_PROFILE_INPUTS)
783                                 {
784                                 read_char_option(f, option, option, value, &options->color_profile.input_file[i]);
785                                 }
786                         }
787                 if (g_ascii_strncasecmp(option, "color_profile.input_name_", 25) == 0)
788                         {
789                         i = strtol(option + 25, NULL, 0) - 1;
790                         if (i >= 0 && i < COLOR_PROFILE_INPUTS)
791                                 {
792                                 read_char_option(f, option, option, value, &options->color_profile.input_name[i]);
793                                 }
794                         }
795
796                 READ_INT(color_profile.screen_type);
797                 READ_CHAR(color_profile.screen_file);
798
799                 /* External Programs */
800
801                 if (g_ascii_strncasecmp(option, "external_", 9) == 0)
802                         {
803                         i = strtol(option + 9, NULL, 0);
804                         if (i > 0 && i <= GQ_EDITOR_SLOTS)
805                                 {
806                                 const gchar *ptr;
807                                 i--;
808                                 g_free(options->editor_name[i]);
809                                 g_free(options->editor_command[i]);
810
811                                 options->editor_name[i] = quoted_value(value_all, &ptr);
812                                 options->editor_command[i] = quoted_value(ptr, NULL);
813                                 }
814                         }
815
816                 /* Exif */
817                 if (0 == g_ascii_strncasecmp(option, "exif.display.", 13))
818                         {
819                         for (i = 0; ExifUIList[i].key; i++)
820                                 if (0 == g_ascii_strcasecmp(option + 13, ExifUIList[i].key))
821                                         ExifUIList[i].current = strtol(value, NULL, 10);
822                         }
823                 }
824
825         fclose(f);
826         g_free(rc_path);
827 }