Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
common/conf.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010-2011, 2014 Henrik Andersson.
4 Copyright (C) 2010-2013 johannes hanika.
5 Copyright (C) 2010, 2012-2017 Tobias Ellinghaus.
6 Copyright (C) 2012 Christian Tellefsen.
7 Copyright (C) 2012 Jérémy Rosen.
8 Copyright (C) 2012 Richard Wonka.
9 Copyright (C) 2012 Simon Spannagel.
10 Copyright (C) 2012, 2014 Ulrich Pegelow.
11 Copyright (C) 2013 Jean-Sébastien Pédron.
12 Copyright (C) 2013 Jesper Pedersen.
13 Copyright (C) 2014 parafin.
14 Copyright (C) 2014, 2020-2021 Pascal Obry.
15 Copyright (C) 2014, 2016 Roman Lebedev.
16 Copyright (C) 2016-2018 Peter Budai.
17 Copyright (C) 2019 jakubfi.
18 Copyright (C) 2019, 2021 luzpaz.
19 Copyright (C) 2020 Hubert Kowalski.
20 Copyright (C) 2020 Philippe Weyland.
21 Copyright (C) 2021 Aldric Renaudin.
22 Copyright (C) 2021 Marco Carrarini.
23 Copyright (C) 2021 Mark-64.
24 Copyright (C) 2021 Ralf Brown.
25 Copyright (C) 2022 Hanno Schwalm.
26 Copyright (C) 2022 Martin Bařinka.
27 Copyright (C) 2025 Aurélien PIERRE.
28
29 darktable is free software: you can redistribute it and/or modify
30 it under the terms of the GNU General Public License as published by
31 the Free Software Foundation, either version 3 of the License, or
32 (at your option) any later version.
33
34 darktable is distributed in the hope that it will be useful,
35 but WITHOUT ANY WARRANTY; without even the implied warranty of
36 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 GNU General Public License for more details.
38
39 You should have received a copy of the GNU General Public License
40 along with darktable. If not, see <http://www.gnu.org/licenses/>.
41*/
42
43#ifdef HAVE_CONFIG_H
44#include "config.h"
45#endif
46
47#include "math/calculator.h"
48#include "system/atomic.h" // dt_atomic_uint64, for the generation counter
49#include "common/paths.h" // DT_PATH_MAX
50#include "darktable.h"
52#include "math/math.h"
53#include "common/conf.h"
54
55#include <glib.h>
56#include <glib/gstdio.h>
57#include <glib/gprintf.h>
58#include <inttypes.h>
59#include <stdio.h>
60#include <stdlib.h>
61#include <strings.h>
62#include "common/utility.h"
63
64typedef struct dt_conf_dreggn_t
65{
67 const char *match;
69
70static void _free_confgen_value(void *value)
71{
73 dt_free(s->def);
74 dt_free(s->min);
75 dt_free(s->max);
78 dt_free(s->longdesc);
79 dt_free(s);
80}
81
88static inline char *_dt_conf_get_var_locked(const char *name)
89{
90 char *str;
91
93 if(!IS_NULL_PTR(str)) return str;
94
96 if(!IS_NULL_PTR(str)) return str;
97
98 // not found, try defaults
100 if(!IS_NULL_PTR(str))
101 {
102 char *str_new = g_strdup(str);
104 return str_new;
105 }
106
107 // FIXME: why insert garbage?
108 // still no luck? insert garbage:
109 str = (char *)g_malloc0(sizeof(int32_t));
111 return str;
112}
113
115static inline char *dt_conf_get_var(const char *name)
116{
120 return str;
121}
122
147/* Advances on every write that actually CHANGES a value. It exists so a consumer on a hot
148 * path can cache what it derived from conf and re-derive only when this number moves: one
149 * atomic load replaces taking the mutex below, which the GUI thread holds constantly.
150 *
151 * It is deliberately one number for the whole table rather than one per key. A per-key
152 * version would need its own lookup -- i.e. the lock again -- to be read, which is the cost
153 * it was meant to avoid. The price is that any conf write invalidates every cache; conf is
154 * written by user action, so that is rare and the re-derivation is what the cache already
155 * did on every call.
156 *
157 * It starts at 1, so a consumer may use 0 as "never read" without a separate flag. */
158static dt_atomic_uint64 _conf_generation = 1;
159
164
165static int dt_conf_set_if_not_overridden(const char *name, char *str)
166{
168
170 int not_stored = (over && !strcmp(str, over));
171
172 if(!not_stored)
173 {
174 const char *current = (const char *)g_hash_table_lookup(darktable.conf->table, name);
175 if(!IS_NULL_PTR(current) && !strcmp(current, str))
176 {
177 // Unchanged: storing it would retire a perfectly good string for nothing.
178 not_stored = 1;
179 }
180 else
181 {
182 // Take the old entry out WITHOUT running the destroy functions, so we decide what
183 // happens to each half: the key was never handed to anyone and is ours to free, the
184 // value may still be held by a reader and is retired instead.
185 gpointer old_key = NULL;
186 gpointer old_value = NULL;
188 {
192 }
193
195
196 /* Bumped under the lock, and only where the value really moved -- the two `not_stored'
197 * branches above are a pinned override and a write of the identical string, neither of
198 * which any consumer needs to re-derive from. */
200 }
201 }
202
204
205 return not_stored;
206}
207
208void dt_conf_set_int(const char *name, int val)
209{
210 char *str = g_strdup_printf("%d", val);
212 {
213 dt_free(str);
214 }
215}
216
217void dt_conf_set_int64(const char *name, int64_t val)
218{
219 char *str = g_strdup_printf("%" PRId64, val);
221 {
222 dt_free(str);
223 }
224}
225
226void dt_conf_set_float(const char *name, float val)
227{
228 char *str = (char *)g_malloc(G_ASCII_DTOSTR_BUF_SIZE);
231 {
232 dt_free(str);
233 }
234}
235
236void dt_conf_set_bool(const char *name, int val)
237{
238 char *str = g_strdup(val ? "TRUE" : "FALSE");
240 {
241 dt_free(str);
242 }
243}
244
245void dt_conf_set_string(const char *name, const char *val)
246{
247 char *str = g_strdup(val);
249 {
250 dt_free(str);
251 }
252}
253
255{
256
257#ifdef WIN32
258 // for Windows native file chooser, gtk_file_chooser_get_current_folder()
259 // does not work, so we workaround
261 {
263 if(pathname)
264 {
267 {
269 }
271 }
272 return;
273 }
274#endif
275
278 {
280 }
281}
282
284{
285 const char *str = dt_conf_get_var(name);
287 if(isnan(new_value))
288 {
289 //we've got garbage, check default
290 const char *def_val = dt_confgen_get(name, DT_DEFAULT);
291 if(!IS_NULL_PTR(def_val))
292 {
294 if(isnan(new_value))
295 new_value = 0.0;
296 else
297 {
298 char *fix_badval = g_strdup(def_val);
300 {
302 }
303 }
304 }
305 else
306 {
307 new_value = 0.0;
308 }
309 }
310
311 int val;
312 if(new_value > 0)
313 val = new_value + 0.5;
314 else
315 val = new_value - 0.5;
316 return val;
317}
318
319int dt_conf_get_int(const char *name)
320{
321 const int min = dt_confgen_get_int(name, DT_MIN);
322 const int max = dt_confgen_get_int(name, DT_MAX);
323 const int val = dt_conf_get_int_fast(name);
324 const int ret = CLAMP(val, min, max);
325 return ret;
326}
327
328int64_t dt_conf_get_int64_fast(const char *name)
329{
330 const char *str = dt_conf_get_var(name);
332 if(isnan(new_value))
333 {
334 //we've got garbage, check default
335 const char *def_val = dt_confgen_get(name, DT_DEFAULT);
336 if(!IS_NULL_PTR(def_val))
337 {
339 if(isnan(new_value))
340 new_value = 0.0;
341 else
342 {
343 char *fix_badval = g_strdup(def_val);
345 {
347 }
348 }
349 }
350 else
351 {
352 new_value = 0.0;
353 }
354 }
355
356 int64_t val;
357 if(new_value > 0)
358 val = new_value + 0.5;
359 else
360 val = new_value - 0.5;
361 return val;
362}
363
364int64_t dt_conf_get_int64(const char *name)
365{
366 const int64_t min = dt_confgen_get_int64(name, DT_MIN);
367 const int64_t max = dt_confgen_get_int64(name, DT_MAX);
368 const int64_t val = dt_conf_get_int64_fast(name);
369 const int64_t ret = CLAMP(val, min, max);
370 return ret;
371}
372
373float dt_conf_get_float_fast(const char *name)
374{
375 const char *str = dt_conf_get_var(name);
377 if(isnan(new_value))
378 {
379 //we've got garbage, check default
380 const char *def_val = dt_confgen_get(name, DT_DEFAULT);
381 if(!IS_NULL_PTR(def_val))
382 {
384 if(isnan(new_value))
385 new_value = 0.0;
386 else
387 {
388 char *fix_badval = g_strdup(def_val);
390 {
392 }
393 }
394 }
395 else
396 {
397 new_value = 0.0;
398 }
399 }
400 return new_value;
401}
402
403float dt_conf_get_float(const char *name)
404{
405 const float min = dt_confgen_get_float(name, DT_MIN);
406 const float max = dt_confgen_get_float(name, DT_MAX);
407 const float val = dt_conf_get_float_fast(name);
408 const float ret = CLAMP(val, min, max);
409 return ret;
410}
411
412int dt_conf_get_and_sanitize_int(const char *name, int min, int max)
413{
414 const int cmin = dt_confgen_get_int(name, DT_MIN);
415 const int cmax = dt_confgen_get_int(name, DT_MAX);
416 const int val = dt_conf_get_int_fast(name);
417 const int ret = CLAMPS(val, MAX(min, cmin), MIN(max, cmax));
418 dt_conf_set_int(name, ret);
419 return ret;
420}
421
422int64_t dt_conf_get_and_sanitize_int64(const char *name, int64_t min, int64_t max)
423{
424 const int64_t cmin = dt_confgen_get_int64(name, DT_MIN);
425 const int64_t cmax = dt_confgen_get_int64(name, DT_MAX);
426 const int64_t val = dt_conf_get_int64_fast(name);
427 const int64_t ret = CLAMPS(val, MAX(min, cmin), MIN(max, cmax));
429 return ret;
430}
431
432float dt_conf_get_and_sanitize_float(const char *name, float min, float max)
433{
434 const float cmin = dt_confgen_get_float(name, DT_MIN);
435 const float cmax = dt_confgen_get_float(name, DT_MAX);
436 const float val = dt_conf_get_float_fast(name);
437 const float ret = CLAMPS(val, MAX(min, cmin), MIN(max, cmax));
439 return ret;
440}
441
442int dt_conf_get_bool(const char *name)
443{
444 const char *str = dt_conf_get_var(name);
445 const int val = (str[0] == 'T') || (str[0] == 't');
446 return val;
447}
448
449gchar *dt_conf_get_string(const char *name)
450{
451 // Copy the value before releasing the lock: dt_conf_get_var() hands back a pointer straight
452 // into the conf hash table, and a concurrent dt_conf_set_*() on the same key can free it
453 // (g_hash_table_insert() destroys the value it replaces) the moment the lock is released --
454 // a caller strdup'ing that pointer afterwards races the free. This was the mechanism behind a
455 // "write_sidecar_files silently flips to FALSE" report: dt_image_get_xmp_mode() reads this key
456 // from many threads per image, and a torn read masqueraded as an unrecognized/disabled value.
458 const char *str = _dt_conf_get_var_locked(name);
459 gchar *result = g_strdup(str);
461 return result;
462}
463
464const char *dt_conf_get_string_const(const char *name)
465{
466 return dt_conf_get_var(name);
467}
468
469gboolean dt_conf_key_not_empty(const char *name)
470{
471 const char *val = dt_conf_get_string_const(name);
472 if(IS_NULL_PTR(val)) return FALSE;
473 if(strlen(val) == 0) return FALSE;
474 return TRUE;
475}
476
478{
479 const gchar *folder = dt_conf_get_string_const(name);
480 if (!IS_NULL_PTR(folder))
481 {
483 return TRUE;
484 }
485 return FALSE;
486}
487
488gboolean dt_conf_is_equal(const char *name, const char *value)
489{
490 const char *str = dt_conf_get_var(name);
491 return g_strcmp0(str, value) == 0;
492}
493
494static char *_sanitize_confgen(const char *name, const char *value)
495{
497
498 if(IS_NULL_PTR(item)) return g_strdup(value);
499
500 char *result = NULL;
501
502 switch(item->type)
503 {
504 case DT_INT:
505 {
506 float v = dt_calculator_solve(1, value);
507
508 const int min = item->min ? (int)dt_calculator_solve(1, item->min) : INT_MIN;
509 const int max = item->max ? (int)dt_calculator_solve(1, item->max) : INT_MAX;
510 // if garbage, use default
511 const int val = isnan(v) ? dt_confgen_get_int(name, DT_DEFAULT) : (int)v;
512 result = g_strdup_printf("%d", CLAMP(val, min, max));
513 }
514 break;
515 case DT_INT64:
516 {
517 float v = dt_calculator_solve(1, value);
518
519 const int64_t min = item->min ? (int64_t)dt_calculator_solve(1, item->min) : INT64_MIN;
520 const int64_t max = item->max ? (int64_t)dt_calculator_solve(1, item->max) : INT64_MAX;
521 // if garbage, use default
522 const int64_t val = isnan(v) ? dt_confgen_get_int64(name, DT_DEFAULT) : (int64_t)v;
523 result = g_strdup_printf("%"PRId64, CLAMP(val, min, max));
524 }
525 break;
526 case DT_FLOAT:
527 {
528 float v = dt_calculator_solve(1, value);
529
530 const float min = item->min ? (float)dt_calculator_solve(1, item->min) : -FLT_MAX;
531 const float max = item->max ? (float)dt_calculator_solve(1, item->max) : FLT_MAX;
532 // if garbage, use default
533 const float val = isnan(v) ? dt_confgen_get_float(name, DT_DEFAULT) : v;
534 result = g_strdup_printf("%f", CLAMP(val, min, max));
535 }
536 break;
537 case DT_BOOL:
538 {
539 if(strcasecmp(value, "true") && strcasecmp(value, "false"))
541 else
542 result = g_strdup(value);
543 }
544 break;
545 case DT_ENUM:
546 {
547 char *v = g_strdup_printf("[%s]", value);
548 if(!strstr(item->enum_values, v))
550 else
551 result = g_strdup(value);
552 dt_free(v);
553 }
554 break;
555 default:
556 result = g_strdup(value);
557 break;
558 }
559
560 return result;
561}
562
563void dt_conf_init(dt_conf_t *cf, const char *filename, GSList *override_entries)
564{
566
568 // Values replaced by a later write live on here until shutdown, because
569 // dt_conf_get_string_const() may have handed one out. See dt_conf_set_if_not_overridden().
570 cf->retired_values = g_ptr_array_new_with_free_func(g_free);
573
574 // init conf filename
575 g_strlcpy(darktable.conf->filename, filename, sizeof(darktable.conf->filename));
576
577#define LINE_SIZE 1023
578
579 char line[LINE_SIZE + 1];
580
581 FILE *f = NULL;
582
583 // check for user config
584 f = g_fopen(filename, "rb");
585
586 // if file has been found, parse it
587
588 if(!IS_NULL_PTR(f))
589 {
590 while(!feof(f))
591 {
592 const int read = fscanf(f, "%" STR(LINE_SIZE) "[^\r\n]\r\n", line);
593 if(read > 0)
594 {
595 char *c = line;
596 char *end = line + strlen(line);
597 // check for '=' which is separator between the conf name and value
598 while(*c != '=' && c < end) c++;
599
600 if(*c == '=')
601 {
602 *c = '\0';
603
604 char *name = g_strdup(line);
605 // ensure that numbers are properly clamped if min/max
606 // defined and if not and garbage is read then the default
607 // value is returned.
608 char *value = _sanitize_confgen(name, (const char *)(c + 1));
609
611 }
612 }
613 }
614 fclose(f);
615 }
616 else
617 {
618 // we initialize the conf table with default values
620 gpointer key, value;
621
623 while (g_hash_table_iter_next (&iter, &key, &value))
624 {
625 const char *name = (const char *)key;
628 }
629 }
630
631 if(!IS_NULL_PTR(override_entries))
632 {
633 for(GSList *p = override_entries; p; p = g_slist_next(p))
634 {
637 }
638 }
639
640#undef LINE_SIZE
641
642 return;
643}
644
654
655static void _conf_add(char *key, char *val, dt_conf_dreggn_t *d)
656{
657 if(strncmp(key, d->match, strlen(d->match)) == 0)
658 {
660 nv->key = g_strdup(key + strlen(d->match) + 1);
661 nv->value = g_strdup(val);
662 d->result = g_slist_append(d->result, nv);
663 }
664}
665
677
678void dt_conf_string_entry_free(gpointer data)
679{
681 dt_free(nv->key);
682 dt_free(nv->value);
683 nv->key = NULL;
684 nv->value = NULL;
685 dt_free(nv);
686}
687
688gboolean dt_confgen_exists(const char *name)
689{
691}
692
694{
696
697 if(!IS_NULL_PTR(item))
698 return item->type;
699 else
700 return DT_STRING;
701}
702
704{
706 if(IS_NULL_PTR(item))
707 return FALSE;
708
709 switch(kind)
710 {
711 case DT_DEFAULT:
712 return !IS_NULL_PTR(item->def);
713 case DT_MIN:
714 return !IS_NULL_PTR(item->min);
715 case DT_MAX:
716 return !IS_NULL_PTR(item->max);
717 case DT_VALUES:
718 return !IS_NULL_PTR(item->enum_values);
719 }
720 return FALSE;
721}
722
724{
726
727 if(!IS_NULL_PTR(item))
728 {
729 switch(kind)
730 {
731 case DT_DEFAULT:
732 return item->def;
733 case DT_MIN:
734 return item->min;
735 case DT_MAX:
736 return item->max;
737 case DT_VALUES:
738 return item->enum_values;
739 }
740 }
741
742 return "";
743}
744
745const char *dt_confgen_get_label(const char *name)
746{
748
749 if(!IS_NULL_PTR(item))
750 {
751 return item->shortdesc;
752 }
753
754 return "";
755}
756
757const char *dt_confgen_get_tooltip(const char *name)
758{
760
761 if(!IS_NULL_PTR(item))
762 {
763 return item->longdesc;
764 }
765
766 return "";
767}
768
770{
772 {
773 //early bail
774 switch (kind)
775 {
776 case DT_MIN:
777 return INT_MIN;
778 break;
779 case DT_MAX:
780 return INT_MAX;
781 break;
782 default:
783 return 0;
784 break;
785 }
786 }
787 const char *str = dt_confgen_get(name, kind);
788
789 //if str is NULL or empty, dt_calculator_solve will return NAN
790 const float value = dt_calculator_solve(1, str);
791
792 switch (kind)
793 {
794 case DT_MIN:
795 return isnan(value) ? INT_MIN : (value > 0 ? value + 0.5f : value - 0.5f);
796 break;
797 case DT_MAX:
798 return isnan(value) ? INT_MAX : (value > 0 ? value + 0.5f : value - 0.5f);
799 break;
800 default:
801 return isnan(value) ? 0.0f : (value > 0 ? value + 0.5f : value - 0.5f);
802 break;
803 }
804 return (int)value;
805}
806
808{
810 {
811 //early bail
812 switch (kind)
813 {
814 case DT_MIN:
815 return INT64_MIN;
816 break;
817 case DT_MAX:
818 return INT64_MAX;
819 break;
820 default:
821 return 0;
822 break;
823 }
824 }
825 const char *str = dt_confgen_get(name, kind);
826
827 //if str is NULL or empty, dt_calculator_solve will return NAN
828 const float value = dt_calculator_solve(1, str);
829
830 switch (kind)
831 {
832 case DT_MIN:
833 return isnan(value) ? INT64_MIN : (value > 0 ? value + 0.5f : value - 0.5f);
834 break;
835 case DT_MAX:
836 return isnan(value) ? INT64_MAX : (value > 0 ? value + 0.5f : value - 0.5f);
837 break;
838 default:
839 return isnan(value) ? 0.0f : (value > 0 ? value + 0.5f : value - 0.5f);
840 break;
841 }
842 return (int64_t)value;
843}
844
846{
847 const char *str = dt_confgen_get(name, kind);
848 return !strcmp(str, "true");
849}
850
852{
854 {
855 //early bail
856 switch (kind)
857 {
858 case DT_MIN:
859 return -FLT_MAX;
860 break;
861 case DT_MAX:
862 return FLT_MAX;
863 break;
864 default:
865 break;
866 }
867 return 0.0f;
868 }
869
870 const char *str = dt_confgen_get(name, kind);
871
872 //if str is NULL or empty, dt_calculator_solve will return NAN
873 const float value = dt_calculator_solve(1, str);
874
875 switch (kind)
876 {
877 case DT_MIN:
878 // to anyone askig FLT_MIN is superclose to 0, not furthest value from 0 possible in float
879 return isnan(value) ? -FLT_MAX : value;
880 break;
881 case DT_MAX:
882 return isnan(value) ? FLT_MAX : value;
883 break;
884 default:
885 break;
886 }
887 return isnan(value) ? 0.0f : value;
888}
889
890gboolean dt_conf_is_default(const char *name)
891{
893 return TRUE; // well if default doesn't know about it, it's default
894
895 switch(dt_confgen_type(name))
896 {
897 case DT_INT:
899 break;
900 case DT_INT64:
902 break;
903 case DT_FLOAT:
905 break;
906 case DT_BOOL:
908 break;
909 case DT_PATH:
910 case DT_STRING:
911 case DT_ENUM:
912 default:
913 {
914 const char *def_val = dt_confgen_get(name, DT_DEFAULT);
915 const char *cur_val = dt_conf_get_var(name);
916 return g_strcmp0(def_val, cur_val) == 0;
917 break;
918 }
919 }
920}
921
922gchar* dt_conf_expand_default_dir(const char *dir)
923{
924 // expand special dirs
925#define CONFIG_DIR "$(config)"
926#define HOME_DIR "$(home)"
927
928 gchar *path = NULL;
930 {
931 gchar configdir[DT_PATH_MAX] = { 0 };
932 dt_loc_get_user_config_dir(configdir, sizeof(configdir));
933 path = g_strdup_printf("%s%s", configdir, dir + strlen(CONFIG_DIR));
934 }
935 else if(g_str_has_prefix(dir, HOME_DIR))
936 {
937 gchar *homedir = dt_loc_get_home_dir(NULL);
938 path = g_strdup_printf("%s%s", homedir, dir + strlen(HOME_DIR));
939 dt_free(homedir);
940 }
941 else path = g_strdup(dir);
942
944 dt_free(path);
945
946 return normalized_path;
947}
948
949static void dt_conf_print(const gchar *key, const gchar *val, FILE *f)
950{
951 fprintf(f, "%s=%s\n", key, val);
952}
953
955{
956 FILE *f = g_fopen(cf->filename, "wb");
957 if(!IS_NULL_PTR(f))
958 {
959 GList *keys = g_hash_table_get_keys(cf->table);
960 GList *sorted = g_list_sort(keys, (GCompareFunc)g_strcmp0);
961
962 for(GList *iter = sorted; iter; iter = g_list_next(iter))
963 {
964 const gchar *key = (const gchar *)iter->data;
965 const gchar *val = (const gchar *)g_hash_table_lookup(cf->table, key);
967 }
968
969 g_list_free(sorted);
970 sorted = NULL;
971 fclose(f);
972 }
973}
975{
977 g_hash_table_unref(cf->table);
978 g_hash_table_unref(cf->override_entries);
979 // Released last: every string here was handed out by dt_conf_get_string_const() at some
980 // point, so it stays alive for as long as any of the conf state does.
981 g_ptr_array_unref(cf->retired_values);
982 cf->retired_values = NULL;
983 g_hash_table_unref(cf->x_confgen);
985}
986
987// clang-format off
988// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
989// vim: shiftwidth=2 expandtab tabstop=2 cindent
990// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
991// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *var)
void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value)
float dt_calculator_solve(const float x, const char *formula)
Definition calculator.c:323
static const dt_adaptation_t kind
const float f
const float v
static const float const float const float min
const float max
void dt_conf_cleanup(dt_conf_t *cf)
Free everything cf owns. No dt_conf_*() call is valid afterwards.
void dt_conf_string_entry_free(gpointer data)
Free one dt_conf_string_entry_t. Shaped as a GDestroyNotify so it can be handed to g_slist_free_full(...
void dt_conf_set_bool(const char *name, int val)
int dt_conf_get_bool(const char *name)
#define HOME_DIR
int dt_conf_key_exists(const char *key)
Does key have a value?
float dt_confgen_get_float(const char *name, dt_confgen_value_kind_t kind)
int64_t dt_conf_get_int64_fast(const char *name)
Stored 64-bit integer for name, NOT clamped.
static char * _sanitize_confgen(const char *name, const char *value)
void dt_conf_init(dt_conf_t *cf, const char *filename, GSList *override_entries)
Populate cf from filename and from the generated defaults.
void dt_conf_set_float(const char *name, float val)
float dt_conf_get_float(const char *name)
Float for name, clamped to its declared bounds.
const char * dt_confgen_get_tooltip(const char *name)
Translated long description of name, borrowed and valid for the process lifetime. NULL when name is n...
uint64_t dt_conf_generation(void)
A counter that advances whenever a conf value actually changes.
static void _conf_add(char *key, char *val, dt_conf_dreggn_t *d)
static int dt_conf_set_if_not_overridden(const char *name, char *str)
gchar * dt_conf_get_string(const char *name)
Read the stored string for name as a private copy.
int dt_conf_get_int_fast(const char *name)
Stored integer for name, NOT clamped to its declared bounds.
int dt_conf_get_and_sanitize_int(const char *name, int min, int max)
static void _free_confgen_value(void *value)
Definition common/conf.c:70
void dt_conf_set_int(const char *name, int val)
gboolean dt_confgen_get_bool(const char *name, dt_confgen_value_kind_t kind)
void dt_conf_set_int64(const char *name, int64_t val)
gchar * dt_conf_expand_default_dir(const char *dir)
Expand the placeholders in a default directory string.
GSList * dt_conf_all_string_entries(const char *dir)
Every key under dir, as a list of copies.
gboolean dt_conf_is_default(const char *name)
Is name still at the value declared in the XML? FALSE for an undeclared key.
static char * _dt_conf_get_var_locked(const char *name)
Definition common/conf.c:88
static dt_atomic_uint64 _conf_generation
Store str for name unless the command line pinned that key.
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
int64_t dt_conf_get_int64(const char *name)
64-bit integer for name, clamped to its declared bounds.
gboolean dt_confgen_value_exists(const char *name, dt_confgen_value_kind_t kind)
int64_t dt_confgen_get_int64(const char *name, dt_confgen_value_kind_t kind)
gboolean dt_confgen_exists(const char *name)
int dt_confgen_get_int(const char *name, dt_confgen_value_kind_t kind)
#define LINE_SIZE
void dt_conf_set_string(const char *name, const char *val)
float dt_conf_get_float_fast(const char *name)
Stored float for name, NOT clamped.
const char * dt_conf_get_string_const(const char *name)
Borrow the stored string for name without copying it.
static char * dt_conf_get_var(const char *name)
const char * dt_confgen_get(const char *name, dt_confgen_value_kind_t kind)
One declared attribute of name from the generated XML, as text.
#define CONFIG_DIR
void dt_conf_save(dt_conf_t *cf)
Write cf back to its file. Overridden keys keep their stored value.
int64_t dt_conf_get_and_sanitize_int64(const char *name, int64_t min, int64_t max)
void dt_conf_set_folder_from_file_chooser(const char *name, GtkFileChooser *chooser)
dt_confgen_type_t dt_confgen_type(const char *name)
static void dt_conf_print(const gchar *key, const gchar *val, FILE *f)
gboolean dt_conf_is_equal(const char *name, const char *value)
const char * dt_confgen_get_label(const char *name)
Translated short description of name, borrowed and valid for the process lifetime....
gboolean dt_conf_get_folder_to_file_chooser(const char *name, GtkFileChooser *chooser)
float dt_conf_get_and_sanitize_float(const char *name, float min, float max)
gboolean dt_conf_key_not_empty(const char *name)
dt_confgen_value_kind_t
@ DT_DEFAULT
@ DT_MAX
@ DT_MIN
@ DT_VALUES
dt_confgen_type_t
Definition common/conf.h:60
@ DT_BOOL
Definition common/conf.h:64
@ DT_STRING
Definition common/conf.h:66
@ DT_FLOAT
Definition common/conf.h:63
@ DT_INT64
Definition common/conf.h:62
@ DT_ENUM
Definition common/conf.h:67
@ DT_PATH
Definition common/conf.h:65
@ DT_INT
Definition common/conf.h:61
darktable_t darktable
Definition darktable.c:213
GtkWidget * folder
destination folder chooser
const int res
Definition dtpthread.h:351
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:127
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Initialise a mutex. With mutexattr NULL – which is how 54 of the 56 call sites in this tree spell it ...
Definition dtpthread.h:104
static int dt_pthread_mutex_destroy(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:132
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:117
gchar * dt_loc_get_home_dir(const gchar *user)
void dt_loc_get_user_config_dir(char *configdir, size_t bufsize)
#define STR(x)
Stringify x after macro-expanding it, e.g. STR(LINE) gives "42".
Definition macros.h:49
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition macros.h:96
#define CLAMPS(A, L, H)
Definition math.h:78
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
Definition mem_alloc.h:184
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
char * key
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
Definition paths.h:57
const char * name
Definition pdf.h:90
static const dt_aligned_pixel_simd_t value
Definition simd.h:144
unsigned __int64 uint64_t
Definition strptime.c:75
struct dt_conf_t * conf
Definition darktable.h:184
const char * match
Definition common/conf.c:67
One key/value pair handed back by dt_conf_all_string_entries().
char * key
char * value
The whole configuration state. One instance lives at darktable.conf.
Definition common/conf.h:99
GHashTable * override_entries
GPtrArray * retired_values
dt_pthread_mutex_t mutex
GHashTable * x_confgen
GHashTable * table
char filename[DT_PATH_MAX]
dt_confgen_type_t type
Definition common/conf.h:72
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29
gchar * dt_util_normalize_path(const gchar *_input)
Definition utility.c:706