Try to load a system-wide rc file if any, before per-user rc file.
[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 static gboolean save_options_to(const gchar *utf8_path, ConfOptions *options)
296 {
297         SecureSaveInfo *ssi;
298         gchar *rc_pathl;
299         gint i;
300
301         rc_pathl = path_from_utf8(utf8_path);
302         ssi = secure_open(rc_pathl);
303         g_free(rc_pathl);
304         if (!ssi)
305                 {
306                 log_printf(_("error saving config file: %s\n"), utf8_path);
307                 return FALSE;
308                 }
309
310 #define WRITE_BOOL(_name_) write_bool_option(ssi, #_name_, options->_name_)
311 #define WRITE_INT(_name_) write_int_option(ssi, #_name_, options->_name_)
312 #define WRITE_UINT(_name_) write_uint_option(ssi, #_name_, options->_name_)
313 #define WRITE_INT_UNIT(_name_, _unit_) write_int_unit_option(ssi, #_name_, options->_name_, _unit_)
314 #define WRITE_CHAR(_name_) write_char_option(ssi, #_name_, options->_name_)
315 #define WRITE_COLOR(_name_) write_color_option(ssi, #_name_, &options->_name_)
316
317 #define WRITE_SEPARATOR() secure_fputc(ssi, '\n')
318 #define WRITE_SUBTITLE(_title_) secure_fprintf(ssi, "\n\n##### "_title_" #####\n\n")
319
320         secure_fprintf(ssi, "######################################################################\n");
321         secure_fprintf(ssi, "# %30s config file      version %-10s #\n", GQ_APPNAME, VERSION);
322         secure_fprintf(ssi, "######################################################################\n");
323         WRITE_SEPARATOR();
324
325         secure_fprintf(ssi, "# Note: This file is autogenerated. Options can be changed here,\n");
326         secure_fprintf(ssi, "#       but user comments and formatting will be lost.\n");
327         WRITE_SEPARATOR();
328
329         WRITE_SUBTITLE("General Options");
330
331         WRITE_BOOL(show_icon_names);
332         WRITE_BOOL(show_copy_path);
333         WRITE_SEPARATOR();
334
335         WRITE_BOOL(tree_descend_subdirs);
336         WRITE_BOOL(lazy_image_sync);
337         WRITE_BOOL(update_on_time_change);
338         WRITE_SEPARATOR();
339
340         WRITE_BOOL(progressive_key_scrolling);
341         WRITE_BOOL(enable_metadata_dirs);
342         WRITE_BOOL(save_metadata_in_image_file);
343
344         WRITE_INT(duplicates_similarity_threshold);
345         WRITE_SEPARATOR();
346
347         WRITE_BOOL(mousewheel_scrolls);
348         WRITE_INT(open_recent_list_maxsize);
349         WRITE_INT(dnd_icon_size);
350         WRITE_BOOL(place_dialogs_under_mouse);
351
352
353         WRITE_SUBTITLE("Startup Options");
354
355         WRITE_BOOL(startup.restore_path);
356         WRITE_BOOL(startup.use_last_path);
357         WRITE_CHAR(startup.path);
358
359
360         WRITE_SUBTITLE("File operations Options");
361
362         WRITE_BOOL(file_ops.enable_in_place_rename);
363         WRITE_BOOL(file_ops.confirm_delete);
364         WRITE_BOOL(file_ops.enable_delete_key);
365         WRITE_BOOL(file_ops.safe_delete_enable);
366         WRITE_CHAR(file_ops.safe_delete_path);
367         WRITE_INT(file_ops.safe_delete_folder_maxsize);
368
369
370         WRITE_SUBTITLE("Layout Options");
371
372         WRITE_INT(layout.style);
373         WRITE_CHAR(layout.order);
374         WRITE_UINT(layout.dir_view_type);
375         WRITE_UINT(layout.file_view_type);
376         WRITE_BOOL(layout.show_marks);
377         WRITE_BOOL(layout.show_thumbnails);
378         WRITE_SEPARATOR();
379
380         WRITE_BOOL(layout.save_window_positions);
381         WRITE_SEPARATOR();
382
383         WRITE_INT(layout.main_window.x);
384         WRITE_INT(layout.main_window.y);
385         WRITE_INT(layout.main_window.w);
386         WRITE_INT(layout.main_window.h);
387         WRITE_BOOL(layout.main_window.maximized);
388         WRITE_INT(layout.main_window.hdivider_pos);
389         WRITE_INT(layout.main_window.vdivider_pos);
390         WRITE_SEPARATOR();
391
392         WRITE_INT(layout.float_window.x);
393         WRITE_INT(layout.float_window.y);
394         WRITE_INT(layout.float_window.w);
395         WRITE_INT(layout.float_window.h);
396         WRITE_INT(layout.float_window.vdivider_pos);
397         WRITE_SEPARATOR();
398
399         WRITE_BOOL(layout.tools_float);
400         WRITE_BOOL(layout.tools_hidden);
401         WRITE_BOOL(layout.tools_restore_state);
402         WRITE_SEPARATOR();
403
404         WRITE_BOOL(layout.toolbar_hidden);
405
406         WRITE_SUBTITLE("Panels Options");
407
408         WRITE_BOOL(panels.exif.enabled);
409         WRITE_INT(panels.exif.width);
410         WRITE_BOOL(panels.info.enabled);
411         WRITE_INT(panels.info.width);
412         WRITE_BOOL(panels.sort.enabled);
413         WRITE_INT(panels.sort.action_state);
414         WRITE_INT(panels.sort.mode_state);
415         WRITE_INT(panels.sort.selection_state);
416
417         WRITE_SUBTITLE("Properties dialog Options");
418         WRITE_CHAR(properties.tabs_order);
419
420         WRITE_SUBTITLE("Image Options");
421
422         secure_fprintf(ssi, "# image.zoom_mode possible values are:\n"
423                             "#   original\n"
424                             "#   fit\n"
425                             "#   dont_change\n");
426         secure_fprintf(ssi, "image.zoom_mode: ");
427         if (options->image.zoom_mode == ZOOM_RESET_ORIGINAL)
428                 secure_fprintf(ssi, "original\n");
429         else if (options->image.zoom_mode == ZOOM_RESET_FIT_WINDOW)
430                 secure_fprintf(ssi, "fit\n");
431         else if (options->image.zoom_mode == ZOOM_RESET_NONE)
432                 secure_fprintf(ssi, "dont_change\n");
433         WRITE_SEPARATOR();
434         WRITE_BOOL(image.zoom_2pass);
435         WRITE_BOOL(image.zoom_to_fit_allow_expand);
436         WRITE_INT(image.zoom_quality);
437         WRITE_INT(image.zoom_increment);
438         WRITE_BOOL(image.fit_window_to_image);
439         WRITE_BOOL(image.limit_window_size);
440         WRITE_INT(image.max_window_size);
441         WRITE_BOOL(image.limit_autofit_size);
442         WRITE_INT(image.max_autofit_size);
443         WRITE_INT(image.scroll_reset_method);
444         WRITE_INT(image.tile_cache_max);
445         WRITE_INT(image.dither_quality);
446         WRITE_BOOL(image.enable_read_ahead);
447         WRITE_BOOL(image.exif_rotate_enable);
448         WRITE_BOOL(image.use_custom_border_color);
449         WRITE_COLOR(image.border_color);
450         WRITE_INT(image.read_buffer_size);
451         WRITE_INT(image.idle_read_loop_count);
452
453         WRITE_SUBTITLE("Thumbnails Options");
454
455         WRITE_INT(thumbnails.max_width);
456         WRITE_INT(thumbnails.max_height);
457         WRITE_BOOL(thumbnails.enable_caching);
458         WRITE_BOOL(thumbnails.cache_into_dirs);
459         WRITE_BOOL(thumbnails.fast);
460         WRITE_BOOL(thumbnails.use_xvpics);
461         WRITE_BOOL(thumbnails.spec_standard);
462         WRITE_INT(thumbnails.quality);
463
464
465         WRITE_SUBTITLE("File sorting Options");
466
467         WRITE_INT(file_sort.method);
468         WRITE_BOOL(file_sort.ascending);
469         WRITE_BOOL(file_sort.case_sensitive);
470
471
472         WRITE_SUBTITLE("Fullscreen Options");
473
474         WRITE_INT(fullscreen.screen);
475         WRITE_BOOL(fullscreen.clean_flip);
476         WRITE_BOOL(fullscreen.disable_saver);
477         WRITE_BOOL(fullscreen.above);
478
479
480         WRITE_SUBTITLE("Histogram Options");
481         WRITE_UINT(histogram.last_channel_mode);
482         WRITE_UINT(histogram.last_log_mode);
483
484
485         WRITE_SUBTITLE("Image Overlay Options");
486         WRITE_UINT(image_overlay.common.state);
487         WRITE_BOOL(image_overlay.common.show_at_startup);
488         WRITE_CHAR(image_overlay.common.template_string);
489
490
491         WRITE_SUBTITLE("Slideshow Options");
492
493         WRITE_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
494         WRITE_BOOL(slideshow.random);
495         WRITE_BOOL(slideshow.repeat);
496
497
498         WRITE_SUBTITLE("Collection Options");
499
500         WRITE_BOOL(collections.rectangular_selection);
501
502
503         WRITE_SUBTITLE("Filtering Options");
504
505         WRITE_BOOL(file_filter.show_hidden_files);
506         WRITE_BOOL(file_filter.show_dot_directory);
507         WRITE_BOOL(file_filter.disable);
508         WRITE_SEPARATOR();
509
510         filter_write_list(ssi);
511
512
513         WRITE_SUBTITLE("Sidecars Options");
514
515         sidecar_ext_write(ssi);
516
517
518         WRITE_SUBTITLE("Color Profiles");
519
520 #ifndef HAVE_LCMS
521         secure_fprintf(ssi, "# NOTICE: %s was not built with support for color profiles,\n"
522                             "#         color profile options will have no effect.\n\n", GQ_APPNAME);
523 #endif
524
525         WRITE_BOOL(color_profile.enabled);
526         WRITE_BOOL(color_profile.use_image);
527         WRITE_INT(color_profile.input_type);
528         WRITE_SEPARATOR();
529
530         for (i = 0; i < COLOR_PROFILE_INPUTS; i++)
531                 {
532                 gchar *buf;
533
534                 buf = g_strdup_printf("color_profile.input_file_%d", i + 1);
535                 write_char_option(ssi, buf, options->color_profile.input_file[i]);
536                 g_free(buf);
537
538                 buf = g_strdup_printf("color_profile.input_name_%d", i + 1);
539                 write_char_option(ssi, buf, options->color_profile.input_name[i]);
540                 g_free(buf);
541                 }
542
543         WRITE_SEPARATOR();
544         WRITE_INT(color_profile.screen_type);
545         WRITE_CHAR(color_profile.screen_file);
546
547
548         WRITE_SUBTITLE("Shell command");
549         WRITE_CHAR(shell.path);
550         WRITE_CHAR(shell.options);
551
552
553         WRITE_SUBTITLE("External Programs");
554         secure_fprintf(ssi, "# Maximum of %d programs (external_1 through external_%d)\n", GQ_EDITOR_GENERIC_SLOTS, GQ_EDITOR_GENERIC_SLOTS);
555         secure_fprintf(ssi, "# external_%d through external_%d are used for file ops\n", GQ_EDITOR_GENERIC_SLOTS + 1, GQ_EDITOR_SLOTS);
556         secure_fprintf(ssi, "# format: external_n: \"menu name\" \"command line\"\n\n");
557
558         for (i = 0; i < GQ_EDITOR_SLOTS; i++)
559                 {
560                 if (i == GQ_EDITOR_GENERIC_SLOTS) secure_fputc(ssi, '\n');
561                 gchar *qname = escquote_value(options->editor[i].name);
562                 gchar *qcommand = escquote_value(options->editor[i].command);
563                 secure_fprintf(ssi, "external_%d: %s %s\n", i+1, qname, qcommand);
564                 g_free(qname);
565                 g_free(qcommand);
566                 }
567
568
569         WRITE_SUBTITLE("Exif Options");
570         secure_fprintf(ssi, "# Display: 0: never\n"
571                             "#          1: if set\n"
572                             "#          2: always\n\n");
573         for (i = 0; ExifUIList[i].key; i++)
574                 {
575                 secure_fprintf(ssi, "exif.display.");
576                 write_int_option(ssi, (gchar *)ExifUIList[i].key, ExifUIList[i].current);
577                 }
578
579         WRITE_SEPARATOR();
580         WRITE_SEPARATOR();
581
582         secure_fprintf(ssi, "######################################################################\n");
583         secure_fprintf(ssi, "#                         end of config file                         #\n");
584         secure_fprintf(ssi, "######################################################################\n");
585
586
587         if (secure_close(ssi))
588                 {
589                 log_printf(_("error saving config file: %s\nerror: %s\n"), utf8_path,
590                            secsave_strerror(secsave_errno));
591                 return FALSE;
592                 }
593
594         return TRUE;
595 }
596
597 void save_options(ConfOptions *options)
598 {
599         gchar *rc_path;
600
601         rc_path = g_build_filename(homedir(), GQ_RC_DIR, RC_FILE_NAME, NULL);
602         save_options_to(rc_path, options);
603         g_free(rc_path);
604 }
605
606
607
608 /*
609  *-----------------------------------------------------------------------------
610  * load configuration (public)
611  *-----------------------------------------------------------------------------
612  */
613
614 static gboolean is_numbered_option(const gchar *option, const gchar *prefix, gint *number)
615 {
616         gsize n;
617         gsize option_len = strlen(option);
618         gsize prefix_len = strlen(prefix);
619         
620         if (option_len <= prefix_len) return FALSE;
621         if (g_ascii_strncasecmp(option, prefix, prefix_len) != 0) return FALSE;
622
623         n = prefix_len;
624         while (g_ascii_isdigit(option[n])) n++;
625         if (n < option_len) return FALSE;
626         
627         if (number) *number = atoi(option + prefix_len);
628         return TRUE;
629 }
630
631
632
633 static gboolean load_options_from(const gchar *utf8_path, ConfOptions *options)
634 {
635         FILE *f;
636         gchar *rc_pathl;
637         gchar s_buf[1024];
638         gchar option[1024];
639         gchar value[1024];
640         gchar value_all[1024];
641         gint i;
642
643         rc_pathl = path_from_utf8(utf8_path);
644         f = fopen(rc_pathl,"r");
645         g_free(rc_pathl);
646         if (!f) return FALSE;
647
648         while (fgets(s_buf, sizeof(s_buf), f))
649                 {
650                 gchar *option_start, *value_start;
651                 gchar *p = s_buf;
652
653                 while (g_ascii_isspace(*p)) p++;
654                 if (!*p || *p == '\n' || *p == '#') continue;
655                 option_start = p;
656                 while (*p && *p != ':') p++;
657                 if (!*p) continue;
658                 *p = '\0';
659                 p++;
660                 strncpy(option, option_start, sizeof(option));
661                 while (g_ascii_isspace(*p)) p++;
662                 value_start = p;
663                 strncpy(value_all, value_start, sizeof(value_all));
664                 while (*p && !g_ascii_isspace(*p) && *p != '\n') p++;
665                 *p = '\0';
666                 strncpy(value, value_start, sizeof(value));
667
668 #define READ_BOOL(_name_) if (read_bool_option(f, option, #_name_, value, &options->_name_)) continue;
669 #define READ_INT(_name_) if (read_int_option(f, option, #_name_, value, &options->_name_)) continue;
670 #define READ_UINT(_name_) if (read_uint_option(f, option, #_name_, value, &options->_name_)) continue;
671 #define READ_INT_CLAMP(_name_, _min_, _max_) if (read_int_option_clamp(f, option, #_name_, value, &options->_name_, _min_, _max_)) continue;
672 #define READ_INT_UNIT(_name_, _unit_) if (read_int_unit_option(f, option, #_name_, value, &options->_name_, _unit_)) continue;
673 #define READ_CHAR(_name_) if (read_char_option(f, option, #_name_, value_all, &options->_name_)) continue;
674 #define READ_COLOR(_name_) if (read_color_option(f, option, #_name_, value, &options->_name_)) continue;
675
676 #define COMPAT_READ_BOOL(_oldname_, _name_) if (read_bool_option(f, option, #_oldname_, value, &options->_name_)) continue;
677 #define COMPAT_READ_INT(_oldname_, _name_) if (read_int_option(f, option, #_oldname_, value, &options->_name_)) continue;
678 #define COMPAT_READ_UINT(_oldname_, _name_) if (read_uint_option(f, option, #_oldname_, value, &options->_name_)) continue;
679 #define COMPAT_READ_INT_CLAMP(_oldname_, _name_, _min_, _max_) if (read_int_option_clamp(f, option, #_oldname_, value, &options->_name_, _min_, _max_)) continue;
680 #define COMPAT_READ_INT_UNIT(_oldname_, _name_, _unit_) if (read_int_unit_option(f, option, #_oldname_, value, &options->_name_, _unit_)) continue;
681 #define COMPAT_READ_CHAR(_oldname_, _name_) if (read_char_option(f, option, #_oldname_, value_all, &options->_name_)) continue;
682 #define COMPAT_READ_COLOR(_oldname_, _name_) if (read_color_option(f, option, #_oldname_, value, &options->_name_)) continue;
683
684                 /* general options */
685                 READ_BOOL(show_icon_names);
686                 READ_BOOL(show_copy_path);
687
688                 READ_BOOL(tree_descend_subdirs);
689                 READ_BOOL(lazy_image_sync);
690                 READ_BOOL(update_on_time_change);
691
692                 READ_INT(duplicates_similarity_threshold);
693
694                 READ_BOOL(progressive_key_scrolling);
695
696                 READ_BOOL(enable_metadata_dirs);
697                 READ_BOOL(save_metadata_in_image_file);
698
699                 READ_BOOL(mousewheel_scrolls);
700
701                 READ_INT(open_recent_list_maxsize);
702                 READ_INT(dnd_icon_size);
703                 READ_BOOL(place_dialogs_under_mouse);
704
705                 /* startup options */
706                 
707                 COMPAT_READ_BOOL(startup_path_enable, startup.restore_path); /* 2008/05/11 */
708                 READ_BOOL(startup.restore_path);
709
710                 READ_BOOL(startup.use_last_path);
711
712                 COMPAT_READ_CHAR(startup_path, startup.path); /* 2008/05/11 */
713                 READ_CHAR(startup.path);
714         
715                 /* layout options */
716
717                 READ_INT(layout.style);
718                 READ_CHAR(layout.order);
719                 
720                 COMPAT_READ_UINT(layout.view_as_icons, layout.file_view_type); /* 2008/05/03 */
721
722                 READ_UINT(layout.dir_view_type);
723                 READ_UINT(layout.file_view_type);
724                 READ_BOOL(layout.show_marks);
725                 READ_BOOL(layout.show_thumbnails);
726
727                 /* window positions */
728
729                 READ_BOOL(layout.save_window_positions);
730
731                 READ_INT(layout.main_window.x);
732                 READ_INT(layout.main_window.y);
733                 READ_INT(layout.main_window.w);
734                 READ_INT(layout.main_window.h);
735                 READ_BOOL(layout.main_window.maximized);
736                 READ_INT(layout.float_window.x);
737                 READ_INT(layout.float_window.y);
738                 READ_INT(layout.float_window.w);
739                 READ_INT(layout.float_window.h);
740                 READ_INT(layout.float_window.vdivider_pos);
741                 READ_INT(layout.main_window.hdivider_pos);
742                 READ_INT(layout.main_window.vdivider_pos);
743                 READ_BOOL(layout.tools_float);
744                 READ_BOOL(layout.tools_hidden);
745                 READ_BOOL(layout.tools_restore_state);
746                 READ_BOOL(layout.toolbar_hidden);
747
748                 /* panels */
749                 READ_BOOL(panels.exif.enabled);
750                 READ_INT_CLAMP(panels.exif.width, PANEL_MIN_WIDTH, PANEL_MAX_WIDTH);
751                 READ_BOOL(panels.info.enabled);
752                 READ_INT_CLAMP(panels.info.width, PANEL_MIN_WIDTH, PANEL_MAX_WIDTH);
753                 READ_BOOL(panels.sort.enabled);
754                 READ_INT(panels.sort.action_state);
755                 READ_INT(panels.sort.mode_state);
756                 READ_INT(panels.sort.selection_state);
757
758                 /* properties dialog options */
759                 READ_CHAR(properties.tabs_order);
760
761                 /* image options */
762                 if (g_ascii_strcasecmp(option, "image.zoom_mode") == 0)
763                         {
764                         if (g_ascii_strcasecmp(value, "original") == 0)
765                                 options->image.zoom_mode = ZOOM_RESET_ORIGINAL;
766                         else if (g_ascii_strcasecmp(value, "fit") == 0)
767                                 options->image.zoom_mode = ZOOM_RESET_FIT_WINDOW;
768                         else if (g_ascii_strcasecmp(value, "dont_change") == 0)
769                                 options->image.zoom_mode = ZOOM_RESET_NONE;
770                         continue;
771                         }
772                 READ_BOOL(image.zoom_2pass);
773                 READ_BOOL(image.zoom_to_fit_allow_expand);
774                 READ_BOOL(image.fit_window_to_image);
775                 READ_BOOL(image.limit_window_size);
776                 READ_INT(image.max_window_size);
777                 READ_BOOL(image.limit_autofit_size);
778                 READ_INT(image.max_autofit_size);
779                 READ_INT(image.scroll_reset_method);
780                 READ_INT(image.tile_cache_max);
781                 READ_INT_CLAMP(image.zoom_quality, GDK_INTERP_NEAREST, GDK_INTERP_HYPER);
782                 READ_INT_CLAMP(image.dither_quality, GDK_RGB_DITHER_NONE, GDK_RGB_DITHER_MAX);
783                 READ_INT(image.zoom_increment);
784                 READ_BOOL(image.enable_read_ahead);
785                 READ_BOOL(image.exif_rotate_enable);
786                 READ_BOOL(image.use_custom_border_color);
787                 READ_COLOR(image.border_color);
788                 READ_INT_CLAMP(image.read_buffer_size, IMAGE_LOADER_READ_BUFFER_SIZE_MIN, IMAGE_LOADER_READ_BUFFER_SIZE_MAX);
789                 READ_INT_CLAMP(image.idle_read_loop_count, IMAGE_LOADER_IDLE_READ_LOOP_COUNT_MIN, IMAGE_LOADER_IDLE_READ_LOOP_COUNT_MAX);
790
791
792                 /* thumbnails options */
793                 READ_INT_CLAMP(thumbnails.max_width, 16, 512);
794                 READ_INT_CLAMP(thumbnails.max_height, 16, 512);
795
796                 READ_BOOL(thumbnails.enable_caching);
797                 READ_BOOL(thumbnails.cache_into_dirs);
798                 READ_BOOL(thumbnails.fast);
799                 READ_BOOL(thumbnails.use_xvpics);
800                 READ_BOOL(thumbnails.spec_standard);
801                 READ_INT_CLAMP(thumbnails.quality, GDK_INTERP_NEAREST, GDK_INTERP_HYPER);
802
803                 /* file sorting options */
804                 READ_UINT(file_sort.method);
805                 READ_BOOL(file_sort.ascending);
806                 READ_BOOL(file_sort.case_sensitive);
807
808                 /* file operations options */
809                 READ_BOOL(file_ops.enable_in_place_rename);
810                 READ_BOOL(file_ops.confirm_delete);
811                 READ_BOOL(file_ops.enable_delete_key);
812                 READ_BOOL(file_ops.safe_delete_enable);
813                 READ_CHAR(file_ops.safe_delete_path);
814                 READ_INT(file_ops.safe_delete_folder_maxsize);
815
816                 /* fullscreen options */
817                 READ_INT(fullscreen.screen);
818                 READ_BOOL(fullscreen.clean_flip);
819                 READ_BOOL(fullscreen.disable_saver);
820                 READ_BOOL(fullscreen.above);
821
822                 /* histogram */
823                 READ_UINT(histogram.last_channel_mode);
824                 READ_UINT(histogram.last_log_mode);
825
826                 /* image overlay */
827                 COMPAT_READ_UINT(image_overlay.common.enabled, image_overlay.common.state); /* 2008-05-12 */ 
828                 READ_UINT(image_overlay.common.state);
829                 COMPAT_READ_BOOL(fullscreen.show_info, image_overlay.common.show_at_startup); /* 2008-04-21 */
830                 READ_BOOL(image_overlay.common.show_at_startup);
831                 COMPAT_READ_CHAR(fullscreen.info, image_overlay.common.template_string); /* 2008-04-21 */
832                 READ_CHAR(image_overlay.common.template_string);
833
834                 /* slideshow options */
835                 READ_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
836                 READ_BOOL(slideshow.random);
837                 READ_BOOL(slideshow.repeat);
838
839                 /* collection options */
840
841                 READ_BOOL(collections.rectangular_selection);
842
843                 /* filtering options */
844
845                 READ_BOOL(file_filter.show_hidden_files);
846                 READ_BOOL(file_filter.show_dot_directory);
847                 READ_BOOL(file_filter.disable);
848
849                 if (g_ascii_strcasecmp(option, "file_filter.ext") == 0)
850                         {
851                         filter_parse(value_all);
852                         continue;
853                         }
854
855                 if (g_ascii_strcasecmp(option, "sidecar.ext") == 0)
856                         {
857                         sidecar_ext_parse(value_all, TRUE);
858                         continue;
859                         }
860
861                 /* Color Profiles */
862
863                 READ_BOOL(color_profile.enabled);
864                 READ_BOOL(color_profile.use_image);
865                 READ_INT(color_profile.input_type);
866
867                 if (is_numbered_option(option, "color_profile.input_file_", &i))
868                         {
869                         if (i > 0 && i <= COLOR_PROFILE_INPUTS)
870                                 {
871                                 i--;
872                                 read_char_option(f, option, option, value, &options->color_profile.input_file[i]);
873                                 }
874                         continue;
875                         }
876
877                 if (is_numbered_option(option, "color_profile.input_name_", &i))
878                         {
879                         if (i > 0 && i <= COLOR_PROFILE_INPUTS)
880                                 {
881                                 i--;
882                                 read_char_option(f, option, option, value, &options->color_profile.input_name[i]);
883                                 }
884                         continue;
885                         }
886
887                 READ_INT(color_profile.screen_type);
888                 READ_CHAR(color_profile.screen_file);
889
890                 /* Shell command */
891                 READ_CHAR(shell.path);
892                 READ_CHAR(shell.options);
893
894                 /* External Programs */
895
896                 if (is_numbered_option(option, "external_", &i))
897                         {
898                         if (i > 0 && i <= GQ_EDITOR_SLOTS)
899                                 {
900                                 const gchar *ptr;
901                                 i--;
902                                 g_free(options->editor[i].name);
903                                 g_free(options->editor[i].command);
904
905                                 options->editor[i].name = quoted_value(value_all, &ptr);
906                                 options->editor[i].command = quoted_value(ptr, NULL);
907                                 }
908                         continue;
909                         }
910
911                 /* Exif */
912                 if (0 == g_ascii_strncasecmp(option, "exif.display.", 13))
913                         {
914                         for (i = 0; ExifUIList[i].key; i++)
915                                 if (0 == g_ascii_strcasecmp(option + 13, ExifUIList[i].key))
916                                         ExifUIList[i].current = strtol(value, NULL, 10);
917                         continue;
918                         }
919                 }
920
921         fclose(f);
922         return TRUE;
923 }
924
925 void load_options(ConfOptions *options)
926 {
927         gboolean success;
928         gchar *rc_path;
929
930         if (isdir(GQ_SYSTEM_WIDE_DIR))
931                 {
932                 rc_path = g_build_filename(GQ_SYSTEM_WIDE_DIR, RC_FILE_NAME, NULL);
933                 success = load_options_from(rc_path, options);
934                 DEBUG_1("Loading options from %s ... %s", rc_path, success ? "done" : "failed");
935                 g_free(rc_path);
936                 }
937         
938         rc_path = g_build_filename(homedir(), GQ_RC_DIR, RC_FILE_NAME, NULL);
939         success = load_options_from(rc_path, options);
940         DEBUG_1("Loading options from %s ... %s", rc_path, success ? "done" : "failed");
941         g_free(rc_path);
942 }