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