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