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