Use g_build_filename().
[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 gboolean read_char_option(FILE *f, gchar *option, gchar *label, gchar *value, gchar **text)
119 {
120         if (g_ascii_strcasecmp(option, label) != 0) return FALSE;
121         if (!text) return FALSE;
122
123         g_free(*text);
124         *text = quoted_value(value, NULL);
125         return TRUE;
126 }
127
128 /* Since gdk_color_to_string() is only available since gtk 2.12
129  * here is an equivalent stub function. */
130 static gchar *color_to_string(GdkColor *color)
131 {
132         return g_strdup_printf("#%04X%04X%04X", color->red, color->green, color->blue);
133 }
134
135 static void write_color_option(SecureSaveInfo *ssi, gchar *label, GdkColor *color)
136 {
137         if (color)
138                 {
139                 gchar *colorstring = color_to_string(color);
140
141                 write_char_option(ssi, label, colorstring);
142                 g_free(colorstring);
143                 }
144         else
145                 secure_fprintf(ssi, "%s: \n", label);
146 }
147
148 static gboolean read_color_option(FILE *f, gchar *option, gchar *label, gchar *value, GdkColor *color)
149 {
150         gchar *colorstr;
151         
152         if (g_ascii_strcasecmp(option, label) != 0) return FALSE;
153         if (!color) return FALSE;
154
155         colorstr = quoted_value(value, NULL);
156         if (!colorstr) return FALSE;
157         gdk_color_parse(colorstr, color);
158         g_free(colorstr);
159         return TRUE;
160 }
161
162 static void write_int_option(SecureSaveInfo *ssi, gchar *label, gint n)
163 {
164         secure_fprintf(ssi, "%s: %d\n", label, n);
165 }
166
167 static gboolean read_int_option(FILE *f, gchar *option, gchar *label, gchar *value, gint *n)
168 {       
169         if (g_ascii_strcasecmp(option, label) != 0) return FALSE;
170         if (!n) return FALSE;
171
172         if (g_ascii_isdigit(value[0]) || (value[0] == '-' && g_ascii_isdigit(value[1])))
173                 {
174                 *n = strtol(value, NULL, 10);
175                 }
176         else
177                 {
178                 if (g_ascii_strcasecmp(value, "true") == 0)
179                         *n = 1;
180                 else
181                         *n = 0;
182                 }
183
184         return TRUE;
185 }
186
187 static void write_uint_option(SecureSaveInfo *ssi, gchar *label, guint n)
188 {
189         secure_fprintf(ssi, "%s: %u\n", label, n);
190 }
191
192 static gboolean read_uint_option(FILE *f, gchar *option, gchar *label, gchar *value, guint *n)
193 {
194         if (g_ascii_strcasecmp(option, label) != 0) return FALSE;
195         if (!n) return FALSE;
196
197         if (g_ascii_isdigit(value[0]))
198                 {
199                 *n = strtoul(value, NULL, 10);
200                 }
201         else
202                 {
203                 if (g_ascii_strcasecmp(value, "true") == 0)
204                         *n = 1;
205                 else
206                         *n = 0;
207                 }
208         
209         return TRUE;
210 }
211
212 static gboolean read_int_option_clamp(FILE *f, gchar *option, gchar *label, gchar *value, gint *n, gint min, gint max)
213 {
214         gboolean ret;
215
216         ret = read_int_option(f, option, label, value, n);
217         if (ret) *n = CLAMP(*n, min, max);
218
219         return ret;
220 }
221
222 static void write_int_unit_option(SecureSaveInfo *ssi, gchar *label, gint n, gint subunits)
223 {
224         gint l, r;
225
226         if (subunits > 0)
227                 {
228                 l = n / subunits;
229                 r = n % subunits;
230                 }
231         else
232                 {
233                 l = n;
234                 r = 0;
235                 }
236
237         secure_fprintf(ssi, "%s: %d.%d\n", label, l, r);
238 }
239
240 static gboolean read_int_unit_option(FILE *f, gchar *option, gchar *label, gchar *value, gint *n, gint subunits)
241 {
242         gint l, r;
243         gchar *ptr;
244
245         if (g_ascii_strcasecmp(option, label) != 0) return FALSE;
246         if (!n) return FALSE;
247
248         ptr = value;
249         while (*ptr != '\0' && *ptr != '.') ptr++;
250         if (*ptr == '.')
251                 {
252                 *ptr = '\0';
253                 l = strtol(value, NULL, 10);
254                 *ptr = '.';
255                 ptr++;
256                 r = strtol(ptr, NULL, 10);
257                 }
258         else
259                 {
260                 l = strtol(value, NULL, 10);
261                 r = 0;
262                 }
263
264         *n = l * subunits + r;
265
266         return TRUE;
267 }
268
269 static void write_bool_option(SecureSaveInfo *ssi, gchar *label, gint n)
270 {
271         secure_fprintf(ssi, "%s: ", label);
272         if (n) secure_fprintf(ssi, "true\n"); else secure_fprintf(ssi, "false\n");
273 }
274
275 static gboolean read_bool_option(FILE *f, gchar *option, gchar *label, gchar *value, gint *n)
276 {
277         if (g_ascii_strcasecmp(option, label) != 0) return FALSE;
278         if (!n) return FALSE;
279
280         if (g_ascii_strcasecmp(value, "true") == 0 || atoi(value) != 0)
281                 *n = TRUE;
282         else
283                 *n = FALSE;
284
285         return TRUE;
286 }
287
288
289 /*
290  *-----------------------------------------------------------------------------
291  * save configuration (public)
292  *-----------------------------------------------------------------------------
293  */
294
295 void save_options(void)
296 {
297         SecureSaveInfo *ssi;
298         gchar *rc_path;
299         gchar *rc_pathl;
300         gint i;
301
302         rc_path = g_build_filename(homedir(), GQ_RC_DIR, RC_FILE_NAME, NULL);
303
304         rc_pathl = path_from_utf8(rc_path);
305         ssi = secure_open(rc_pathl);
306         g_free(rc_pathl);
307         if (!ssi)
308                 {
309                 log_printf(_("error saving config file: %s\n"), rc_path);
310                 g_free(rc_path);
311                 return;
312                 }
313
314 #define WRITE_BOOL(_name_) write_bool_option(ssi, #_name_, options->_name_)
315 #define WRITE_INT(_name_) write_int_option(ssi, #_name_, options->_name_)
316 #define WRITE_UINT(_name_) write_uint_option(ssi, #_name_, options->_name_)
317 #define WRITE_INT_UNIT(_name_, _unit_) write_int_unit_option(ssi, #_name_, options->_name_, _unit_)
318 #define WRITE_CHAR(_name_) write_char_option(ssi, #_name_, options->_name_)
319 #define WRITE_COLOR(_name_) write_color_option(ssi, #_name_, &options->_name_)
320
321 #define WRITE_SEPARATOR() secure_fputc(ssi, '\n')
322 #define WRITE_SUBTITLE(_title_) secure_fprintf(ssi, "\n\n##### "_title_" #####\n\n")
323
324         secure_fprintf(ssi, "######################################################################\n");
325         secure_fprintf(ssi, "# %30s config file      version %-10s #\n", GQ_APPNAME, VERSION);
326         secure_fprintf(ssi, "######################################################################\n");
327         WRITE_SEPARATOR();
328
329         secure_fprintf(ssi, "# Note: This file is autogenerated. Options can be changed here,\n");
330         secure_fprintf(ssi, "#       but user comments and formatting will be lost.\n");
331         WRITE_SEPARATOR();
332
333         WRITE_SUBTITLE("General Options");
334
335         WRITE_BOOL(show_icon_names);
336         WRITE_BOOL(show_copy_path);
337         WRITE_SEPARATOR();
338
339         WRITE_BOOL(tree_descend_subdirs);
340         WRITE_BOOL(lazy_image_sync);
341         WRITE_BOOL(update_on_time_change);
342         WRITE_SEPARATOR();
343
344         WRITE_BOOL(progressive_key_scrolling);
345         WRITE_BOOL(enable_metadata_dirs);
346         WRITE_BOOL(save_metadata_in_image_file);
347
348         WRITE_INT(duplicates_similarity_threshold);
349         WRITE_SEPARATOR();
350
351         WRITE_BOOL(mousewheel_scrolls);
352         WRITE_INT(open_recent_list_maxsize);
353         WRITE_INT(dnd_icon_size);
354         WRITE_BOOL(place_dialogs_under_mouse);
355
356
357         WRITE_SUBTITLE("Startup Options");
358
359         WRITE_BOOL(startup.restore_path);
360         WRITE_BOOL(startup.use_last_path);
361         WRITE_CHAR(startup.path);
362
363
364         WRITE_SUBTITLE("File operations Options");
365
366         WRITE_BOOL(file_ops.enable_in_place_rename);
367         WRITE_BOOL(file_ops.confirm_delete);
368         WRITE_BOOL(file_ops.enable_delete_key);
369         WRITE_BOOL(file_ops.safe_delete_enable);
370         WRITE_CHAR(file_ops.safe_delete_path);
371         WRITE_INT(file_ops.safe_delete_folder_maxsize);
372
373
374         WRITE_SUBTITLE("Layout Options");
375
376         WRITE_INT(layout.style);
377         WRITE_CHAR(layout.order);
378         WRITE_UINT(layout.dir_view_type);
379         WRITE_UINT(layout.file_view_type);
380         WRITE_BOOL(layout.show_marks);
381         WRITE_BOOL(layout.show_thumbnails);
382         WRITE_SEPARATOR();
383
384         WRITE_BOOL(layout.save_window_positions);
385         WRITE_SEPARATOR();
386
387         WRITE_INT(layout.main_window.x);
388         WRITE_INT(layout.main_window.y);
389         WRITE_INT(layout.main_window.w);
390         WRITE_INT(layout.main_window.h);
391         WRITE_BOOL(layout.main_window.maximized);
392         WRITE_INT(layout.main_window.hdivider_pos);
393         WRITE_INT(layout.main_window.vdivider_pos);
394         WRITE_SEPARATOR();
395
396         WRITE_INT(layout.float_window.x);
397         WRITE_INT(layout.float_window.y);
398         WRITE_INT(layout.float_window.w);
399         WRITE_INT(layout.float_window.h);
400         WRITE_INT(layout.float_window.vdivider_pos);
401         WRITE_SEPARATOR();
402
403         WRITE_BOOL(layout.tools_float);
404         WRITE_BOOL(layout.tools_hidden);
405         WRITE_BOOL(layout.tools_restore_state);
406         WRITE_SEPARATOR();
407
408         WRITE_BOOL(layout.toolbar_hidden);
409
410         WRITE_SUBTITLE("Panels Options");
411
412         WRITE_BOOL(panels.exif.enabled);
413         WRITE_INT(panels.exif.width);
414         WRITE_BOOL(panels.info.enabled);
415         WRITE_INT(panels.info.width);
416         WRITE_BOOL(panels.sort.enabled);
417         WRITE_INT(panels.sort.action_state);
418         WRITE_INT(panels.sort.mode_state);
419         WRITE_INT(panels.sort.selection_state);
420
421         WRITE_SUBTITLE("Properties dialog Options");
422         WRITE_CHAR(properties.tabs_order);
423
424         WRITE_SUBTITLE("Image Options");
425
426         secure_fprintf(ssi, "# image.zoom_mode possible values are:\n"
427                             "#   original\n"
428                             "#   fit\n"
429                             "#   dont_change\n");
430         secure_fprintf(ssi, "image.zoom_mode: ");
431         if (options->image.zoom_mode == ZOOM_RESET_ORIGINAL)
432                 secure_fprintf(ssi, "original\n");
433         else if (options->image.zoom_mode == ZOOM_RESET_FIT_WINDOW)
434                 secure_fprintf(ssi, "fit\n");
435         else if (options->image.zoom_mode == ZOOM_RESET_NONE)
436                 secure_fprintf(ssi, "dont_change\n");
437         WRITE_SEPARATOR();
438         WRITE_BOOL(image.zoom_2pass);
439         WRITE_BOOL(image.zoom_to_fit_allow_expand);
440         WRITE_INT(image.zoom_quality);
441         WRITE_INT(image.zoom_increment);
442         WRITE_BOOL(image.fit_window_to_image);
443         WRITE_BOOL(image.limit_window_size);
444         WRITE_INT(image.max_window_size);
445         WRITE_BOOL(image.limit_autofit_size);
446         WRITE_INT(image.max_autofit_size);
447         WRITE_INT(image.scroll_reset_method);
448         WRITE_INT(image.tile_cache_max);
449         WRITE_INT(image.dither_quality);
450         WRITE_BOOL(image.enable_read_ahead);
451         WRITE_BOOL(image.exif_rotate_enable);
452         WRITE_BOOL(image.use_custom_border_color);
453         WRITE_COLOR(image.border_color);
454         WRITE_INT(image.read_buffer_size);
455         WRITE_INT(image.idle_read_loop_count);
456
457         WRITE_SUBTITLE("Thumbnails Options");
458
459         WRITE_INT(thumbnails.max_width);
460         WRITE_INT(thumbnails.max_height);
461         WRITE_BOOL(thumbnails.enable_caching);
462         WRITE_BOOL(thumbnails.cache_into_dirs);
463         WRITE_BOOL(thumbnails.fast);
464         WRITE_BOOL(thumbnails.use_xvpics);
465         WRITE_BOOL(thumbnails.spec_standard);
466         WRITE_INT(thumbnails.quality);
467
468
469         WRITE_SUBTITLE("File sorting Options");
470
471         WRITE_INT(file_sort.method);
472         WRITE_BOOL(file_sort.ascending);
473         WRITE_BOOL(file_sort.case_sensitive);
474
475
476         WRITE_SUBTITLE("Fullscreen Options");
477
478         WRITE_INT(fullscreen.screen);
479         WRITE_BOOL(fullscreen.clean_flip);
480         WRITE_BOOL(fullscreen.disable_saver);
481         WRITE_BOOL(fullscreen.above);
482
483
484         WRITE_SUBTITLE("Histogram Options");
485         WRITE_UINT(histogram.last_channel_mode);
486         WRITE_UINT(histogram.last_log_mode);
487
488
489         WRITE_SUBTITLE("Image Overlay Options");
490         WRITE_UINT(image_overlay.common.state);
491         WRITE_BOOL(image_overlay.common.show_at_startup);
492         WRITE_CHAR(image_overlay.common.template_string);
493
494
495         WRITE_SUBTITLE("Slideshow Options");
496
497         WRITE_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
498         WRITE_BOOL(slideshow.random);
499         WRITE_BOOL(slideshow.repeat);
500
501
502         WRITE_SUBTITLE("Collection Options");
503
504         WRITE_BOOL(collections.rectangular_selection);
505
506
507         WRITE_SUBTITLE("Filtering Options");
508
509         WRITE_BOOL(file_filter.show_hidden_files);
510         WRITE_BOOL(file_filter.show_dot_directory);
511         WRITE_BOOL(file_filter.disable);
512         WRITE_SEPARATOR();
513
514         filter_write_list(ssi);
515
516
517         WRITE_SUBTITLE("Sidecars Options");
518
519         sidecar_ext_write(ssi);
520
521
522         WRITE_SUBTITLE("Color Profiles");
523
524 #ifndef HAVE_LCMS
525         secure_fprintf(ssi, "# NOTICE: %s was not built with support for color profiles,\n"
526                             "#         color profile options will have no effect.\n\n", GQ_APPNAME);
527 #endif
528
529         WRITE_BOOL(color_profile.enabled);
530         WRITE_BOOL(color_profile.use_image);
531         WRITE_INT(color_profile.input_type);
532         WRITE_SEPARATOR();
533
534         for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
535                 {
536                 gchar *buf;
537
538                 buf = g_strdup_printf("color_profile.input_file_%d", i + 1);
539                 write_char_option(ssi, buf, options->color_profile.input_file[i]);
540                 g_free(buf);
541
542                 buf = g_strdup_printf("color_profile.input_name_%d", i + 1);
543                 write_char_option(ssi, buf, options->color_profile.input_name[i]);
544                 g_free(buf);
545                 }
546
547         WRITE_SEPARATOR();
548         WRITE_INT(color_profile.screen_type);
549         WRITE_CHAR(color_profile.screen_file);
550
551         WRITE_SUBTITLE("External Programs");
552         secure_fprintf(ssi, "# Maximum of %d programs (external_1 through external_%d)\n", GQ_EDITOR_GENERIC_SLOTS, GQ_EDITOR_GENERIC_SLOTS);
553         secure_fprintf(ssi, "# external_%d through external_%d are used for file ops\n", GQ_EDITOR_GENERIC_SLOTS + 1, GQ_EDITOR_SLOTS);
554         secure_fprintf(ssi, "# format: external_n: \"menu name\" \"command line\"\n\n");
555
556         for (i = 0; i < GQ_EDITOR_SLOTS; i++)
557                 {
558                 if (i == GQ_EDITOR_GENERIC_SLOTS) secure_fputc(ssi, '\n');
559                 gchar *qname = escquote_value(options->editor_name[i]);
560                 gchar *qcommand = escquote_value(options->editor_command[i]);
561                 secure_fprintf(ssi, "external_%d: %s %s\n", i+1, qname, qcommand);
562                 g_free(qname);
563                 g_free(qcommand);
564                 }
565
566
567         WRITE_SUBTITLE("Exif Options");
568         secure_fprintf(ssi, "# Display: 0: never\n"
569                             "#          1: if set\n"
570                             "#          2: always\n\n");
571         for (i = 0; ExifUIList[i].key; i++)
572                 {
573                 secure_fprintf(ssi, "exif.display.");
574                 write_int_option(ssi, (gchar *)ExifUIList[i].key, ExifUIList[i].current);
575                 }
576
577         WRITE_SEPARATOR();
578         WRITE_SEPARATOR();
579
580         secure_fprintf(ssi, "######################################################################\n");
581         secure_fprintf(ssi, "#                         end of config file                         #\n");
582         secure_fprintf(ssi, "######################################################################\n");
583
584
585         if (secure_close(ssi))
586                 log_printf(_("error saving config file: %s\nerror: %s\n"), rc_path,
587                             secsave_strerror(secsave_errno));
588
589         g_free(rc_path);
590 }
591
592 /*
593  *-----------------------------------------------------------------------------
594  * load configuration (public)
595  *-----------------------------------------------------------------------------
596  */
597
598 void load_options(void)
599 {
600         FILE *f;
601         gchar *rc_path;
602         gchar *rc_pathl;
603         gchar s_buf[1024];
604         gchar option[1024];
605         gchar value[1024];
606         gchar value_all[1024];
607         gint i;
608
609         for (i = 0; ExifUIList[i].key; i++)
610                 ExifUIList[i].current = ExifUIList[i].default_value;
611
612         rc_path = g_build_filename(homedir(), GQ_RC_DIR, RC_FILE_NAME, NULL);
613
614         rc_pathl = path_from_utf8(rc_path);
615         f = fopen(rc_pathl,"r");
616         g_free(rc_pathl);
617         if (!f)
618                 {
619                 g_free(rc_path);
620                 return;
621                 }
622
623         while (fgets(s_buf, sizeof(s_buf), f))
624                 {
625                 gchar *option_start, *value_start;
626                 gchar *p = s_buf;
627
628                 while (g_ascii_isspace(*p)) p++;
629                 if (!*p || *p == '\n' || *p == '#') continue;
630                 option_start = p;
631                 while (*p && *p != ':') p++;
632                 if (!*p) continue;
633                 *p = '\0';
634                 p++;
635                 strncpy(option, option_start, sizeof(option));
636                 while (g_ascii_isspace(*p)) p++;
637                 value_start = p;
638                 strncpy(value_all, value_start, sizeof(value_all));
639                 while (*p && !g_ascii_isspace(*p) && *p != '\n') p++;
640                 *p = '\0';
641                 strncpy(value, value_start, sizeof(value));
642
643 #define READ_BOOL(_name_) if (read_bool_option(f, option, #_name_, value, &options->_name_)) continue;
644 #define READ_INT(_name_) if (read_int_option(f, option, #_name_, value, &options->_name_)) continue;
645 #define READ_UINT(_name_) if (read_uint_option(f, option, #_name_, value, &options->_name_)) continue;
646 #define READ_INT_CLAMP(_name_, _min_, _max_) if (read_int_option_clamp(f, option, #_name_, value, &options->_name_, _min_, _max_)) continue;
647 #define READ_INT_UNIT(_name_, _unit_) if (read_int_unit_option(f, option, #_name_, value, &options->_name_, _unit_)) continue;
648 #define READ_CHAR(_name_) if (read_char_option(f, option, #_name_, value_all, &options->_name_)) continue;
649 #define READ_COLOR(_name_) if (read_color_option(f, option, #_name_, value, &options->_name_)) continue;
650
651 #define COMPAT_READ_BOOL(_oldname_, _name_) if (read_bool_option(f, option, #_oldname_, value, &options->_name_)) continue;
652 #define COMPAT_READ_INT(_oldname_, _name_) if (read_int_option(f, option, #_oldname_, value, &options->_name_)) continue;
653 #define COMPAT_READ_UINT(_oldname_, _name_) if (read_uint_option(f, option, #_oldname_, value, &options->_name_)) continue;
654 #define COMPAT_READ_INT_CLAMP(_oldname_, _name_, _min_, _max_) if (read_int_option_clamp(f, option, #_oldname_, value, &options->_name_, _min_, _max_)) continue;
655 #define COMPAT_READ_INT_UNIT(_oldname_, _name_, _unit_) if (read_int_unit_option(f, option, #_oldname_, value, &options->_name_, _unit_)) continue;
656 #define COMPAT_READ_CHAR(_oldname_, _name_) if (read_char_option(f, option, #_oldname_, value_all, &options->_name_)) continue;
657 #define COMPAT_READ_COLOR(_oldname_, _name_) if (read_color_option(f, option, #_oldname_, value, &options->_name_)) continue;
658
659                 /* general options */
660                 READ_BOOL(show_icon_names);
661                 READ_BOOL(show_copy_path);
662
663                 READ_BOOL(tree_descend_subdirs);
664                 READ_BOOL(lazy_image_sync);
665                 READ_BOOL(update_on_time_change);
666
667                 READ_INT(duplicates_similarity_threshold);
668
669                 READ_BOOL(progressive_key_scrolling);
670
671                 READ_BOOL(enable_metadata_dirs);
672                 READ_BOOL(save_metadata_in_image_file);
673
674                 READ_BOOL(mousewheel_scrolls);
675
676                 READ_INT(open_recent_list_maxsize);
677                 READ_INT(dnd_icon_size);
678                 READ_BOOL(place_dialogs_under_mouse);
679
680                 /* startup options */
681                 
682                 COMPAT_READ_BOOL(startup_path_enable, startup.restore_path); /* 2008/05/11 */
683                 READ_BOOL(startup.restore_path);
684
685                 READ_BOOL(startup.use_last_path);
686
687                 COMPAT_READ_CHAR(startup_path, startup.path); /* 2008/05/11 */
688                 READ_CHAR(startup.path);
689         
690                 /* layout options */
691
692                 READ_INT(layout.style);
693                 READ_CHAR(layout.order);
694                 
695                 COMPAT_READ_UINT(layout.view_as_icons, layout.file_view_type); /* 2008/05/03 */
696
697                 READ_UINT(layout.dir_view_type);
698                 READ_UINT(layout.file_view_type);
699                 READ_BOOL(layout.show_marks);
700                 READ_BOOL(layout.show_thumbnails);
701
702                 /* window positions */
703
704                 READ_BOOL(layout.save_window_positions);
705
706                 READ_INT(layout.main_window.x);
707                 READ_INT(layout.main_window.y);
708                 READ_INT(layout.main_window.w);
709                 READ_INT(layout.main_window.h);
710                 READ_BOOL(layout.main_window.maximized);
711                 READ_INT(layout.float_window.x);
712                 READ_INT(layout.float_window.y);
713                 READ_INT(layout.float_window.w);
714                 READ_INT(layout.float_window.h);
715                 READ_INT(layout.float_window.vdivider_pos);
716                 READ_INT(layout.main_window.hdivider_pos);
717                 READ_INT(layout.main_window.vdivider_pos);
718                 READ_BOOL(layout.tools_float);
719                 READ_BOOL(layout.tools_hidden);
720                 READ_BOOL(layout.tools_restore_state);
721                 READ_BOOL(layout.toolbar_hidden);
722
723                 /* panels */
724                 READ_BOOL(panels.exif.enabled);
725                 READ_INT_CLAMP(panels.exif.width, PANEL_MIN_WIDTH, PANEL_MAX_WIDTH);
726                 READ_BOOL(panels.info.enabled);
727                 READ_INT_CLAMP(panels.info.width, PANEL_MIN_WIDTH, PANEL_MAX_WIDTH);
728                 READ_BOOL(panels.sort.enabled);
729                 READ_INT(panels.sort.action_state);
730                 READ_INT(panels.sort.mode_state);
731                 READ_INT(panels.sort.selection_state);
732
733                 /* properties dialog options */
734                 READ_CHAR(properties.tabs_order);
735
736                 /* image options */
737                 if (g_ascii_strcasecmp(option, "image.zoom_mode") == 0)
738                         {
739                         if (g_ascii_strcasecmp(value, "original") == 0)
740                                 options->image.zoom_mode = ZOOM_RESET_ORIGINAL;
741                         else if (g_ascii_strcasecmp(value, "fit") == 0)
742                                 options->image.zoom_mode = ZOOM_RESET_FIT_WINDOW;
743                         else if (g_ascii_strcasecmp(value, "dont_change") == 0)
744                                 options->image.zoom_mode = ZOOM_RESET_NONE;
745                         continue;
746                         }
747                 READ_BOOL(image.zoom_2pass);
748                 READ_BOOL(image.zoom_to_fit_allow_expand);
749                 READ_BOOL(image.fit_window_to_image);
750                 READ_BOOL(image.limit_window_size);
751                 READ_INT(image.max_window_size);
752                 READ_BOOL(image.limit_autofit_size);
753                 READ_INT(image.max_autofit_size);
754                 READ_INT(image.scroll_reset_method);
755                 READ_INT(image.tile_cache_max);
756                 READ_INT_CLAMP(image.zoom_quality, GDK_INTERP_NEAREST, GDK_INTERP_HYPER);
757                 READ_INT_CLAMP(image.dither_quality, GDK_RGB_DITHER_NONE, GDK_RGB_DITHER_MAX);
758                 READ_INT(image.zoom_increment);
759                 READ_BOOL(image.enable_read_ahead);
760                 READ_BOOL(image.exif_rotate_enable);
761                 READ_BOOL(image.use_custom_border_color);
762                 READ_COLOR(image.border_color);
763                 READ_INT_CLAMP(image.read_buffer_size, IMAGE_LOADER_READ_BUFFER_SIZE_MIN, IMAGE_LOADER_READ_BUFFER_SIZE_MAX);
764                 READ_INT_CLAMP(image.idle_read_loop_count, IMAGE_LOADER_IDLE_READ_LOOP_COUNT_MIN, IMAGE_LOADER_IDLE_READ_LOOP_COUNT_MAX);
765
766
767                 /* thumbnails options */
768                 READ_INT_CLAMP(thumbnails.max_width, 16, 512);
769                 READ_INT_CLAMP(thumbnails.max_height, 16, 512);
770
771                 READ_BOOL(thumbnails.enable_caching);
772                 READ_BOOL(thumbnails.cache_into_dirs);
773                 READ_BOOL(thumbnails.fast);
774                 READ_BOOL(thumbnails.use_xvpics);
775                 READ_BOOL(thumbnails.spec_standard);
776                 READ_INT_CLAMP(thumbnails.quality, GDK_INTERP_NEAREST, GDK_INTERP_HYPER);
777
778                 /* file sorting options */
779                 READ_UINT(file_sort.method);
780                 READ_BOOL(file_sort.ascending);
781                 READ_BOOL(file_sort.case_sensitive);
782
783                 /* file operations options */
784                 READ_BOOL(file_ops.enable_in_place_rename);
785                 READ_BOOL(file_ops.confirm_delete);
786                 READ_BOOL(file_ops.enable_delete_key);
787                 READ_BOOL(file_ops.safe_delete_enable);
788                 READ_CHAR(file_ops.safe_delete_path);
789                 READ_INT(file_ops.safe_delete_folder_maxsize);
790
791                 /* fullscreen options */
792                 READ_INT(fullscreen.screen);
793                 READ_BOOL(fullscreen.clean_flip);
794                 READ_BOOL(fullscreen.disable_saver);
795                 READ_BOOL(fullscreen.above);
796
797                 /* histogram */
798                 READ_UINT(histogram.last_channel_mode);
799                 READ_UINT(histogram.last_log_mode);
800
801                 /* image overlay */
802                 COMPAT_READ_UINT(image_overlay.common.enabled, image_overlay.common.state); /* 2008-05-12 */ 
803                 READ_UINT(image_overlay.common.state);
804                 COMPAT_READ_BOOL(fullscreen.show_info, image_overlay.common.show_at_startup); /* 2008-04-21 */
805                 READ_BOOL(image_overlay.common.show_at_startup);
806                 COMPAT_READ_CHAR(fullscreen.info, image_overlay.common.template_string); /* 2008-04-21 */
807                 READ_CHAR(image_overlay.common.template_string);
808
809                 /* slideshow options */
810                 READ_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
811                 READ_BOOL(slideshow.random);
812                 READ_BOOL(slideshow.repeat);
813
814                 /* collection options */
815
816                 READ_BOOL(collections.rectangular_selection);
817
818                 /* filtering options */
819
820                 READ_BOOL(file_filter.show_hidden_files);
821                 READ_BOOL(file_filter.show_dot_directory);
822                 READ_BOOL(file_filter.disable);
823
824                 if (g_ascii_strcasecmp(option, "file_filter.ext") == 0)
825                         {
826                         filter_parse(value_all);
827                         continue;
828                         }
829
830                 if (g_ascii_strcasecmp(option, "sidecar.ext") == 0)
831                         {
832                         sidecar_ext_parse(value_all, TRUE);
833                         continue;
834                         }
835
836                 /* Color Profiles */
837
838                 READ_BOOL(color_profile.enabled);
839                 READ_BOOL(color_profile.use_image);
840                 READ_INT(color_profile.input_type);
841
842                 if (g_ascii_strncasecmp(option, "color_profile.input_file_", 25) == 0)
843                         {
844                         i = strtol(option + 25, NULL, 0) - 1;
845                         if (i >= 0 && i < COLOR_PROFILE_INPUTS)
846                                 {
847                                 read_char_option(f, option, option, value, &options->color_profile.input_file[i]);
848                                 }
849                         continue;
850                         }
851                 if (g_ascii_strncasecmp(option, "color_profile.input_name_", 25) == 0)
852                         {
853                         i = strtol(option + 25, NULL, 0) - 1;
854                         if (i >= 0 && i < COLOR_PROFILE_INPUTS)
855                                 {
856                                 read_char_option(f, option, option, value, &options->color_profile.input_name[i]);
857                                 }
858                         continue;
859                         }
860
861                 READ_INT(color_profile.screen_type);
862                 READ_CHAR(color_profile.screen_file);
863
864                 /* External Programs */
865
866                 if (g_ascii_strncasecmp(option, "external_", 9) == 0)
867                         {
868                         i = strtol(option + 9, NULL, 0);
869                         if (i > 0 && i <= GQ_EDITOR_SLOTS)
870                                 {
871                                 const gchar *ptr;
872                                 i--;
873                                 g_free(options->editor_name[i]);
874                                 g_free(options->editor_command[i]);
875
876                                 options->editor_name[i] = quoted_value(value_all, &ptr);
877                                 options->editor_command[i] = quoted_value(ptr, NULL);
878                                 }
879                         continue;
880                         }
881
882                 /* Exif */
883                 if (0 == g_ascii_strncasecmp(option, "exif.display.", 13))
884                         {
885                         for (i = 0; ExifUIList[i].key; i++)
886                                 if (0 == g_ascii_strcasecmp(option + 13, ExifUIList[i].key))
887                                         ExifUIList[i].current = strtol(value, NULL, 10);
888                         continue;
889                         }
890                 }
891
892         fclose(f);
893         g_free(rc_path);
894 }