Save properties window width and height to rc file and restore
[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_INT(layout.properties_window.w);
400         WRITE_INT(layout.properties_window.h);
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
552         WRITE_SUBTITLE("Shell command");
553         WRITE_CHAR(shell.path);
554         WRITE_CHAR(shell.options);
555
556
557         WRITE_SUBTITLE("External Programs");
558         secure_fprintf(ssi, "# Maximum of %d programs (external_1 through external_%d)\n", GQ_EDITOR_GENERIC_SLOTS, GQ_EDITOR_GENERIC_SLOTS);
559         secure_fprintf(ssi, "# external_%d through external_%d are used for file ops\n", GQ_EDITOR_GENERIC_SLOTS + 1, GQ_EDITOR_SLOTS);
560         secure_fprintf(ssi, "# format: external_n: \"menu name\" \"command line\"\n\n");
561
562         for (i = 0; i < GQ_EDITOR_SLOTS; i++)
563                 {
564                 if (i == GQ_EDITOR_GENERIC_SLOTS) secure_fputc(ssi, '\n');
565                 gchar *qname = escquote_value(options->editor[i].name);
566                 gchar *qcommand = escquote_value(options->editor[i].command);
567                 secure_fprintf(ssi, "external_%d: %s %s\n", i+1, qname, qcommand);
568                 g_free(qname);
569                 g_free(qcommand);
570                 }
571
572
573         WRITE_SUBTITLE("Exif Options");
574         secure_fprintf(ssi, "# Display: 0: never\n"
575                             "#          1: if set\n"
576                             "#          2: always\n\n");
577         for (i = 0; ExifUIList[i].key; i++)
578                 {
579                 secure_fprintf(ssi, "exif.display.");
580                 write_int_option(ssi, (gchar *)ExifUIList[i].key, ExifUIList[i].current);
581                 }
582
583         WRITE_SEPARATOR();
584         WRITE_SEPARATOR();
585
586         secure_fprintf(ssi, "######################################################################\n");
587         secure_fprintf(ssi, "#                         end of config file                         #\n");
588         secure_fprintf(ssi, "######################################################################\n");
589
590
591         if (secure_close(ssi))
592                 {
593                 log_printf(_("error saving config file: %s\nerror: %s\n"), utf8_path,
594                            secsave_strerror(secsave_errno));
595                 return FALSE;
596                 }
597
598         return TRUE;
599 }
600
601 void save_options(ConfOptions *options)
602 {
603         gchar *rc_path;
604
605         rc_path = g_build_filename(homedir(), GQ_RC_DIR, RC_FILE_NAME, NULL);
606         save_options_to(rc_path, options);
607         g_free(rc_path);
608 }
609
610
611
612 /*
613  *-----------------------------------------------------------------------------
614  * load configuration (public)
615  *-----------------------------------------------------------------------------
616  */
617
618 static gboolean is_numbered_option(const gchar *option, const gchar *prefix, gint *number)
619 {
620         gsize n;
621         gsize option_len = strlen(option);
622         gsize prefix_len = strlen(prefix);
623         
624         if (option_len <= prefix_len) return FALSE;
625         if (g_ascii_strncasecmp(option, prefix, prefix_len) != 0) return FALSE;
626
627         n = prefix_len;
628         while (g_ascii_isdigit(option[n])) n++;
629         if (n < option_len) return FALSE;
630         
631         if (number) *number = atoi(option + prefix_len);
632         return TRUE;
633 }
634
635
636
637 static gboolean load_options_from(const gchar *utf8_path, ConfOptions *options)
638 {
639         FILE *f;
640         gchar *rc_pathl;
641         gchar s_buf[1024];
642         gchar option[1024];
643         gchar value[1024];
644         gchar value_all[1024];
645         gint i;
646
647         rc_pathl = path_from_utf8(utf8_path);
648         f = fopen(rc_pathl,"r");
649         g_free(rc_pathl);
650         if (!f) return FALSE;
651
652         while (fgets(s_buf, sizeof(s_buf), f))
653                 {
654                 gchar *option_start, *value_start;
655                 gchar *p = s_buf;
656
657                 while (g_ascii_isspace(*p)) p++;
658                 if (!*p || *p == '\n' || *p == '#') continue;
659                 option_start = p;
660                 while (*p && *p != ':') p++;
661                 if (!*p) continue;
662                 *p = '\0';
663                 p++;
664                 strncpy(option, option_start, sizeof(option));
665                 while (g_ascii_isspace(*p)) p++;
666                 value_start = p;
667                 strncpy(value_all, value_start, sizeof(value_all));
668                 while (*p && !g_ascii_isspace(*p) && *p != '\n') p++;
669                 *p = '\0';
670                 strncpy(value, value_start, sizeof(value));
671
672 #define READ_BOOL(_name_) if (read_bool_option(f, option, #_name_, value, &options->_name_)) continue;
673 #define READ_INT(_name_) if (read_int_option(f, option, #_name_, value, &options->_name_)) continue;
674 #define READ_UINT(_name_) if (read_uint_option(f, option, #_name_, value, &options->_name_)) continue;
675 #define READ_INT_CLAMP(_name_, _min_, _max_) if (read_int_option_clamp(f, option, #_name_, value, &options->_name_, _min_, _max_)) continue;
676 #define READ_INT_UNIT(_name_, _unit_) if (read_int_unit_option(f, option, #_name_, value, &options->_name_, _unit_)) continue;
677 #define READ_CHAR(_name_) if (read_char_option(f, option, #_name_, value_all, &options->_name_)) continue;
678 #define READ_COLOR(_name_) if (read_color_option(f, option, #_name_, value, &options->_name_)) continue;
679
680 #define COMPAT_READ_BOOL(_oldname_, _name_) if (read_bool_option(f, option, #_oldname_, value, &options->_name_)) continue;
681 #define COMPAT_READ_INT(_oldname_, _name_) if (read_int_option(f, option, #_oldname_, value, &options->_name_)) continue;
682 #define COMPAT_READ_UINT(_oldname_, _name_) if (read_uint_option(f, option, #_oldname_, value, &options->_name_)) continue;
683 #define COMPAT_READ_INT_CLAMP(_oldname_, _name_, _min_, _max_) if (read_int_option_clamp(f, option, #_oldname_, value, &options->_name_, _min_, _max_)) continue;
684 #define COMPAT_READ_INT_UNIT(_oldname_, _name_, _unit_) if (read_int_unit_option(f, option, #_oldname_, value, &options->_name_, _unit_)) continue;
685 #define COMPAT_READ_CHAR(_oldname_, _name_) if (read_char_option(f, option, #_oldname_, value_all, &options->_name_)) continue;
686 #define COMPAT_READ_COLOR(_oldname_, _name_) if (read_color_option(f, option, #_oldname_, value, &options->_name_)) continue;
687
688                 /* general options */
689                 READ_BOOL(show_icon_names);
690                 READ_BOOL(show_copy_path);
691
692                 READ_BOOL(tree_descend_subdirs);
693                 READ_BOOL(lazy_image_sync);
694                 READ_BOOL(update_on_time_change);
695
696                 READ_INT(duplicates_similarity_threshold);
697
698                 READ_BOOL(progressive_key_scrolling);
699
700                 READ_BOOL(enable_metadata_dirs);
701                 READ_BOOL(save_metadata_in_image_file);
702
703                 READ_BOOL(mousewheel_scrolls);
704
705                 READ_INT(open_recent_list_maxsize);
706                 READ_INT(dnd_icon_size);
707                 READ_BOOL(place_dialogs_under_mouse);
708
709                 /* startup options */
710                 
711                 COMPAT_READ_BOOL(startup_path_enable, startup.restore_path); /* 2008/05/11 */
712                 READ_BOOL(startup.restore_path);
713
714                 READ_BOOL(startup.use_last_path);
715
716                 COMPAT_READ_CHAR(startup_path, startup.path); /* 2008/05/11 */
717                 READ_CHAR(startup.path);
718         
719                 /* layout options */
720
721                 READ_INT(layout.style);
722                 READ_CHAR(layout.order);
723                 
724                 COMPAT_READ_UINT(layout.view_as_icons, layout.file_view_type); /* 2008/05/03 */
725
726                 READ_UINT(layout.dir_view_type);
727                 READ_UINT(layout.file_view_type);
728                 READ_BOOL(layout.show_marks);
729                 READ_BOOL(layout.show_thumbnails);
730
731                 /* window positions */
732
733                 READ_BOOL(layout.save_window_positions);
734
735                 READ_INT(layout.main_window.x);
736                 READ_INT(layout.main_window.y);
737                 READ_INT(layout.main_window.w);
738                 READ_INT(layout.main_window.h);
739                 READ_BOOL(layout.main_window.maximized);
740                 READ_INT(layout.main_window.hdivider_pos);
741                 READ_INT(layout.main_window.vdivider_pos);
742
743                 READ_INT(layout.float_window.x);
744                 READ_INT(layout.float_window.y);
745                 READ_INT(layout.float_window.w);
746                 READ_INT(layout.float_window.h);
747                 READ_INT(layout.float_window.vdivider_pos);
748         
749                 READ_INT(layout.properties_window.w);
750                 READ_INT(layout.properties_window.h);
751
752                 READ_BOOL(layout.tools_float);
753                 READ_BOOL(layout.tools_hidden);
754                 READ_BOOL(layout.tools_restore_state);
755                 READ_BOOL(layout.toolbar_hidden);
756
757                 /* panels */
758                 READ_BOOL(panels.exif.enabled);
759                 READ_INT_CLAMP(panels.exif.width, PANEL_MIN_WIDTH, PANEL_MAX_WIDTH);
760                 READ_BOOL(panels.info.enabled);
761                 READ_INT_CLAMP(panels.info.width, PANEL_MIN_WIDTH, PANEL_MAX_WIDTH);
762                 READ_BOOL(panels.sort.enabled);
763                 READ_INT(panels.sort.action_state);
764                 READ_INT(panels.sort.mode_state);
765                 READ_INT(panels.sort.selection_state);
766
767                 /* properties dialog options */
768                 READ_CHAR(properties.tabs_order);
769
770                 /* image options */
771                 if (g_ascii_strcasecmp(option, "image.zoom_mode") == 0)
772                         {
773                         if (g_ascii_strcasecmp(value, "original") == 0)
774                                 options->image.zoom_mode = ZOOM_RESET_ORIGINAL;
775                         else if (g_ascii_strcasecmp(value, "fit") == 0)
776                                 options->image.zoom_mode = ZOOM_RESET_FIT_WINDOW;
777                         else if (g_ascii_strcasecmp(value, "dont_change") == 0)
778                                 options->image.zoom_mode = ZOOM_RESET_NONE;
779                         continue;
780                         }
781                 READ_BOOL(image.zoom_2pass);
782                 READ_BOOL(image.zoom_to_fit_allow_expand);
783                 READ_BOOL(image.fit_window_to_image);
784                 READ_BOOL(image.limit_window_size);
785                 READ_INT(image.max_window_size);
786                 READ_BOOL(image.limit_autofit_size);
787                 READ_INT(image.max_autofit_size);
788                 READ_INT(image.scroll_reset_method);
789                 READ_INT(image.tile_cache_max);
790                 READ_INT_CLAMP(image.zoom_quality, GDK_INTERP_NEAREST, GDK_INTERP_HYPER);
791                 READ_INT_CLAMP(image.dither_quality, GDK_RGB_DITHER_NONE, GDK_RGB_DITHER_MAX);
792                 READ_INT(image.zoom_increment);
793                 READ_BOOL(image.enable_read_ahead);
794                 READ_BOOL(image.exif_rotate_enable);
795                 READ_BOOL(image.use_custom_border_color);
796                 READ_COLOR(image.border_color);
797                 READ_INT_CLAMP(image.read_buffer_size, IMAGE_LOADER_READ_BUFFER_SIZE_MIN, IMAGE_LOADER_READ_BUFFER_SIZE_MAX);
798                 READ_INT_CLAMP(image.idle_read_loop_count, IMAGE_LOADER_IDLE_READ_LOOP_COUNT_MIN, IMAGE_LOADER_IDLE_READ_LOOP_COUNT_MAX);
799
800
801                 /* thumbnails options */
802                 READ_INT_CLAMP(thumbnails.max_width, 16, 512);
803                 READ_INT_CLAMP(thumbnails.max_height, 16, 512);
804
805                 READ_BOOL(thumbnails.enable_caching);
806                 READ_BOOL(thumbnails.cache_into_dirs);
807                 READ_BOOL(thumbnails.fast);
808                 READ_BOOL(thumbnails.use_xvpics);
809                 READ_BOOL(thumbnails.spec_standard);
810                 READ_INT_CLAMP(thumbnails.quality, GDK_INTERP_NEAREST, GDK_INTERP_HYPER);
811
812                 /* file sorting options */
813                 READ_UINT(file_sort.method);
814                 READ_BOOL(file_sort.ascending);
815                 READ_BOOL(file_sort.case_sensitive);
816
817                 /* file operations options */
818                 READ_BOOL(file_ops.enable_in_place_rename);
819                 READ_BOOL(file_ops.confirm_delete);
820                 READ_BOOL(file_ops.enable_delete_key);
821                 READ_BOOL(file_ops.safe_delete_enable);
822                 READ_CHAR(file_ops.safe_delete_path);
823                 READ_INT(file_ops.safe_delete_folder_maxsize);
824
825                 /* fullscreen options */
826                 READ_INT(fullscreen.screen);
827                 READ_BOOL(fullscreen.clean_flip);
828                 READ_BOOL(fullscreen.disable_saver);
829                 READ_BOOL(fullscreen.above);
830
831                 /* histogram */
832                 READ_UINT(histogram.last_channel_mode);
833                 READ_UINT(histogram.last_log_mode);
834
835                 /* image overlay */
836                 COMPAT_READ_UINT(image_overlay.common.enabled, image_overlay.common.state); /* 2008-05-12 */ 
837                 READ_UINT(image_overlay.common.state);
838                 COMPAT_READ_BOOL(fullscreen.show_info, image_overlay.common.show_at_startup); /* 2008-04-21 */
839                 READ_BOOL(image_overlay.common.show_at_startup);
840                 COMPAT_READ_CHAR(fullscreen.info, image_overlay.common.template_string); /* 2008-04-21 */
841                 READ_CHAR(image_overlay.common.template_string);
842
843                 /* slideshow options */
844                 READ_INT_UNIT(slideshow.delay, SLIDESHOW_SUBSECOND_PRECISION);
845                 READ_BOOL(slideshow.random);
846                 READ_BOOL(slideshow.repeat);
847
848                 /* collection options */
849
850                 READ_BOOL(collections.rectangular_selection);
851
852                 /* filtering options */
853
854                 READ_BOOL(file_filter.show_hidden_files);
855                 READ_BOOL(file_filter.show_dot_directory);
856                 READ_BOOL(file_filter.disable);
857
858                 if (g_ascii_strcasecmp(option, "file_filter.ext") == 0)
859                         {
860                         filter_parse(value_all);
861                         continue;
862                         }
863
864                 if (g_ascii_strcasecmp(option, "sidecar.ext") == 0)
865                         {
866                         sidecar_ext_parse(value_all, TRUE);
867                         continue;
868                         }
869
870                 /* Color Profiles */
871
872                 READ_BOOL(color_profile.enabled);
873                 READ_BOOL(color_profile.use_image);
874                 READ_INT(color_profile.input_type);
875
876                 if (is_numbered_option(option, "color_profile.input_file_", &i))
877                         {
878                         if (i > 0 && i <= COLOR_PROFILE_INPUTS)
879                                 {
880                                 i--;
881                                 read_char_option(f, option, option, value, &options->color_profile.input_file[i]);
882                                 }
883                         continue;
884                         }
885
886                 if (is_numbered_option(option, "color_profile.input_name_", &i))
887                         {
888                         if (i > 0 && i <= COLOR_PROFILE_INPUTS)
889                                 {
890                                 i--;
891                                 read_char_option(f, option, option, value, &options->color_profile.input_name[i]);
892                                 }
893                         continue;
894                         }
895
896                 READ_INT(color_profile.screen_type);
897                 READ_CHAR(color_profile.screen_file);
898
899                 /* Shell command */
900                 READ_CHAR(shell.path);
901                 READ_CHAR(shell.options);
902
903                 /* External Programs */
904
905                 if (is_numbered_option(option, "external_", &i))
906                         {
907                         if (i > 0 && i <= GQ_EDITOR_SLOTS)
908                                 {
909                                 const gchar *ptr;
910                                 i--;
911                                 g_free(options->editor[i].name);
912                                 g_free(options->editor[i].command);
913
914                                 options->editor[i].name = quoted_value(value_all, &ptr);
915                                 options->editor[i].command = quoted_value(ptr, NULL);
916                                 }
917                         continue;
918                         }
919
920                 /* Exif */
921                 if (0 == g_ascii_strncasecmp(option, "exif.display.", 13))
922                         {
923                         for (i = 0; ExifUIList[i].key; i++)
924                                 if (0 == g_ascii_strcasecmp(option + 13, ExifUIList[i].key))
925                                         ExifUIList[i].current = strtol(value, NULL, 10);
926                         continue;
927                         }
928                 }
929
930         fclose(f);
931         return TRUE;
932 }
933
934 void load_options(ConfOptions *options)
935 {
936         gboolean success;
937         gchar *rc_path;
938
939         if (isdir(GQ_SYSTEM_WIDE_DIR))
940                 {
941                 rc_path = g_build_filename(GQ_SYSTEM_WIDE_DIR, RC_FILE_NAME, NULL);
942                 success = load_options_from(rc_path, options);
943                 DEBUG_1("Loading options from %s ... %s", rc_path, success ? "done" : "failed");
944                 g_free(rc_path);
945                 }
946         
947         rc_path = g_build_filename(homedir(), GQ_RC_DIR, RC_FILE_NAME, NULL);
948         success = load_options_from(rc_path, options);
949         DEBUG_1("Loading options from %s ... %s", rc_path, success ? "done" : "failed");
950         g_free(rc_path);
951 }