Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
darktable.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2014 johannes hanika.
4 Copyright (C) 2010-2011, 2015 Bruce Guenter.
5 Copyright (C) 2010-2012 Henrik Andersson.
6 Copyright (C) 2010 Richard Hughes.
7 Copyright (C) 2010-2020 Tobias Ellinghaus.
8 Copyright (C) 2011 Alexey Dokuchaev.
9 Copyright (C) 2011 Antony Dovgal.
10 Copyright (C) 2011 calca.
11 Copyright (C) 2011-2012 Christian Tellefsen.
12 Copyright (C) 2011 David Bremner.
13 Copyright (C) 2011-2012 Edouard Gomez.
14 Copyright (C) 2011 Kanstantsin Shautsou.
15 Copyright (C) 2011-2015 Pascal de Bruijn.
16 Copyright (C) 2011 Robert Bieber.
17 Copyright (C) 2011-2012, 2016-2018 Ulrich Pegelow.
18 Copyright (C) 2012 James C. McPherson.
19 Copyright (C) 2012 Jeroen Hegeman.
20 Copyright (C) 2012-2015 Jérémy Rosen.
21 Copyright (C) 2012-2013, 2015, 2018-2019 parafin.
22 Copyright (C) 2012 Richard Wonka.
23 Copyright (C) 2013, 2021 Aldric Renaudin.
24 Copyright (C) 2013 Jens Fendler.
25 Copyright (C) 2013, 2015, 2017, 2019-2022 Pascal Obry.
26 Copyright (C) 2013 Simon Spannagel.
27 Copyright (C) 2013 sthen.
28 Copyright (C) 2013 Stuart Henderson.
29 Copyright (C) 2014 Fernando R.
30 Copyright (C) 2014 Moritz Lipp.
31 Copyright (C) 2014-2015 Pedro Côrte-Real.
32 Copyright (C) 2014-2017, 2020 Roman Lebedev.
33 Copyright (C) 2015, 2017, 2019 Dan Torop.
34 Copyright (C) 2015 Jean-Sébastien Pédron.
35 Copyright (C) 2015 K. Adam Christensen.
36 Copyright (C) 2015 Matthias Gehre.
37 Copyright (C) 2016-2018 Peter Budai.
38 Copyright (C) 2017, 2021 luzpaz.
39 Copyright (C) 2018-2019 Edgardo Hoszowski.
40 Copyright (C) 2019 Alexis Mousset.
41 Copyright (C) 2019 Andreas Schneider.
42 Copyright (C) 2019, 2022-2023, 2025-2026 Aurélien PIERRE.
43 Copyright (C) 2019 Felipe Contreras.
44 Copyright (C) 2019-2022 Hanno Schwalm.
45 Copyright (C) 2019 Heiko Bauke.
46 Copyright (C) 2019 jakubfi.
47 Copyright (C) 2020 Chris Elston.
48 Copyright (C) 2020 David-Tillmann Schaefer.
49 Copyright (C) 2020-2022 Diederik Ter Rahe.
50 Copyright (C) 2020-2021 Hubert Kowalski.
51 Copyright (C) 2020 Matthieu Volat.
52 Copyright (C) 2020-2022 Philippe Weyland.
53 Copyright (C) 2020-2021 Ralf Brown.
54 Copyright (C) 2021 Ilya Kurdyukov.
55 Copyright (C) 2021 Paolo DePetrillo.
56 Copyright (C) 2022 Martin Bařinka.
57 Copyright (C) 2022 Victor Forsiuk.
58 Copyright (C) 2023 lologor.
59 Copyright (C) 2023 Luca Zulberti.
60 Copyright (C) 2023 Maurizio Paglia.
61 Copyright (C) 2024 Alynx Zhou.
62 Copyright (C) 2025-2026 Guillaume Stutin.
63 Copyright (C) 2025 Miguel Moquillon.
64
65 darktable is free software: you can redistribute it and/or modify
66 it under the terms of the GNU General Public License as published by
67 the Free Software Foundation, either version 3 of the License, or
68 (at your option) any later version.
69
70 darktable is distributed in the hope that it will be useful,
71 but WITHOUT ANY WARRANTY; without even the implied warranty of
72 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
73 GNU General Public License for more details.
74
75 You should have received a copy of the GNU General Public License
76 along with darktable. If not, see <http://www.gnu.org/licenses/>.
77*/
78#ifdef HAVE_CONFIG_H
79#include "config.h"
80#endif
81
82
83#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
84#include <malloc.h>
85#endif
86#ifdef __APPLE__
87#include <sys/malloc.h>
88#endif
89
90/* Platform memory-query APIs used by dt_get_total_memory()/dt_get_system_available_mem()
91 * below: sysctl(CTL_HW, ...) on Apple/BSD and the mach host/task statistics on Apple.
92 * These used to arrive through darktable.h's OS block; this TU is their only
93 * non-external consumer in the tree (common/telemetry.c carries its own), so it declares
94 * them itself. */
95#ifdef __APPLE__
96#include <mach/mach.h>
97#include <sys/sysctl.h>
98#endif
99#if defined(__DragonFly__) || defined(__FreeBSD__)
100#include <sys/sysctl.h>
101#include <sys/types.h>
102#endif
103#if defined(__NetBSD__) || defined(__OpenBSD__)
104#include <sys/param.h>
105#include <sys/sysctl.h>
106#endif
107
108#include "common/collection.h"
109#include "common/paths.h" // DT_PATH_MAX
112#include "metadata/colorlabels.h"
113#include "darktable.h"
114#include "common/anonymous_ids.h"
115#include "system/capabilities.h"
117#include "system/sys_resources.h"
118#include "common/datetime.h"
119#include "metadata/exif.h"
120#include "history/history.h"
122#include "common/selection.h"
123#include "gui/privacy_consent.h"
124#include "common/sentry.h"
125#include "common/telemetry.h"
126#include "common/updates.h"
128#include "widgets/bauhaus.h"
129#include "gui/presets.h"
130#include "gui/splash.h"
131
132#include "common/file_location.h"
133#include "common/film.h"
134#include "common/folder_survey.h"
136#include "common/grealpath.h"
137#include "common/image.h"
138#include "caches/image_cache.h"
139#include "database/database.h"
142#include "develop/iop_order.h"
143#include "common/l10n.h"
144#include "metadata/metadata.h"
145#include "common/image_notify.h"
147#include "history/notify.h"
148#include "history/presets.h"
149#include "metadata/notify.h"
150#include "caches/mipmap_cache.h"
151#include "common/noiseprofiles.h"
152#include "common/opencl.h"
153#include "common/points.h"
155#include "metadata/tags.h"
156#include "common/styles.h"
157#include "common/undo.h"
158#include "system/fp_mode.h"
159#include "common/conf.h"
160#include "control/control.h"
161#include "control/crawler.h"
163#include "control/signal.h"
165#include "develop/develop.h" // dt_dev_get_global(), dev->iop
166#include "develop/imageop.h"
167#include "develop/imageop_gui.h" // module->gui->expander
168#include "develop/supervisor.h"
169
170#include "gui/application.h"
172#include "develop/gui_throttle.h"
173#include "gui/guides.h"
174#include "gui/presets.h"
175#include "libs/lib.h"
176#include "views/view.h"
177#include "conf_gen.h"
178
179#include <errno.h>
180#if !defined(_WIN32) && !defined(__APPLE__)
181#include <fontconfig/fontconfig.h>
182#endif
183#include <glib.h>
184#include <glib/gstdio.h>
185#include <pango/pangocairo.h>
186#include <stdint.h>
187#include <stdio.h>
188#include <stdlib.h>
189#include <string.h>
190#include <sys/param.h>
191#include <sys/types.h>
192#include <unistd.h>
193#include <locale.h>
194#include <limits.h>
195
196#if defined(__x86_64__) || defined(__i386__)
197#include <xmmintrin.h>
198#endif
199
200
201#include "common/dbus.h"
202#include "common/utility.h"
203#include "common/times.h" // dt_times_t, dt_get_times(), dt_get_wtime(), dt_show_times()
204
205#if defined(__SUNOS__)
206#include <sys/varargs.h>
207#endif
208
209#ifdef _OPENMP
210#include <omp.h>
211#endif
212
214
215#if !defined(_WIN32) && !defined(__APPLE__)
216typedef struct _PangoFcFontMap PangoFcFontMap;
217extern GType pango_fc_font_map_get_type(void);
218extern void pango_fc_font_map_shutdown(PangoFcFontMap *fcfontmap);
219#endif
220
227static GLogWriterOutput _gtk_log_writer_filter(GLogLevelFlags log_level, const GLogField *fields,
228 gsize n_fields, gpointer user_data)
229{
230 const gchar *message = NULL;
231
232 for(gsize k = 0; k < n_fields; k++)
233 {
234 if(g_strcmp0(fields[k].key, "MESSAGE")) continue;
235
236 message = fields[k].value;
237 break;
238 }
239
240 // Silence only warnings/errors that come from default Adwaita CSS or desktop theme
241 // because there is nothing we can do about those.
242 // Yes, default Adwaita GTK CSS is still using deprecated GTK stuff in 2026...
243 // Even those morons can't keep up with the pace of their own deprecations.
244 if(message)
245 {
246 if(!g_strcmp0(message, "Unable to load dot from the cursor theme"))
247 return G_LOG_WRITER_HANDLED;
248
249 if(g_str_has_prefix(message, "Theme parsing error:")
250 && g_str_has_suffix(message, "The :insensitive pseudo-class is deprecated. Use :disabled instead."))
251 return G_LOG_WRITER_HANDLED;
252
253 if(g_str_has_prefix(message, "Theme parsing error:")
254 && g_str_has_suffix(message, "The :inconsistent pseudo-class is deprecated. Use :indeterminate instead."))
255 return G_LOG_WRITER_HANDLED;
256 }
257
258 return g_log_writer_default(log_level, fields, n_fields, user_data);
259}
260
261static int usage(const char *argv0)
262{
263#ifdef _WIN32
264 char *logfile = g_build_filename(g_get_user_cache_dir(), "ansel", "ansel-log.txt", NULL);
265#endif
266 // clang-format off
267 printf("usage: %s [options] [IMG_1234.{RAW,..}|image_folder/]\n", argv0);
268 printf("\n");
269 printf("options:\n");
270 printf("\n");
271 printf(" --cachedir <user cache directory>\n");
272 printf(" --conf <key>=<value>\n");
273 printf(" --configdir <user config directory>\n");
274 printf(" -d {all,cache,camctl,camsupport,colorprofile,control,demosaic,dev,gtk,history,imageio,import,\n");
275 printf(" input,ioporder,lighttable,lua,masks,memory,nan,nocache_reuse,opencl,params,\n");
276 printf(" perf,pipe,pipecache,print,signal,sql,shortcuts,tiling,undo,verbose}\n");
277 printf(" --d-signal <signal> \n");
278 printf(" --d-signal-act <all,raise,connect,disconnect");
279 // clang-format on
280#ifdef DT_HAVE_SIGNAL_TRACE
281 printf(",print-trace");
282#endif
283 printf(">\n");
284 printf(" --datadir <data directory>\n");
285#ifdef HAVE_OPENCL
286 printf(" --disable-opencl\n");
287#endif
288 printf(" --doc [documentation directory]\n");
289 printf(" -h, --help");
290#ifdef _WIN32
291 printf(", /?");
292#endif
293 printf("\n");
294 printf(" --library <library file>\n");
295 printf(" --localedir <locale directory>\n");
296 printf(" --moduledir <module directory>\n");
297 printf(" --noiseprofiles <noiseprofiles json file>\n");
298 printf(" -t <num openmp threads>\n");
299 printf(" --tmpdir <tmp directory>\n");
300 printf(" --version\n");
301#ifdef _WIN32
302 printf("\n");
303 printf(" note: debug log and output will be written to this file:\n");
304 printf(" %s\n", logfile);
305#endif
306
307#ifdef _WIN32
308 dt_free(logfile);
309#endif
310
311 return 1;
312}
313
315{
316 char ver[100] = { 0 };
317 g_strlcpy(ver, darktable_package_string, sizeof(ver));
318 int count = -1;
319 char *start = ver;
320 for(char *p = ver; *p; p++)
321 {
322 // first look for a number
323 if(count == -1)
324 {
325 if(*p >= '0' && *p <= '9')
326 {
327 count++;
328 start = p;
329 }
330 }
331 // then check for <major>.<minor>
332 else
333 {
334 if(*p == '.' || *p == '+') count++;
335 if(count == 2)
336 {
337 *p = '\0';
338 break;
339 }
340 }
341 }
342 return g_strdup(start);
343}
344
345const char *dt_session_id(void)
346{
347 // Random per-run UUID, generated once and shared by crash reporting and usage
348 // analytics so a single session can be correlated across Sentry and PostHog.
349 static gchar *id = NULL;
350 static gsize init = 0;
351 if(g_once_init_enter(&init))
352 {
353 id = g_uuid_string_random();
354 g_once_init_leave(&init, 1);
355 }
356 return id;
357}
358
359const char *dt_install_id(void)
360{
361 // Anonymous, stable per-installation UUID, persisted in conf and shared by crash
362 // reporting (Sentry user id) and usage analytics (PostHog distinct_id) so the
363 // same user can be de-duplicated across both systems. Created lazily on first use.
364 static gchar *id = NULL;
365 static gsize init = 0;
366 if(g_once_init_enter(&init))
367 {
368 gchar *stored = dt_conf_get_string("telemetry/install_id");
369 if(!stored || !*stored)
370 {
371 g_free(stored);
372 stored = g_uuid_string_random();
373 dt_conf_set_string("telemetry/install_id", stored);
374 }
375 id = stored;
376 g_once_init_leave(&init, 1);
377 }
378 return id;
379}
380
381gboolean dt_supported_image(const gchar *filename)
382{
383 char *ext = g_strrstr(filename, ".");
384 if(IS_NULL_PTR(ext))
385 return FALSE;
386 return dt_image_ext_is_supported(ext + 1);
387}
388
389int dt_load_from_string(const gchar *input, gboolean open_image_in_dr, gboolean *single_image)
390{
391 int32_t id = 0;
392 if(IS_NULL_PTR(input) || input[0] == '\0') return 0;
393
394 char *filename = dt_util_normalize_path(input);
395
396 if(IS_NULL_PTR(filename))
397 {
398 dt_control_log(_("found strange path `%s'"), input);
399 return 0;
400 }
401
402 if(g_file_test(filename, G_FILE_TEST_IS_DIR))
403 {
404 // import a directory into a film roll
405 id = dt_film_import(filename);
406 if(id)
407 {
408 dt_film_open(id);
409 dt_ctl_switch_mode_to("lighttable");
410 }
411 else
412 {
413 dt_control_log(_("error loading directory `%s'"), filename);
414 }
415 if(single_image) *single_image = FALSE;
416 }
417 else
418 {
419 // import a single image
420 gchar *directory = g_path_get_dirname((const gchar *)filename);
421 dt_film_t film;
422 const int filmid = dt_film_new(&film, directory);
423 id = dt_image_import(filmid, filename, TRUE);
425 if(id)
426 {
427 dt_film_open(filmid);
428 // make sure buffers are loaded (load full for testing)
431 gboolean loaded = (!IS_NULL_PTR(buf.buf));
433 if(!loaded)
434 {
435 id = 0;
436 dt_control_log(_("file `%s' has unknown format!"), filename);
437 }
438 else
439 {
440 if(open_image_in_dr)
441 {
443 dt_ctl_switch_mode_to("darkroom");
444 }
445 }
446 }
447 else
448 {
449 dt_control_log(_("error loading file `%s'"), filename);
450 }
451 if(single_image) *single_image = TRUE;
452 }
453 dt_free(filename);
454 return id;
455}
456
457// Returns total system memory in kiloBytes
458static inline size_t _get_total_memory()
459{
460#if defined(__linux__)
461 FILE *f = g_fopen("/proc/meminfo", "rb");
462 if(IS_NULL_PTR(f)) return 0;
463 size_t mem = 0;
464 char *line = NULL;
465 size_t len = 0;
466 int first = 1, found = 0;
467 // return "MemTotal" or the value from the first line
468 while(!found && getline(&line, &len, f) != -1)
469 {
470 char *colon = strchr(line, ':');
471 if(IS_NULL_PTR(colon)) continue;
472 found = !strncmp(line, "MemTotal:", 9);
473 if(found || first) mem = atol(colon + 1);
474 first = 0;
475 }
476 fclose(f);
477 if(len > 0)
478 {
479 dt_free(line);
480 }
481 return mem;
482#elif defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) \
483 || defined(__OpenBSD__)
484#if defined(__APPLE__)
485 int mib[2] = { CTL_HW, HW_MEMSIZE };
486#elif defined(HW_PHYSMEM64)
487 int mib[2] = { CTL_HW, HW_PHYSMEM64 };
488#else
489 int mib[2] = { CTL_HW, HW_PHYSMEM };
490#endif
491 uint64_t physical_memory;
492 size_t length = sizeof(uint64_t);
493 sysctl(mib, 2, (void *)&physical_memory, &length, (void *)NULL, 0);
494 return physical_memory / 1024;
495#elif defined _WIN32
496 MEMORYSTATUSEX memInfo;
497 memInfo.dwLength = sizeof(MEMORYSTATUSEX);
498 GlobalMemoryStatusEx(&memInfo);
499 return memInfo.ullTotalPhys / (uint64_t)1024;
500#else
501 // assume 2GB until we have a better solution.
502 fprintf(stderr, "Unknown memory size. Assuming 2GB\n");
503 return 2097152;
504#endif
505}
506
507void *dt_alloc_align(size_t size)
508{
510}
511
512/* Singleton accessors: the orchestrator BINDS the application-wide instances to the
513 * lower-level libs that declare these symbols (caches/pixelpipe_cache.h and
514 * common/openmp.h). This keeps those libs free of darktable.h — they link
515 * against two functions instead of importing the whole application struct. */
516
521
523{
524 return darktable.gui;
525}
526
528{
529 return darktable.develop;
530}
531
533{
534 return darktable.iop;
535}
536
541
543{
544 darktable.develop = dev;
545}
546
548{
549 return darktable.themes;
550}
551
552void dt_gui_set_themes(GList *themes)
553{
554 g_list_free_full(darktable.themes, dt_free_gpointer);
555 darktable.themes = themes;
556}
557
558/* The string is written by pipeline worker threads and read by the GUI thread painting the
559 * banner, so it carries its own lock rather than borrowing control->log_mutex: the borrowed
560 * one was taken by the single writer at its CALL SITE, which left the invariant unenforceable
561 * -- and left the reader, dt_control_draw_busy_msg(), holding no lock at all while a worker
562 * dt_free()d the very pointer it had handed to pango. That fired once per module per frame
563 * whenever the darkroom was rendering.
564 *
565 * A private lock also keeps this independent of dt_control_t's lifetime, which is freed at
566 * darktable.c's teardown while this string is not. */
567/* Static rather than initialised in dt_init() because this string is written from worker
568 * threads: a lock that is valid from program start has no window in which it is not.
569 *
570 * dt_pthread_mutex_t now wraps exactly one pthread_mutex_t -- the ~1.8 kB of _DEBUG
571 * instrumentation that used to trail it is gone -- so this initialiser is complete rather
572 * than relying on C11 6.7.9p21 zero-fill for the remainder.
573 *
574 * One consequence: this is one of the two locks in the tree that are NOT recursive.
575 * PTHREAD_MUTEX_INITIALIZER takes no attribute, and there is no portable static recursive
576 * initialiser (glibc hides PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP behind _GNU_SOURCE,
577 * mingw spells it without the _NP, neither is visible here). It guards a strdup and a
578 * pointer swap, calls nothing that could re-enter, and giving up the from-program-start
579 * validity to gain recursion would be the worse trade. See system/dtpthread.h. */
580static dt_pthread_mutex_t _main_message_lock = { PTHREAD_MUTEX_INITIALIZER };
581
589
597
602
603dt_pthread_mutex_t *dt_pipeline_threadsafe_mutex(void)
604{
606}
607
608
609
611{
612 return darktable.undo;
613}
614
619
621{
622 return darktable.lib;
623}
624
626{
627 return darktable.imageio;
628}
629
631{
632 return darktable.points;
633}
634
636{
637 return darktable.l10n;
638}
639
641{
642 return darktable.dbus;
643}
644
646{
647 return darktable.bauhaus;
648}
649
651{
652 return darktable.control;
653}
654
655
656/* --- pixelpipe cache handlers ------------------------------------------------
657 * See dt_dev_pixelpipe_cache_set_handlers(). These are the application's answers to the
658 * cache's three announcements; the cache itself names none of these subsystems. */
659static void _pixelpipe_cache_warn(const char *message)
660{
661 dt_control_log("%s", message);
662}
663
664static void _pixelpipe_cache_ready(uint64_t hash, uint64_t producer_node_key)
665{
667 producer_node_key);
668}
669
676
677
678/* The mipmap cache's user-facing settings live in conf; the cache does not read conf. The
679 * application owns that translation, here and in the preference-change handler below, which is
680 * what makes the lifecycle of these four visible: read at startup, re-read when the user
681 * changes one, never anywhere else. */
683{
686 s.disk_backend = dt_conf_get_bool("cache_disk_backend");
687 s.embedded_jpg = dt_conf_get_int("lighttable/embedded_jpg");
688 s.cache_quality = dt_conf_get_int("database_cache_quality");
689 return s;
690}
691
692/* Same arrangement for the database's maintenance and snapshot policy. These were read
693 * with dt_conf_* from five places inside database.c, several of them deep in a decision
694 * the user never sees. */
696{
697 dt_database_settings_t s = { 0 };
698 s.maintenance_check = dt_conf_get_string("database/maintenance_check");
699 s.maintenance_freepage_ratio = dt_conf_get_int("database/maintenance_freepage_ratio");
700 s.create_snapshot = dt_conf_get_string("database/create_snapshot");
701 s.keep_snapshots = dt_conf_get_int("database/keep_snapshots");
705}
706
707/* The database moved the legacy pre-XDG library file and settled on a new name for it.
708 * Persisting that is ours: the module does not write conf. */
709static void _database_renamed(const char *new_library_name)
710{
711 dt_conf_set_string("database", new_library_name);
712}
713
718
719/* src/metadata states what it did; where that appears is ours to decide. Installed
720 * unconditionally: dt_control_log()/dt_toast_log() are themselves no-ops without a GUI, so
721 * this keeps the headless behaviour the direct calls had. */
722static void _metadata_notify(const dt_metadata_notice_t kind, const char *message)
723{
725 dt_toast_log("%s", message);
726 else
727 dt_control_log("%s", message);
728}
729
730/* The pipeline worker names what it is chewing on; the banner and its repaint are ours.
731 * Called from worker threads, as the calls it replaces were -- dt_set_main_message()
732 * under log_mutex and the centre redraw are both worker-safe. */
733static void _pipeline_busy(const char *message_or_null)
734{
735 // dt_set_main_message() takes the string's own lock. Do NOT reintroduce an outer
736 // control->log_mutex here: it guards the message LOG, not this, and it bought nothing.
737 dt_set_main_message(message_or_null ? g_strdup(message_or_null) : NULL);
739}
740
741static void _pipeline_message(const char *message)
742{
743 dt_control_log("%s", message);
744}
745
746/* The geotag list is copied here, at the raise site, exactly where the old call sites
747 * copied it: the signal takes ownership of what it is given. */
748static void _metadata_geotags_changed(const GList *imgs)
749{
751 g_list_copy((GList *)imgs), 0);
752}
753
758
759/* History, styles and presets state what happened; turning that into a signal is ours. */
760static void _history_notify(const char *message)
761{
762 dt_control_log("%s", message);
763}
764
765static void _history_toast(const char *message)
766{
767 dt_toast_log("%s", message);
768}
769
785
786/* The copy is made here, at the raise site, exactly where the call site used to make it:
787 * the signal takes ownership of the list it is given, and the caller keeps its own. */
788static void _history_images_changed(const GList *imgs)
789{
791 g_list_copy((GList *)imgs));
792}
793
794/* Only the side that loaded the modules knows what an operation is called. */
795static const char *_history_operation_name(const char *operation)
796{
797 return dt_iop_get_localized_name(operation);
798}
799
800/* Only the side of the application that owns the panels can answer this. */
801static gboolean _presets_can_autoapply(const gchar *operation)
802{
803 for(const GList *lib_modules = dt_lib_get_global()->plugins; lib_modules;
804 lib_modules = g_list_next(lib_modules))
805 {
806 dt_lib_module_t *lib_module = (dt_lib_module_t *)lib_modules->data;
807 if(!strcmp(lib_module->plugin_name, operation)) return dt_lib_presets_can_autoapply(lib_module);
808 }
809 return TRUE;
810}
811
812/* The two parameters are the GTK signal signature, not ours; neither carries anything we
813 * need, since the settings are read from conf either way. */
814static void _preferences_changed(gpointer instance, gpointer user_data)
815{
816 (void)instance;
817 (void)user_data;
818
822}
823
824/* Same "read at startup, re-read on change, never anywhere else" lifecycle as the mipmap cache
825 * settings above, for the "write_sidecar_files" preference: dt_image_get_xmp_mode() is on the
826 * per-image hot path and reads a cache instead of conf directly. */
827/* Module inventories for the documentation capture panel (gui/actions/doc_screenshot.h).
828 *
829 * They live HERE, and that is deliberate. The panel lists tool modules and darkroom modules,
830 * which are dt_lib_module_t and dt_iop_module_t -- two and three layers above gui/, where the
831 * panel is. Reading them from there inverted the include graph four times over. The
832 * orchestrator is the one place that sits above every module by construction, so it is the
833 * only place that may legally see both lists; the panel asks for (widget, name) pairs and
834 * these hand them over.
835 *
836 * Called on every refresh of the panel, so they read the live lists rather than a snapshot.
837 */
838static void _doc_screenshot_lib_modules(void *inventory)
839{
840 // Tool modules of every view: the ones belonging to the view we are not in are unmapped,
841 // so they show up greyed out instead of disappearing from the inventory.
842 for(GList *item = dt_lib_get_global()->plugins; item; item = g_list_next(item))
843 {
844 dt_lib_module_t *module = (dt_lib_module_t *)item->data;
845 GtkWidget *target = IS_NULL_PTR(module->expander) ? module->widget : module->expander;
846 dt_gui_doc_screenshot_add_target(inventory, target, module->common_fields.name);
847 }
848}
849
850static void _doc_screenshot_iop_modules(void *inventory)
851{
852 // This list is only populated while an image is open in darkroom.
853 for(GList *item = dt_dev_get_global()->iop; item; item = g_list_next(item))
854 {
855 dt_iop_module_t *module = (dt_iop_module_t *)item->data;
856 if(IS_NULL_PTR(module->gui) || IS_NULL_PTR(module->gui->expander)) continue;
857
858 // Several instances of the same module share a name: keep them apart in the tree, and
859 // therefore in the file names too.
860 gchar *label = (module->multi_name[0] != '\0')
861 ? g_strdup_printf("%s (%s)", module->common_fields.name, module->multi_name)
862 : g_strdup(module->common_fields.name);
863 dt_gui_doc_screenshot_add_target(inventory, module->gui->expander, label);
864 dt_free(label);
865 }
866}
867
868static void _xmp_mode_preferences_changed(gpointer instance, gpointer user_data)
869{
870 (void)instance;
871 (void)user_data;
872
874}
875
876
877// Nightly update check found a newer build (GUI thread). Help > Update to the latest
878// nightly build opens the same URL; here we only say so.
879static void _updates_notify(const char *version, const char *url)
880{
881 dt_control_log(_("A newer nightly build is available (%s).\nHelp ▸ Update to the latest nightly build"), version);
882}
883
884int dt_init(int argc, char *argv[], const gboolean init_gui, const gboolean load_data)
885{
886 double start_wtime = dt_get_wtime();
887
888#ifndef _WIN32
889 if(getuid() == 0 || geteuid() == 0)
890 printf(
891 "WARNING: either your user id or the effective user id are 0. are you running darktable as root?\n");
892#endif
893
894 dt_fp_init(DT_FP_MODE_FAST);
895
897
898#ifdef M_MMAP_THRESHOLD
899 mallopt(M_MMAP_THRESHOLD, 128 * 1024); /* use mmap() for large allocations */
900#endif
901
902 // make sure that stack/frame limits are good (musl)
904
905 // init all pointers to 0:
906 memset(&darktable, 0, sizeof(darktable_t));
907
908 darktable.start_wtime = start_wtime;
909
910 darktable.progname = argv[0];
911
912 darktable.main_message = NULL;
913
914 // FIXME: move there into dt_database_t
917
918 darktable.control = (dt_control_t *)calloc(1, sizeof(dt_control_t));
919
920 // database
921 char *dbfilename_from_command = NULL;
922 char *noiseprofiles_from_command = NULL;
923 char *datadir_from_command = NULL;
924 char *moduledir_from_command = NULL;
925 char *localedir_from_command = NULL;
926 char *tmpdir_from_command = NULL;
927 char *configdir_from_command = NULL;
928 char *cachedir_from_command = NULL;
929 char *kerneldir_from_command = NULL;
930
931#ifdef HAVE_OPENCL
932 gboolean exclude_opencl = FALSE;
933 gboolean print_statistics = (strstr(argv[0], "ansel-cltest") == NULL);
934#endif
935
937#ifdef _OPENMP
939#endif
940
941 darktable.unmuted = 0;
942 gboolean cpu_threads_from_cli = FALSE;
943
944 GSList *config_override = NULL;
945 for(int k = 1; k < argc; k++)
946 {
947#ifdef _WIN32
948 if(!strcmp(argv[k], "/?"))
949 {
950 return usage(argv[0]);
951 }
952#endif
953 if(argv[k][0] == '-')
954 {
955 if(!strcmp(argv[k], "--help") || !strcmp(argv[k], "-h"))
956 {
957 return usage(argv[0]);
958 }
959 else if(!strcmp(argv[k], "--version"))
960 {
961 printf("this is %s\ncopyright (c) 2009-2022 Johannes Hanika, (c) 2022-%s Aurélien Pierre\n" PACKAGE_BUGREPORT "\n\ncompile options:\n"
962 " bit depth is %" G_GSIZE_FORMAT " bit\n"
963#ifdef _DEBUG
964 " debug build\n"
965#else
966 " normal build\n"
967#endif
968#ifdef _OPENMP
969 " OpenMP support enabled\n"
970#else
971 " OpenMP support disabled\n"
972#endif
973
974#ifdef HAVE_OPENCL
975 " OpenCL support enabled\n"
976#else
977 " OpenCL support disabled\n"
978#endif
979
980#ifdef USE_COLORDGTK
981 " Colord support enabled\n"
982#else
983 " Colord support disabled\n"
984#endif
985
986#ifdef HAVE_OPENEXR
987 " OpenEXR support enabled\n"
988#else
989 " OpenEXR support disabled\n"
990#endif
991 ,
994 CHAR_BIT * sizeof(void *)
995 );
996 return 1;
997 }
998 else if(!strcmp(argv[k], "--library") && argc > k + 1)
999 {
1000 dbfilename_from_command = argv[++k];
1001 argv[k-1] = NULL;
1002 argv[k] = NULL;
1003 }
1004 else if(!strcmp(argv[k], "--datadir") && argc > k + 1)
1005 {
1006 datadir_from_command = argv[++k];
1007 argv[k-1] = NULL;
1008 argv[k] = NULL;
1009 }
1010 else if(!strcmp(argv[k], "--moduledir") && argc > k + 1)
1011 {
1012 moduledir_from_command = argv[++k];
1013 argv[k-1] = NULL;
1014 argv[k] = NULL;
1015 }
1016 else if(!strcmp(argv[k], "--tmpdir") && argc > k + 1)
1017 {
1018 tmpdir_from_command = argv[++k];
1019 argv[k-1] = NULL;
1020 argv[k] = NULL;
1021 }
1022 else if(!strcmp(argv[k], "--configdir") && argc > k + 1)
1023 {
1024 configdir_from_command = argv[++k];
1025 argv[k-1] = NULL;
1026 argv[k] = NULL;
1027 }
1028 else if(!strcmp(argv[k], "--cachedir") && argc > k + 1)
1029 {
1030 cachedir_from_command = argv[++k];
1031 argv[k-1] = NULL;
1032 argv[k] = NULL;
1033 }
1034 else if(!strcmp(argv[k], "--localedir") && argc > k + 1)
1035 {
1036 localedir_from_command = argv[++k];
1037 argv[k-1] = NULL;
1038 argv[k] = NULL;
1039 }
1040 else if(!strcmp(argv[k], "--kerneldir") && argc > k + 1)
1041 {
1042 kerneldir_from_command = argv[++k];
1043 argv[k-1] = NULL;
1044 argv[k] = NULL;
1045 }
1046 else if(argv[k][1] == 'd' && argc > k + 1)
1047 {
1048 if(!strcmp(argv[k + 1], "all"))
1049 darktable.unmuted = 0xffffffff & ~DT_DEBUG_VERBOSE; // enable all debug information except verbose
1050 else if(!strcmp(argv[k + 1], "cache"))
1051 darktable.unmuted |= DT_DEBUG_CACHE; // enable debugging for lib/film/cache module
1052 else if(!strcmp(argv[k + 1], "control"))
1053 darktable.unmuted |= DT_DEBUG_CONTROL; // enable debugging for scheduler module
1054 else if(!strcmp(argv[k + 1], "dev"))
1055 darktable.unmuted |= DT_DEBUG_DEV; // develop module
1056 else if(!strcmp(argv[k + 1], "gtk"))
1057 darktable.unmuted |= DT_DEBUG_GTK; // GTK widgets and display setup
1058 else if(!strcmp(argv[k + 1], "input"))
1059 darktable.unmuted |= DT_DEBUG_INPUT; // input devices
1060 else if(!strcmp(argv[k + 1], "pipecache"))
1061 darktable.unmuted |= DT_DEBUG_PIPECACHE; // pipeline cache
1062 else if(!strcmp(argv[k + 1], "perf"))
1063 darktable.unmuted |= DT_DEBUG_PERF; // performance measurements
1064 else if(!strcmp(argv[k + 1], "opencl"))
1065 darktable.unmuted |= DT_DEBUG_OPENCL; // gpu accel via opencl
1066 else if(!strcmp(argv[k + 1], "sql"))
1067 darktable.unmuted |= DT_DEBUG_SQL; // SQLite3 queries
1068 else if(!strcmp(argv[k + 1], "memory"))
1069 darktable.unmuted |= DT_DEBUG_MEMORY; // some stats on mem usage now and then.
1070 else if(!strcmp(argv[k + 1], "lighttable"))
1071 darktable.unmuted |= DT_DEBUG_LIGHTTABLE; // lighttable related stuff.
1072 else if(!strcmp(argv[k + 1], "nan"))
1073 darktable.unmuted |= DT_DEBUG_NAN; // check for NANs when processing the pipe.
1074 else if(!strcmp(argv[k + 1], "masks"))
1075 darktable.unmuted |= DT_DEBUG_MASKS; // masks related stuff.
1076 else if(!strcmp(argv[k + 1], "lua"))
1077 darktable.unmuted |= DT_DEBUG_LUA; // lua errors are reported on console
1078 else if(!strcmp(argv[k + 1], "print"))
1079 darktable.unmuted |= DT_DEBUG_PRINT; // print errors are reported on console
1080 else if(!strcmp(argv[k + 1], "camsupport"))
1081 darktable.unmuted |= DT_DEBUG_CAMERA_SUPPORT; // camera support warnings are reported on console
1082 else if(!strcmp(argv[k + 1], "colorprofile"))
1083 darktable.unmuted |= DT_DEBUG_COLORPROFILE; // color profile handling
1084 else if(!strcmp(argv[k + 1], "nocache_reuse"))
1085 darktable.unmuted |= DT_DEBUG_NOCACHE_REUSE; // disable reusable pixelpipe cache buffers
1086 else if(!strcmp(argv[k + 1], "ioporder"))
1087 darktable.unmuted |= DT_DEBUG_IOPORDER; // iop order information are reported on console
1088 else if(!strcmp(argv[k + 1], "imageio"))
1089 darktable.unmuted |= DT_DEBUG_IMAGEIO; // image importing or exporting messages on console
1090 else if(!strcmp(argv[k + 1], "undo"))
1091 darktable.unmuted |= DT_DEBUG_UNDO; // undo/redo
1092 else if(!strcmp(argv[k + 1], "signal"))
1093 darktable.unmuted |= DT_DEBUG_SIGNAL; // signal information on console
1094 else if(!strcmp(argv[k + 1], "params"))
1095 darktable.unmuted |= DT_DEBUG_PARAMS; // iop module params checks on console
1096 else if(!strcmp(argv[k + 1], "demosaic"))
1098 else if(!strcmp(argv[k + 1], "shortcuts"))
1100 else if(!strcmp(argv[k + 1], "tiling"))
1102 else if(!strcmp(argv[k + 1], "verbose"))
1104 else if(!strcmp(argv[k + 1], "pipe"))
1106 else if(!strcmp(argv[k + 1], "history"))
1108 else if(!strcmp(argv[k + 1], "import"))
1110 else if(!strcmp(argv[k + 1], "supervisor"))
1111 darktable.unmuted |= DT_DEBUG_SUPERVISOR; // high-level event supervisor (NDJSON)
1112 else
1113 return usage(argv[0]);
1114 k++;
1115 argv[k-1] = NULL;
1116 argv[k] = NULL;
1117 }
1118 else if(!strcmp(argv[k], "--d-signal-act") && argc > k + 1)
1119 {
1120 if(!strcmp(argv[k + 1], "all"))
1121 darktable.unmuted_signal_dbg_acts = 0xffffffff; // enable all signal debug information
1122 else if(!strcmp(argv[k + 1], "raise"))
1123 darktable.unmuted_signal_dbg_acts |= DT_DEBUG_SIGNAL_ACT_RAISE; // enable debugging for signal raising
1124 else if(!strcmp(argv[k + 1], "connect"))
1125 darktable.unmuted_signal_dbg_acts |= DT_DEBUG_SIGNAL_ACT_CONNECT; // enable debugging for signal connection
1126 else if(!strcmp(argv[k + 1], "disconnect"))
1127 darktable.unmuted_signal_dbg_acts |= DT_DEBUG_SIGNAL_ACT_DISCONNECT; // enable debugging for signal disconnection
1128 else if(!strcmp(argv[k + 1], "print-trace"))
1129 {
1130#ifdef DT_HAVE_SIGNAL_TRACE
1131 darktable.unmuted_signal_dbg_acts |= DT_DEBUG_SIGNAL_ACT_PRINT_TRACE; // enable printing of signal tracing
1132#else
1133 fprintf(stderr, "[signal] print-trace not available, skipping\n");
1134#endif
1135 }
1136 else
1137 return usage(argv[0]);
1138 k++;
1139 argv[k-1] = NULL;
1140 argv[k] = NULL;
1141 }
1142 else if(!strcmp(argv[k], "--d-signal") && argc > k + 1)
1143 {
1144 gchar *str = g_ascii_strup(argv[k+1], -1);
1145
1146 #define CHKSIGDBG(sig) else if(!g_strcmp0(str, #sig)) do {darktable.unmuted_signal_dbg[sig] = TRUE;} while (0)
1147 if(!g_strcmp0(str, "ALL"))
1148 {
1149 for(int sig=0; sig<DT_SIGNAL_COUNT; sig++)
1151 }
1193
1194 else
1195 {
1196 fprintf(stderr, "unknown signal name: '%s'. use 'ALL' to enable debug for all or use full signal name\n", str);
1197 return usage(argv[0]);
1198 }
1199 dt_free(str);
1200 #undef CHKSIGDBG
1201 k++;
1202 argv[k-1] = NULL;
1203 argv[k] = NULL;
1204 }
1205 else if(argv[k][1] == 't' && argc > k + 1)
1206 {
1207 darktable.num_openmp_threads = CLAMP(atol(argv[k + 1]), 1, 100);
1208 printf("[dt_init] using %d threads for openmp parallel sections\n", darktable.num_openmp_threads);
1209 k++;
1210 argv[k-1] = NULL;
1211 argv[k] = NULL;
1212 cpu_threads_from_cli = TRUE;
1213 }
1214 else if(!strcmp(argv[k], "--conf") && argc > k + 1)
1215 {
1216 gchar *keyval = g_strdup(argv[++k]), *c = keyval;
1217 argv[k-1] = NULL;
1218 argv[k] = NULL;
1219 gchar *end = keyval + strlen(keyval);
1220 while(*c != '=' && c < end) c++;
1221 if(*c == '=' && *(c + 1) != '\0')
1222 {
1223 *c++ = '\0';
1225 entry->key = g_strdup(keyval);
1226 entry->value = g_strdup(c);
1227 config_override = g_slist_append(config_override, entry);
1228 }
1229 dt_free(keyval);
1230 }
1231 else if(!strcmp(argv[k], "--noiseprofiles") && argc > k + 1)
1232 {
1233 noiseprofiles_from_command = argv[++k];
1234 argv[k-1] = NULL;
1235 argv[k] = NULL;
1236 }
1237 else if(!strcmp(argv[k], "--disable-opencl"))
1238 {
1239#ifdef HAVE_OPENCL
1240 exclude_opencl = TRUE;
1241#endif
1242 argv[k] = NULL;
1243 }
1244 else if(!strcmp(argv[k], "--doc"))
1245 {
1246 // Documentation mode: unlocks the widget-screenshot panel in the "Run" menu. Both
1247 // the flag and the directory belong to that module, the only thing that reads them
1248 // back. The optional directory is the root of the documentation tree to write into.
1249 //
1250 // It is consumed only when it really is an existing directory, so that
1251 // `ansel --doc IMG_1234.RAW` still opens the raw file rather than swallowing it.
1252 argv[k] = NULL;
1253 if(argc > k + 1 && !IS_NULL_PTR(argv[k + 1]) && g_file_test(argv[k + 1], G_FILE_TEST_IS_DIR))
1254 {
1256 argv[k] = NULL;
1257 }
1261 }
1262 else if(!strcmp(argv[k], "--debug"))
1263 {
1264 argv[k] = NULL;
1265 }
1266 else if(!strcmp(argv[k], "--"))
1267 {
1268 // "--" confuses the argument parser of glib/gtk. remove it.
1269 argv[k] = NULL;
1270 break;
1271 }
1272#ifdef __APPLE__
1273 else if(!strncmp(argv[k], "-psn_", 5))
1274 {
1275 // "-psn_*" argument is added automatically by macOS and should be ignored
1276 argv[k] = NULL;
1277 }
1278#endif
1279 else
1280 return usage(argv[0]); // fail on unrecognized options
1281 }
1282 }
1283
1284 // remove the NULLs to not confuse gtk_init() later.
1285 for(int i = 1; i < argc; i++)
1286 {
1287 int k;
1288 for(k = i; k < argc; k++)
1289 if(!IS_NULL_PTR(argv[k])) break;
1290
1291 if(k > i)
1292 {
1293 k -= i;
1294 for(int j = i + k; j < argc; j++)
1295 {
1296 argv[j-k] = argv[j];
1297 argv[j] = NULL;
1298 }
1299 argc -= k;
1300 }
1301 }
1302
1303 // get valid directories
1304 dt_loc_init(datadir_from_command, moduledir_from_command, localedir_from_command, configdir_from_command, cachedir_from_command, tmpdir_from_command, kerneldir_from_command);
1305
1306 fprintf(stdout, "[build] version: %s\n", darktable_package_string);
1307 fprintf(stdout, "[build] type: %s | cpu mode: %s\n", DT_BUILD_TYPE, DT_BUILD_CPU_MODE);
1308 fprintf(stdout, "[build] c compiler: %s\n", DT_BUILD_C_COMPILER);
1309 fprintf(stdout, "[build] c flags: %s\n", DT_BUILD_C_FLAGS);
1310 fprintf(stdout, "[build] c++ compiler: %s\n", DT_BUILD_CXX_COMPILER);
1311 fprintf(stdout, "[build] c++ flags: %s\n", DT_BUILD_CXX_FLAGS);
1312
1314 {
1315 fprintf(stderr, "[memory] at startup\n");
1317 }
1318
1319 char sharedir[DT_PATH_MAX] = { 0 };
1320 dt_loc_get_sharedir(sharedir, sizeof(sharedir));
1321
1322 // we have to have our share dir in XDG_DATA_DIRS,
1323 // otherwise GTK+ won't find our logo for the about screen (and maybe other things)
1324 {
1325 const gchar *xdg_data_dirs = g_getenv("XDG_DATA_DIRS");
1326 gchar *new_xdg_data_dirs = NULL;
1327 gboolean set_env = TRUE;
1328 if(!IS_NULL_PTR(xdg_data_dirs) && *xdg_data_dirs != '\0')
1329 {
1330 // check if sharedir is already in there
1331 gboolean found = FALSE;
1332 gchar **tokens = g_strsplit(xdg_data_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
1333 // xdg_data_dirs is neither NULL nor empty => !IS_NULL_PTR(tokens)
1334 for(char **iter = tokens; !IS_NULL_PTR(*iter); iter++)
1335 if(!strcmp(sharedir, *iter))
1336 {
1337 found = TRUE;
1338 break;
1339 }
1340 g_strfreev(tokens);
1341 if(found)
1342 set_env = FALSE;
1343 else
1344 new_xdg_data_dirs = g_strjoin(G_SEARCHPATH_SEPARATOR_S, sharedir, xdg_data_dirs, NULL);
1345 }
1346 else
1347 {
1348#ifndef _WIN32
1349 // see http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html for a reason to use those as a
1350 // default
1351 if(!g_strcmp0(sharedir, "/usr/local/share")
1352 || !g_strcmp0(sharedir, "/usr/local/share/")
1353 || !g_strcmp0(sharedir, "/usr/share") || !g_strcmp0(sharedir, "/usr/share/"))
1354 new_xdg_data_dirs = g_strdup("/usr/local/share/" G_SEARCHPATH_SEPARATOR_S "/usr/share/");
1355 else
1356 new_xdg_data_dirs = g_strdup_printf("%s" G_SEARCHPATH_SEPARATOR_S "/usr/local/share/" G_SEARCHPATH_SEPARATOR_S
1357 "/usr/share/", sharedir);
1358#else
1359 set_env = FALSE;
1360#endif
1361 }
1362
1363 if(set_env) g_setenv("XDG_DATA_DIRS", new_xdg_data_dirs, 1);
1364 dt_print(DT_DEBUG_DEV, "new_xdg_data_dirs: %s\n", new_xdg_data_dirs);
1365 dt_free(new_xdg_data_dirs);
1366 }
1367
1368 setlocale(LC_ALL, "");
1369 char localedir[DT_PATH_MAX] = { 0 };
1370 dt_loc_get_localedir(localedir, sizeof(localedir));
1371 bindtextdomain(GETTEXT_PACKAGE, localedir);
1372 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
1373 textdomain(GETTEXT_PACKAGE);
1374
1375 if(init_gui)
1376 {
1377 // I doubt that connecting to dbus for ansel-cli makes sense
1378 darktable.dbus = NULL; //dt_dbus_init();
1379
1380 // make sure that we have no stale global progress bar visible. thus it's run as early as possible
1382 }
1383
1384 // thread-safe init:
1385 dt_exif_init();
1386 char datadir[DT_PATH_MAX] = { 0 };
1387 dt_loc_get_user_config_dir(datadir, sizeof(datadir));
1388 char anselrc[DT_PATH_MAX] = { 0 };
1389 dt_concat_path_file(anselrc, datadir, "anselrc");
1390
1391 // initialize the config backend. this needs to be done first...
1392 darktable.conf = (dt_conf_t *)calloc(1, sizeof(dt_conf_t));
1393 dt_conf_init(darktable.conf, anselrc, config_override);
1394 g_slist_free_full(config_override, dt_free_gpointer);
1395
1396 // set the interface language and prepare selection for prefs
1397 darktable.l10n = dt_l10n_init(init_gui);
1398
1399 dt_confgen_init();
1400 // The throttle's persisted state and timeout preference are configuration, so they are
1401 // supplied here rather than read inside it.
1402 dt_gui_throttle_init(dt_conf_get_int("processing/gui_throttle_runtime_us"));
1403 dt_gui_throttle_set_timeout_ms((guint)MAX(dt_conf_get_int("processing/timeout"), 0));
1404
1405 // Needs to run after dt_confgen_init()
1406 // Don't override cli argument if any
1407 if(!cpu_threads_from_cli)
1408 {
1409 const int user_threads = dt_conf_get_int("cpu_threads");
1410 if(user_threads > 0) darktable.num_openmp_threads = user_threads;
1411 }
1412
1413#ifdef _OPENMP
1414 omp_set_num_threads(darktable.num_openmp_threads);
1415#endif
1416
1417 // we need this REALLY early so that error messages can be shown, however after gtk_disable_setlocale
1418 if(init_gui)
1419 {
1420 g_log_set_writer_func(_gtk_log_writer_filter, NULL, NULL);
1421 gtk_init(&argc, &argv);
1422
1423 darktable.themes = NULL;
1424 }
1425
1426 // build the colour-profile module's own list; it owns it, we do not hold it
1428
1429 // initialize datetime data
1431
1432 // initialize the database
1433 //
1434 // Every user preference the database acts on is read here and handed over, so that the
1435 // SQL layer never reads conf itself and "when does this take effect" has one answer.
1443
1444 gchar *configured_library = dt_conf_get_string("database");
1445 const dt_database_params_t db_params = { .alternative = dbfilename_from_command,
1446 .library = configured_library,
1447 .load_data = load_data,
1448 .has_gui = init_gui,
1449 .verbose = (dt_get_debug_flags() & DT_DEBUG_SQL) != 0 };
1450
1451 gboolean recheck_needed = TRUE;
1452 while (recheck_needed)
1453 {
1454 // Before, not after: dt_database_open() can hit a read-only or corrupt database and needs
1455 // to ask the user what to do about it, and dt_gui_gtk_init() -- where every other backend
1456 // handler is registered -- only runs much further down. This is the only place that knows
1457 // this early whether there will be anybody to ask.
1458 if(init_gui) dt_database_gui_register_handlers();
1459
1460 const dt_database_open_result_t opened = dt_database_open(&db_params);
1461 if(opened == DT_DATABASE_OPEN_FAILED)
1462 {
1463 printf("ERROR : cannot open database\n");
1464 dt_free(configured_library);
1466 return 1;
1467 }
1468 else if(opened == DT_DATABASE_OPEN_LOCKED)
1469 {
1470 gboolean error = FALSE;
1471
1472 if (init_gui)
1473 {
1474 gboolean image_loaded_elsewhere = FALSE;
1475#ifndef MAC_INTEGRATION
1476 // send the images to the other instance via dbus
1477 fprintf(stderr, "trying to open the images in the running instance\n");
1478
1480 {
1481 GDBusConnection *connection = NULL;
1482 for(int i = 1; i < argc; i++)
1483 {
1484 // make the filename absolute ...
1485 if(argv[i] == NULL || *argv[i] == '\0') continue;
1486 gchar *filename = dt_util_normalize_path(argv[i]);
1487 if(IS_NULL_PTR(filename)) continue;
1488 if(IS_NULL_PTR(connection)) connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
1489 // ... and send it to the running instance of darktable
1490 image_loaded_elsewhere = g_dbus_connection_call_sync(connection, "org.darktable.service", "/darktable",
1491 "org.darktable.service.Remote", "Open",
1492 g_variant_new("(s)", filename), NULL,
1493 G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL) != NULL;
1494 dt_free(filename);
1495 }
1496 if(connection) g_object_unref(connection);
1497 }
1498#endif
1499 if(!image_loaded_elsewhere)
1500 // Reporting CONSUMES the pending error.
1502 }
1503 if(error)
1504 {
1505 fprintf(stderr, "ERROR: can't acquire database lock, aborting.\n");
1506 dt_free(configured_library);
1508 return error;
1509 }
1510 else
1511 {
1512 // Close before retrying. The loop used to jump straight back to
1513 // dt_database_init(), abandoning the half-open database it had just been handed
1514 // -- its two filename strings and, when only one of the two lock files had been
1515 // taken, that lock file too. dt_database_open() refuses to open over an open
1516 // connection, so the leak is now a compile-time-visible step instead.
1518 continue;
1519 }
1520 }
1521 recheck_needed = FALSE;
1522 }
1523
1524 dt_free(configured_library);
1525
1526 //db maintenance on startup (if configured to do so)
1528 {
1530 }
1531
1532 // init darktable tags table
1534
1535 // The signal system exists to tell GUI widgets about backend events -- every raise is
1536 // already dead in a GUI-less process (dt_control_signal_raise() bails when the control
1537 // system is not running, and only the GUI starts it), so only the GUI gets the machinery.
1538 // The connect/raise surface treats a NULL system as "not in this process" and no-ops.
1539 darktable.signals = init_gui ? dt_control_signal_init() : NULL;
1540
1541 /* src/metadata reports that the tag vocabulary changed; turning that into the GTK signal
1542 * its consumers already listen for is ours. Installed HERE, not with the other handlers
1543 * further up: the signal system does not exist until the line above, and nothing can
1544 * edit a tag before it does. */
1550 // Same reason for these two: they raise signals, so they wait for the signal system.
1553 // Critical: ensure image cache gets refreshed BEFORE any other IMAGE_INFO_CHANGED handlers.
1554 // This handler reloads dt_image_t from DB so all downstream callbacks see fresh metadata.
1556
1557 // Make sure that the database and xmp files are in sync
1558 // We need conf and db to be up and running for that which is the case here.
1559 // FIXME: is this also useful in non-gui mode?
1560 GList *changed_xmp_files = NULL;
1561 if(init_gui && dt_conf_get_bool("run_crawler_on_start"))
1562 {
1563 changed_xmp_files = dt_control_crawler_run();
1564 }
1565
1566 if(init_gui)
1567 {
1569 }
1570 else
1571 {
1572 if(dbfilename_from_command && !strcmp(dbfilename_from_command, ":memory:"))
1573 dt_gui_presets_init(); // init preset db schema.
1577 }
1578
1579 // we initialize grouping early because it's needed for collection init
1580 // idem for folder reachability
1581 if(init_gui)
1582 {
1583 darktable.gui = (dt_gui_gtk_t *)calloc(1, sizeof(dt_gui_gtk_t));
1584 memset(darktable.gui->scroll_to, 0, sizeof(darktable.gui->scroll_to));
1586 }
1587
1588 // The collection and selection are lighttable state: dt_gui_gtk_init() creates them.
1589 // A GUI-less process (ansel-cli) runs without either -- their modules' public entry
1590 // points treat "not created" as a no-op, so shared code needs no guards.
1591
1592 /* capabilities set to NULL */
1593 darktable.capabilities = NULL;
1594
1595
1596 // Re-assert our handlers once the third-party libraries above are up. This used to compensate
1597 // for GraphicsMagick's InitializeMagick(), which stole all of them; that library is gone, but
1598 // the call is cheap and idempotent (system_signal_handling.c counts its invocations), and it
1599 // keeps the guarantee that whatever init ran before this point cannot leave us without a
1600 // SIGSEGV handler. Crash reporting is initialized after it, deliberately.
1602
1603#ifdef _OPENMP
1604 // Re-assert our thread count last, after every library above has initialised.
1605 //
1606 // omp_set_num_threads() writes only the CALLING thread's ICV, and a library that sizes its own
1607 // pool from omp_get_num_procs() publishes that by calling it -- a process-wide side effect on a
1608 // library-local decision. GraphicsMagick's InitializeMagick() did exactly that from here, which
1609 // silently overrode `-t N` and the "CPU cores" preference for every parallel region entered from
1610 // this thread afterwards: invisible in the GUI, where pixel work runs on control worker threads
1611 // that set their own count in dt_control_work(), and total in ansel-cli, where the export
1612 // pipeline runs on this very thread.
1613 //
1614 // Both of the libraries known to have done it -- GraphicsMagick and G'MIC -- have since been
1615 // removed, so nothing in the current dependency set is known to clobber the count. This stays
1616 // anyway, and deliberately unconditional: it costs one call at startup, the failure mode is
1617 // silent, and it took an LD_PRELOAD shim to find the last one. Keep it after every library init.
1618 omp_set_num_threads(darktable.num_openmp_threads);
1619#endif
1620
1621 // noiseprofiles.json is parsed lazily by common/noiseprofiles.c on first lookup;
1622 // only the --noiseprofiles override needs to reach it now.
1623 if(noiseprofiles_from_command) dt_noiseprofile_set_path(noiseprofiles_from_command);
1624
1625 // The GUI must be initialized before the views, because the init()
1626 // functions of the views depend on darktable.control->accels_* to register
1627 // their keyboard accelerators
1628
1629 // TODO : Make a single call to unified GUI API initializing everything graphical at once.
1630 // The current tangled mess is a nightmare to maintain.
1631
1632 if(init_gui)
1633 {
1635 {
1636 fprintf(stderr, "ERROR: can't init gui, aborting.\n");
1638 return 1;
1639 }
1641 }
1642 else
1643 darktable.gui = NULL;
1644
1645 // This needs to run after gui init because we init cache lines size with window size
1646 // but before image cache init and pipeline cache init (aka dev init aka darkroom init aka viewmanager init)
1647 // because we init its size here
1649
1652
1653 // check whether we were able to load darkroom view. if we failed, we'll crash everywhere later on.
1655 {
1656 fprintf(stderr, "ERROR: can't init develop system, aborting.\n");
1658 return 1;
1659 }
1660
1661 // The arena is only a virtual-memory reservation (physical pages get committed on
1662 // use), so init only fails on exhausted address space or a pathological requested
1663 // size. Rather than aborting outright, retry smaller: a shrunken cache degrades
1664 // performance, an abort loses the session.
1665 size_t pipecache_size = darktable.dtresources.pixelpipe_memory;
1666 dt_dev_pixelpipe_cache_init(pipecache_size,
1669 while(!dt_dev_pixelpipe_cache_is_ready() && pipecache_size / 2 >= (size_t)512 * 1024 * 1024)
1670 {
1671 pipecache_size /= 2;
1672 fprintf(stderr,
1673 "WARNING: can't reserve %" G_GSIZE_FORMAT " MiB of virtual memory for the pixelpipe cache, "
1674 "retrying with %" G_GSIZE_FORMAT " MiB. Check your memory settings.\n",
1675 2 * pipecache_size / (1024 * 1024), pipecache_size / (1024 * 1024));
1676 dt_dev_pixelpipe_cache_init(pipecache_size,
1679 }
1680 darktable.dtresources.pixelpipe_memory = pipecache_size;
1681
1682 /* The cache announces three things -- it is full, a cacheline became readable, and the
1683 * supervisor's bookkeeping -- and used to do it by calling dt_control_log(), raising
1684 * DT_SIGNAL_CACHELINE_READY and calling dt_supervisor_*() itself. That put control/ and
1685 * develop/ inside a module that is otherwise pure storage. The orchestrator wires them
1686 * here instead: the cache says what happened, the application decides who hears it. */
1690 {
1691 fprintf(stderr, "ERROR: can't init pixelpipe cache, aborting.\n");
1693 return 1;
1694 }
1695
1696 // High-level event supervisor registry (active only under -d supervisor).
1698
1699 darktable.points = (dt_points_t *)calloc(1, sizeof(dt_points_t));
1701
1702 // must come before mipmap_cache, because that one will need to access
1703 // image dimensions stored in here:
1705
1707 dt_mipmap_cache_init(&mipmap_settings, (dt_get_debug_flags() & DT_DEBUG_CACHE) != 0);
1708
1709 /* Re-tell the cache whenever the user changes one of its four settings. */
1711 G_CALLBACK(_preferences_changed), NULL);
1712
1715 G_CALLBACK(_xmp_mode_preferences_changed), NULL);
1716
1717#ifdef HAVE_OPENCL
1718 dt_opencl_init(exclude_opencl, print_statistics);
1719 // Show the splash only while compiling OpenCL kernels (triggered from opencl.c),
1720 // then close it immediately so the rest of the startup stays splash-free.
1722#endif
1723
1724 darktable.imageio = (dt_imageio_t *)calloc(1, sizeof(dt_imageio_t));
1726
1727 // load default iop order
1729 // load iop order rules
1731 // load the darkroom mode plugins once:
1733 // check if all modules have a iop order assigned
1735 {
1736 fprintf(stderr, "ERROR: iop order looks bad, aborting.\n");
1738 return 1;
1739 }
1740
1741 // set up memory.darktable_iop_names table
1743
1744 // set up the list of exiv2 metadata
1746
1747 // init metadata flags
1749
1750 if(init_gui)
1751 {
1752 darktable.lib = (dt_lib_t *)calloc(1, sizeof(dt_lib_t));
1754
1755 // prevent bauhaus widgets from sending value-changed signals
1756 // because some of them expect user interactions.
1758
1759 // init the gui part of views
1761
1763
1764 // initialize undo struct
1766
1767 // Global menu inherits many parts of the GUI,
1768 // so it should be inited last
1770 }
1771
1773 {
1774 fprintf(stderr, "[memory] after successful startup\n");
1776 }
1777
1778 if(init_gui)
1779 {
1780 // we have to call dt_ctl_switch_mode_to() here already to not run into a lua deadlock.
1781 // having another call later is ok
1782 dt_ctl_switch_mode_to("lighttable");
1783
1784#ifndef MAC_INTEGRATION
1785 // load image(s) specified on cmdline.
1786 // this has to happen after lua is initialized as image import can run lua code
1787 if (argc == 2)
1788 {
1789 // If only one image is listed, attempt to load it in darkroom
1790 (void)dt_load_from_string(argv[1], TRUE, NULL);
1791 }
1792 else if (argc > 2)
1793 {
1794 // when multiple names are given, fire up a background job to import them
1796 }
1797#endif
1798 }
1799
1800 // last but not least construct the popup that asks the user about images whose xmp files are newer than the
1801 // db entry
1802 if(init_gui && changed_xmp_files)
1803 {
1804 dt_control_crawler_show_image_list(changed_xmp_files);
1805 }
1806
1807 if(init_gui)
1808 {
1809 // The user config is already loaded from gui/application.c, right after dt_accels_init()
1810 // and before any widget/menu is built -- loading it again here would re-read the
1811 // still-on-disk (unsaved) file and clobber any normalization dt_accels_connect_accels()
1812 // already applied to the live GtkAccelMap in the meantime (e.g. an old Ctrl-flavored
1813 // save recognized as today's platform-native default and resynced accordingly).
1815 //gtk_window_add_accel_group(GTK_WINDOW(dt_ui_main_window(darktable.gui->ui)), darktable.gui->accels->global_accels);
1816
1817 // Studio capture folder survey: restore the persisted comparison state and,
1818 // once the main loop runs and the window is mapped, propose to resume a
1819 // session that was monitoring when the application was last closed.
1822 g_idle_add((GSourceFunc)dt_folder_survey_propose_resume, NULL);
1823 }
1824
1826
1827 // On first launch, ask once for consent to the opt-in data flows (crash reports
1828 // and usage analytics) in a single dialog, before initializing either module so
1829 // their enabled flags are set when they read them.
1830 dt_privacy_ask_consent(init_gui);
1831
1832 // Initialize crash reporting last, after the final dt_set_signal_handlers() so
1833 // sentry's handler sits on top and chains down into our gdb/drmingw fallback.
1834 dt_sentry_init(init_gui);
1835
1836#ifdef HAVE_OPENCL
1837 /* Connect the crash reporter to the OpenCL module, which is the only place that knows
1838 * whether a crash was its driver's doing. Wired here rather than inside either one so
1839 * neither has to include the other: sentry supplies backtraces without knowing what a GPU
1840 * is, and opencl judges them without knowing that sentry exists.
1841 *
1842 * Guarded because opencl.h declares nothing without HAVE_OPENCL -- a build with OpenCL
1843 * compiled out has no such function to point at, and no GPU driver to blame either. */
1845#endif
1846
1847 // Opt-in usage analytics (PostHog) - separate toggle from crash reporting.
1848 dt_telemetry_init(init_gui);
1849
1850 // Nightly builds: once a day, ask ansel.photos/nightly.json whether a newer build
1851 // exists for this format. Its own toggle (updates/enabled), no telemetry involved.
1852 // The toast is ours to post: the module lives in common/ and does not know control/.
1854
1855 dt_print(DT_DEBUG_CONTROL, "[init] startup took %f seconds\n", dt_get_wtime() - start_wtime);
1856
1857 return 0;
1858}
1859
1860static void _dt_drain_main_context(const int max_iters)
1861{
1862 if(max_iters <= 0) return;
1863 GMainContext *ctx = g_main_context_default();
1864 for(int i = 0; i < max_iters && g_main_context_pending(ctx); i++)
1865 g_main_context_iteration(ctx, FALSE);
1866}
1867
1869{
1870 const int init_gui = (!IS_NULL_PTR(darktable.gui));
1871
1872 // Flush crash reporting and mark this session as a clean exit. Done early so
1873 // events are sent while the rest of the app is still up; the clean-session
1874 // counter it writes is persisted later by dt_conf_cleanup().
1876
1877 // Stop the update check first: it is the one that may still post to the GUI thread.
1879
1880 // Flush and stop usage analytics.
1882
1883 // Restore selection if exiting on culling mode to be sure it's saved in DB
1886
1887 // Restore auto-computed zoom level to user-defined
1888 dt_conf_set_int("plugins/lighttable/images_in_row", dt_conf_get_int("plugins/lighttable/images_in_row_backup"));
1889
1890 // last chance to ask user for any input...
1891
1892 const gboolean perform_maintenance = dt_database_maybe_maintenance(TRUE);
1893 const gboolean perform_snapshot = dt_database_maybe_snapshot();
1894 gchar **snaps_to_remove = NULL;
1895 if(perform_snapshot)
1896 {
1897 snaps_to_remove = dt_database_snaps_to_remove();
1898 }
1899
1900#ifdef HAVE_PRINT
1902#endif
1903
1904 // anything that asks user for input should be placed before this line
1905
1906 if(init_gui)
1907 {
1910
1911 if(darktable.gui->surface)
1912 {
1913 cairo_surface_destroy(darktable.gui->surface);
1914 darktable.gui->surface = NULL;
1915 }
1916
1917 // hide main window and do rest of the cleanup in the background
1918 gtk_widget_hide(dt_ui_main_window(darktable.gui->ui));
1919
1921 //dt_dbus_destroy(darktable.dbus);
1922
1923 // Stop control workers before unloading views and libs. They can still be
1924 // processing lighttable-side jobs while shutdown is tearing down modules.
1928
1930
1933 }
1934
1935 dt_dev_pixelpipe_cache_wait_dump_pending("app-cleanup-before-view-manager");
1938
1939 if(init_gui)
1940 {
1943
1945
1948
1949 /* Force GTK to teardown the toplevel widget tree now, while the main
1950 * context still exists. This helps release style/cairo resources that
1951 * would otherwise stay alive until process exit. */
1952 GtkWidget *main_window = dt_ui_main_window(darktable.gui->ui);
1953 if(GTK_IS_WIDGET(main_window))
1954 gtk_widget_destroy(main_window);
1955
1956 dt_gui_gtk_t *gui = darktable.gui;
1957 darktable.gui = NULL;
1959 dt_free(gui->ui);
1960 dt_free(gui);
1961 }
1962
1969
1970 dt_collection_cleanup_global(); // no-ops in a GUI-less process: never created there
1972
1973 // Mipmap cleanup may still consult the image cache for paths.
1976
1978 dt_conf_set_int("processing/gui_throttle_runtime_us", dt_gui_throttle_get_runtime_us());
1980 // Needs conf alive: a clean exit with OpenCL running is what clears the driver-crash streak.
1987 g_list_free_full(darktable.iop_order_list, dt_free_gpointer);
1989 g_list_free_full(darktable.iop_order_rules, dt_free_gpointer);
1991
1992#ifdef HAVE_OPENCL
1994 {
1995 for(int i = 0; i < dt_opencl_get_num_devices(); i++)
1997 }
1998#endif
1999
2002
2004
2005 dt_guides_cleanup(); // module-private list: a no-op when the GUI never registered any
2006
2007 if(perform_maintenance)
2008 {
2011 }
2012
2014 if(perform_snapshot)
2015 {
2016 if(dt_database_snapshot() && snaps_to_remove)
2017 {
2018 int i = 0;
2019 while(snaps_to_remove[i])
2020 {
2021 // make file to remove writable, mostly problem on windows.
2022 g_chmod(snaps_to_remove[i], S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
2023
2024 dt_print(DT_DEBUG_SQL, "[db backup] removing old snap: %s... ", snaps_to_remove[i]);
2025 const int retunlink = g_remove(snaps_to_remove[i++]);
2026 dt_print(DT_DEBUG_SQL, "%s\n", retunlink == 0 ? "success" : "failed!");
2027 }
2028 }
2029 }
2030 if(snaps_to_remove)
2031 {
2032 g_strfreev(snaps_to_remove);
2033 }
2035
2036 if(init_gui)
2037 {
2039 }
2040
2042
2043 if(init_gui)
2044 {
2047 }
2048 else
2049 {
2052 }
2054
2056 darktable.signals = NULL;
2057
2059
2062
2064
2065 /* Stop GLib pooled workers first, then release the current thread default
2066 * PangoCairo font map before finalizing Fontconfig caches. */
2067 if(init_gui)
2068 {
2069 g_thread_pool_stop_unused_threads();
2070#if !defined(_WIN32) && !defined(__APPLE__)
2071 PangoFontMap *fontmap = pango_cairo_font_map_get_default();
2072 gboolean use_fontconfig_backend = FALSE;
2073
2074 if(fontmap && PANGO_IS_CAIRO_FONT_MAP(fontmap))
2075 {
2076 const cairo_font_type_t font_backend
2077 = pango_cairo_font_map_get_font_type(PANGO_CAIRO_FONT_MAP(fontmap));
2078 use_fontconfig_backend = (font_backend == CAIRO_FONT_TYPE_FT);
2079 }
2080
2081 if(use_fontconfig_backend && fontmap && g_type_is_a(G_OBJECT_TYPE(fontmap), pango_fc_font_map_get_type()))
2082 pango_fc_font_map_shutdown((PangoFcFontMap *)fontmap);
2083 if(use_fontconfig_backend) FcFini();
2084#endif
2085 pango_cairo_font_map_set_default(NULL);
2086 }
2087}
2088
2090{
2091 return darktable.start_wtime;
2092}
2093
2095{
2096 return darktable.unmuted;
2097}
2098
2100{
2102}
2103
2104gboolean dt_get_signal_debug(const int signal)
2105{
2106 return darktable.unmuted_signal_dbg[signal];
2107}
2108
2109void dt_print(dt_debug_thread_t thread, const char *msg, ...)
2110{
2112 {
2113 printf("%f ", dt_get_wtime() - darktable.start_wtime);
2114 va_list ap;
2115 va_start(ap, msg);
2116 g_vprintf(msg, ap);
2117 va_end(ap);
2118 fflush(stdout);
2119 }
2120}
2121
2122void dt_print_nts(dt_debug_thread_t thread, const char *msg, ...)
2123{
2125 {
2126 va_list ap;
2127 va_start(ap, msg);
2128 g_vprintf(msg, ap);
2129 va_end(ap);
2130 fflush(stdout);
2131 }
2132}
2133
2134void dt_vprint(dt_debug_thread_t thread, const char *msg, ...)
2135{
2137 {
2138 printf("%f ", dt_get_wtime() - darktable.start_wtime);
2139 va_list ap;
2140 va_start(ap, msg);
2141 g_vprintf(msg, ap);
2142 va_end(ap);
2143 fflush(stdout);
2144 }
2145}
2146
2147void dt_show_times(const dt_times_t *start, const char *prefix)
2148{
2149 /* Skip all the calculations an everything if -d perf isn't on */
2151 {
2152 dt_times_t end;
2153 dt_get_times(&end);
2154 char buf[140]; /* Arbitrary size, should be lots big enough for everything used in DT */
2155 snprintf(buf, sizeof(buf), "%s took %.3f secs (%.3f CPU)", prefix, end.clock - start->clock,
2156 end.user - start->user);
2157 dt_print(DT_DEBUG_PERF, "%s\n", buf);
2158 }
2159}
2160
2161void dt_show_times_f(const dt_times_t *start, const char *prefix, const char *suffix, ...)
2162{
2163 /* Skip all the calculations an everything if -d perf isn't on */
2165 {
2166 dt_times_t end;
2167 dt_get_times(&end);
2168 char buf[160]; /* Arbitrary size, should be lots big enough for everything used in DT */
2169 const int n = snprintf(buf, sizeof(buf), "%s took %.3f secs (%.3f CPU) ", prefix, end.clock - start->clock,
2170 end.user - start->user);
2171 if(n < sizeof(buf) - 1)
2172 {
2173 va_list ap;
2174 va_start(ap, suffix);
2175 vsnprintf(buf + n, sizeof(buf) - n, suffix, ap);
2176 va_end(ap);
2177 }
2178 dt_print(DT_DEBUG_PERF, "%s\n", buf);
2179 }
2180}
2181
2182#if defined(_WIN32)
2183#include <windows.h>
2184
2186{
2187 MEMORYSTATUSEX status;
2188 status.dwLength = sizeof(status);
2189 if(GlobalMemoryStatusEx(&status))
2190 return (size_t)status.ullAvailPhys; // Includes reclaimable
2191 else
2192 return 0;
2193}
2194
2195#elif defined(__APPLE__)
2196#include <mach/mach.h>
2197
2198static size_t _probe_system_available_mem(void)
2199{
2200 mach_port_t host = mach_host_self();
2201 vm_statistics64_data_t vmstat;
2202 mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
2203 if(host_statistics64(host, HOST_VM_INFO64, (host_info64_t)&vmstat, &count) != KERN_SUCCESS) return 0;
2204
2205 size_t page_size;
2206 host_page_size(host, &page_size);
2207
2208 // Free + inactive (reclaimable)
2209 return (vmstat.free_count + vmstat.inactive_count) * page_size;
2210}
2211
2212#elif defined(__linux__)
2213#include <string.h>
2214
2215// A cgroup v2 memory.max limit (container, Flatpak sandbox, systemd slice) caps us
2216// before the system-wide MemAvailable does: the kernel enforces it with a per-cgroup
2217// OOM kill while /proc/meminfo still reports plenty of available RAM. Walk our own
2218// cgroup path up to the root and report the tightest limit (out_limit) and the
2219// tightest remaining slack including reclaimable pages (out_available), each
2220// SIZE_MAX when no level sets a limit.
2221static void _probe_cgroup_v2(size_t *out_limit, size_t *out_available)
2222{
2223 size_t tightest = SIZE_MAX;
2224 size_t tightest_limit = SIZE_MAX;
2225 *out_limit = SIZE_MAX;
2226 *out_available = SIZE_MAX;
2227
2228 FILE *f = g_fopen("/proc/self/cgroup", "r");
2229 if(IS_NULL_PTR(f)) return;
2230
2231 char line[512];
2232 char path[512] = "";
2233 while(fgets(line, sizeof(line), f))
2234 {
2235 // cgroup v2 unified hierarchy entry: "0::/user.slice/..."
2236 if(!strncmp(line, "0::", 3))
2237 {
2238 g_strlcpy(path, line + 3, sizeof(path));
2239 char *newline = strchr(path, '\n');
2240 if(newline) *newline = '\0';
2241 break;
2242 }
2243 }
2244 fclose(f);
2245 if(path[0] == '\0') return;
2246
2247 while(TRUE)
2248 {
2249 char file[1024];
2250 snprintf(file, sizeof(file), "/sys/fs/cgroup%s/memory.max", path);
2251 FILE *fmax = g_fopen(file, "r");
2252 if(fmax)
2253 {
2254 // The file contains either a byte count or the literal "max" (no limit),
2255 // which simply fails the numeric scan.
2256 unsigned long long max_bytes = 0;
2257 if(fscanf(fmax, "%llu", &max_bytes) == 1 && max_bytes > 0)
2258 {
2259 unsigned long long cur_bytes = max_bytes;
2260 snprintf(file, sizeof(file), "/sys/fs/cgroup%s/memory.current", path);
2261 FILE *fcur = g_fopen(file, "r");
2262 if(fcur)
2263 {
2264 if(fscanf(fcur, "%llu", &cur_bytes) != 1) cur_bytes = max_bytes;
2265 fclose(fcur);
2266 }
2267
2268 // memory.current still charges pages the kernel could drop at will: the page
2269 // cache and — critically for us — our own MADV_FREE'd arena pages, which land
2270 // on the cgroup's inactive file LRU. Count that list as available, the same
2271 // way system-wide MemAvailable does, or the slack of a busy cgroup would read
2272 // ~0 even though our own freed cache is fully reclaimable.
2273 unsigned long long inactive_file = 0;
2274 snprintf(file, sizeof(file), "/sys/fs/cgroup%s/memory.stat", path);
2275 FILE *fstat = g_fopen(file, "r");
2276 if(fstat)
2277 {
2278 char stat_line[256];
2279 while(fgets(stat_line, sizeof(stat_line), fstat))
2280 if(sscanf(stat_line, "inactive_file %llu", &inactive_file) == 1) break;
2281 fclose(fstat);
2282 }
2283
2284 const size_t slack = (max_bytes > cur_bytes) ? (size_t)(max_bytes - cur_bytes) : 0;
2285 const size_t available = slack + (size_t)inactive_file;
2286 if(available < tightest) tightest = available;
2287 if((size_t)max_bytes < tightest_limit) tightest_limit = (size_t)max_bytes;
2288 }
2289 fclose(fmax);
2290 }
2291
2292 char *slash = strrchr(path, '/');
2293 if(IS_NULL_PTR(slash) || slash == path) break;
2294 *slash = '\0';
2295 }
2296
2297 *out_limit = tightest_limit;
2298 *out_available = tightest;
2299}
2300
2301static size_t _probe_system_available_mem(void)
2302{
2303 FILE *f = g_fopen("/proc/meminfo", "r");
2304 if(IS_NULL_PTR(f)) return 0;
2305
2306 char line[256];
2307 size_t available_kb = 0;
2308 size_t available = 0;
2309
2310 while(fgets(line, sizeof(line), f))
2311 {
2312 if(sscanf(line, "MemAvailable: %" G_GSIZE_FORMAT " kB", &available_kb) == 1)
2313 {
2314 available = available_kb * 1024; // kB to bytes
2315 break;
2316 }
2317 }
2318 fclose(f);
2319
2320 size_t cgroup_limit = SIZE_MAX;
2321 size_t cgroup_available = SIZE_MAX;
2322 _probe_cgroup_v2(&cgroup_limit, &cgroup_available);
2323 if(cgroup_available != SIZE_MAX) available = MIN(available, cgroup_available);
2324
2325 return available;
2326}
2327
2328#else
2329static size_t _probe_system_available_mem(void)
2330{
2331 return 0; // Unsupported platform: 0 = "no information", not "out of memory"
2332}
2333#endif
2334
2335/* Short-lived cache of the system probe. Measured at 61 µs per probe (16 µs for
2336 * /proc/meminfo, 45 µs walking the cgroup tree), which the tiling planners alone
2337 * would pay ~30 times per pipeline run — 1.8 ms of a 16 ms realtime frame. The
2338 * cached value is at most DT_SYS_MEM_PROBE_PERIOD_US old; callers that just changed
2339 * the situation themselves (the pixelpipe pressure valve, right after shedding
2340 * cache) call dt_invalidate_system_available_mem() to force the next read to be
2341 * ground truth. */
2342#define DT_SYS_MEM_PROBE_PERIOD_US 50000 // 50 ms
2343
2345static size_t _sys_mem_probe_value = 0;
2346static gint64 _sys_mem_probe_time_us = 0;
2347
2349{
2350 g_mutex_lock(&_sys_mem_probe_lock);
2351
2352 const gint64 now = g_get_monotonic_time();
2354 {
2355 const size_t cached = _sys_mem_probe_value;
2356 g_mutex_unlock(&_sys_mem_probe_lock);
2357 return cached;
2358 }
2359
2360 const size_t available = _probe_system_available_mem();
2361 _sys_mem_probe_value = available;
2363 g_mutex_unlock(&_sys_mem_probe_lock);
2364 return available;
2365}
2366
2368{
2369 g_mutex_lock(&_sys_mem_probe_lock);
2371 g_mutex_unlock(&_sys_mem_probe_lock);
2372}
2373
2374// Tightest container/cgroup memory limit this process runs under, SIZE_MAX when
2375// uncontained. This is the envelope the kernel actually OOM-enforces on us,
2376// regardless of how much RAM the machine has.
2377static size_t _get_container_mem_limit(void)
2378{
2379#if defined(__linux__)
2380 size_t cgroup_limit = SIZE_MAX;
2381 size_t cgroup_available = SIZE_MAX;
2382 _probe_cgroup_v2(&cgroup_limit, &cgroup_available);
2383 return cgroup_limit;
2384#else
2385 return SIZE_MAX;
2386#endif
2387}
2388
2389
2391{
2392 return dt_conf_get_int("worker_threads");
2393}
2394
2396{
2397 size_t cache_used = 0;
2398 size_t cache_max = 0;
2399 dt_dev_pixelpipe_cache_get_usage(&cache_used, &cache_max);
2400 const size_t budget_left = cache_max - cache_used;
2401
2402 // The budget is only a startup-time plan: cap it by what the system can actually
2403 // back right now without dropping under the pressure floor (issue #1083), so
2404 // tiled modules plan tile sizes that will survive the allocation-time pressure
2405 // valve in pixelpipe_cache.c. Half of our own current cache usage counts as
2406 // room too: it is LRU-evictable, and the valve will evict it on demand — our own
2407 // cache must never be what forces a module into tiling.
2408 const size_t sys_available = dt_get_system_available_mem();
2409 if(sys_available == 0) return budget_left; // no information on this platform
2410
2411 const size_t pressure_floor = dt_get_memory_pressure_floor();
2412 const size_t sys_room = ((sys_available > pressure_floor) ? sys_available - pressure_floor : 0)
2413 + cache_used / 2;
2414 return MIN(budget_left, sys_room);
2415}
2416
2418{
2420}
2421
2423{
2425}
2426
2431
2432void dt_configure_runtime_performance(dt_sys_resources_t *resources, gboolean init_gui)
2433{
2434 size_t physical_memory = _get_total_memory() * 1000;
2435
2436 // A container/cgroup memory limit (Flatpak sandbox, systemd slice, docker...) is
2437 // the envelope the kernel actually OOM-enforces on us: inside it, the machine's
2438 // physical RAM is irrelevant, so it IS our total memory for budgeting purposes.
2439 const size_t container_limit = _get_container_mem_limit();
2440 if(container_limit != SIZE_MAX && (physical_memory == 0 || container_limit < physical_memory))
2441 {
2443 "[MEMORY CONFIGURATION] container/cgroup memory limit detected: %" G_GSIZE_FORMAT
2444 " MiB — using it as the total RAM\n", container_limit / (1024 * 1024));
2445 physical_memory = container_limit;
2446 }
2447
2448 resources->total_memory = physical_memory;
2449
2450 const size_t threads = darktable.num_openmp_threads;
2451 const size_t mem = resources->total_memory / (1024 * 1024);
2452 const size_t bits = CHAR_BIT * sizeof(void *);
2453 const gboolean sufficient = (mem >= 4096 && threads >= 2);
2454
2455 dt_print(DT_DEBUG_MEMORY, "[MEMORY CONFIGURATION] found a %s %" G_GSIZE_FORMAT "-bit system with %" G_GSIZE_FORMAT " cores\n",
2456 (sufficient) ? "sufficient" : "low performance", bits, threads);
2457
2458 // Override RAM detection with user config
2459 if(dt_conf_get_int64("host_memory_limit") > 0)
2460 resources->total_memory = dt_conf_get_int64("host_memory_limit") * 1024 * 1024;
2461
2462 // A host_memory_limit above the physical RAM would make us plan caches the system
2463 // can never back: the OS OOM-killer, not us, would then enforce the difference by
2464 // killing the app without a message (issue #1083). The user limit can only shrink
2465 // the detected RAM, never grow it.
2466 if(physical_memory > 0 && resources->total_memory > physical_memory)
2467 {
2468 fprintf(stderr,
2469 "MEMORY WARNING: host_memory_limit (%" G_GSIZE_FORMAT " MiB) exceeds the physical RAM "
2470 "(%" G_GSIZE_FORMAT " MiB) and was clamped to it.\n",
2471 resources->total_memory / (1024 * 1024), physical_memory / (1024 * 1024));
2472 resources->total_memory = physical_memory;
2473 }
2474
2475 // Keep OS headroom between 1 GB and a third of the system RAM
2476 resources->headroom_memory = dt_conf_get_int64("memory_os_headroom") * 1024 * 1024;
2477 resources->headroom_memory
2478 = CLAMP(resources->headroom_memory, 1024 * 1024 * 1024, resources->total_memory / 3);
2479
2480 // Runtime memory-pressure floor: while running, whenever the SYSTEM-wide available
2481 // RAM drops below this — whether we or another application consumed it — the
2482 // pixelpipe cache sheds entries and returns their pages to the OS instead of
2483 // letting the system OOM-killer pick a victim (issue #1083). This is a live
2484 // safety net on top of the static budgets below, which are only plans.
2485 // Conf default 0 = auto: half the OS headroom.
2486 // The bounds scale with the envelope: on a normal machine the floor stays within
2487 // [512 MB, total/4], but inside a small container keeping 512 MB free would eat
2488 // the whole allotment, so the lower bound relaxes to total/8 there.
2489 // An ABSOLUTE reserve, not a fraction of anything. What the kernel and other
2490 // applications need in order to keep breathing does not scale with how much RAM the
2491 // machine has: 200 MiB is about as useful on a 4 GB laptop as on a 128 GB workstation.
2492 //
2493 // Deriving it from the headroom (previously half of it) made the floor grow with the
2494 // machine, which is backwards -- a 31 GB system ended up reserving 5175 MiB, so once
2495 // free RAM dipped under that the pixelpipe cache refused EVERY allocation, including
2496 // ones of a few kilobytes, and the application could not even start. Reserving a large
2497 // share of a large machine also wastes precisely the memory the user bought it for.
2498 int64_t pressure_floor = dt_conf_get_int64("memory_pressure_floor") * 1024 * 1024;
2499 if(pressure_floor <= 0) pressure_floor = DT_MEMORY_PRESSURE_FLOOR_DEFAULT;
2500 // Only a sanity clamp for hand-set values: never negative, and never so large on a
2501 // small machine that the floor swallows the whole envelope.
2502 resources->pressure_floor_memory = CLAMP(pressure_floor, 0, (int64_t)resources->total_memory / 4);
2503
2504 // Keep mipmap cache between 256 MB and a sixth of the system RAM
2505 resources->mipmap_memory = dt_conf_get_int64("memory_mipmap_cache") * 1024 * 1024;
2506 resources->mipmap_memory
2507 = CLAMP(resources->mipmap_memory, 256 * 1024 * 1024, resources->total_memory / 6);
2508
2509 // 6 temp copies of 24 Mpx RGBA float32 at full res
2510 const size_t min_pipecache_memory = 6 * 6000 * 4000 * 4 * sizeof(float);
2511
2512 // Pipeline cache gets the rest. Need to cast as int otherwise, negative values saturate the uint64 to MAX_UINT or something
2513 resources->pixelpipe_memory = MAX((int64_t)resources->total_memory
2514 - (int64_t)resources->mipmap_memory
2515 - (int64_t)resources->headroom_memory,
2516 (int64_t)min_pipecache_memory);
2517
2518 if(resources->pixelpipe_memory == min_pipecache_memory)
2519 {
2520 fprintf(stderr,
2521 "MEMORY WARNING: your pixelpipe cache allocated RAM is too small for your typical raw size.\n"
2522 "MEMORY WARNING: reduce your OS/apps headroom, or your thumbnail cache size.\n"
2523 "MEMORY WARNING: you may also simply need more RAM or need to reset the config key host_memory.\n"
2524 "MEMORY WARNING: we shrank the thumbnails cache to the bare minimum to leave enough space for pixelpipe cache.\n");
2525 resources->mipmap_memory = MAX((int64_t)resources->total_memory
2526 - (int64_t)resources->headroom_memory
2527 - (int64_t)resources->pixelpipe_memory,
2528 (int64_t)128 * 1024 * 1024);
2529 }
2530
2531 // Print
2532 dt_print(DT_DEBUG_MEMORY | DT_DEBUG_CACHE, _("[MEMORY CONFIGURATION] Total system RAM: %" G_GSIZE_FORMAT " MiB\n"),
2533 resources->total_memory / (1024 * 1024));
2534
2535 dt_print(DT_DEBUG_MEMORY | DT_DEBUG_CACHE, _("[MEMORY CONFIGURATION] OS & Apps RAM headroom: %" G_GSIZE_FORMAT " MiB\n"),
2536 resources->headroom_memory / (1024 * 1024));
2537
2538 dt_print(DT_DEBUG_MEMORY | DT_DEBUG_CACHE, _("[MEMORY CONFIGURATION] Lightable thumbnails cache size: %" G_GSIZE_FORMAT " MiB\n"),
2539 resources->mipmap_memory / (1024 * 1024));
2540
2541 dt_print(DT_DEBUG_MEMORY | DT_DEBUG_CACHE, _("[MEMORY CONFIGURATION] Pixelpipe cache size: %" G_GSIZE_FORMAT " MiB\n"),
2542 resources->pixelpipe_memory / (1024 * 1024));
2543
2544 dt_print(DT_DEBUG_MEMORY | DT_DEBUG_CACHE, _("[MEMORY CONFIGURATION] System memory pressure floor: %" G_GSIZE_FORMAT " MiB\n"),
2545 resources->pressure_floor_memory / (1024 * 1024));
2546
2547 dt_print(DT_DEBUG_MEMORY | DT_DEBUG_CACHE, _("[MEMORY CONFIGURATION] Worker threads: %i\n"), dt_worker_threads());
2548
2549 if(resources->total_memory < resources->headroom_memory + resources->mipmap_memory + resources->pixelpipe_memory)
2550 dt_control_log(_("CRITICAL WARNING: Ansel will not be able to use the RAM you allocated it.\n"
2551 "Review your memory settings or add more RAM to your system."));
2552}
2553
2554int dt_capabilities_check(char *capability)
2555{
2556 for(GList *capabilities = darktable.capabilities; capabilities; capabilities = g_list_next(capabilities))
2557 {
2558 if(!strcmp(capabilities->data, capability))
2559 {
2560 return TRUE;
2561 }
2562 }
2563 return FALSE;
2564}
2565
2566
2567void dt_capabilities_add(char *capability)
2568{
2570
2571 if(!dt_capabilities_check(capability))
2572 darktable.capabilities = g_list_append(darktable.capabilities, capability);
2573
2575}
2576
2577
2586
2587
2593
2594
2596{
2597 fprintf(stdout, "[memory] Currently-free and reclaimable memory detected: %lu MiB\n", dt_get_system_available_mem() / (1024 * 1024));
2598
2599#if defined(__linux__)
2600 char *line = NULL;
2601 size_t len = 128;
2602 char vmsize[64];
2603 char vmpeak[64];
2604 char vmrss[64];
2605 char vmhwm[64];
2606 FILE *f;
2607
2608 char pidstatus[128];
2609 snprintf(pidstatus, sizeof(pidstatus), "/proc/%u/status", (uint32_t)getpid());
2610
2611 f = g_fopen(pidstatus, "r");
2612 if(IS_NULL_PTR(f)) return;
2613
2614 /* read memory size data from /proc/pid/status */
2615 while(getline(&line, &len, f) != -1)
2616 {
2617 if(!strncmp(line, "VmPeak:", 7))
2618 g_strlcpy(vmpeak, line + 8, sizeof(vmpeak));
2619 else if(!strncmp(line, "VmSize:", 7))
2620 g_strlcpy(vmsize, line + 8, sizeof(vmsize));
2621 else if(!strncmp(line, "VmRSS:", 6))
2622 g_strlcpy(vmrss, line + 8, sizeof(vmrss));
2623 else if(!strncmp(line, "VmHWM:", 6))
2624 g_strlcpy(vmhwm, line + 8, sizeof(vmhwm));
2625 }
2626 dt_free(line);
2627 fclose(f);
2628
2629 fprintf(stderr, "[memory] max address space (vmpeak): %15s"
2630 "[memory] cur address space (vmsize): %15s"
2631 "[memory] max used memory (vmhwm ): %15s"
2632 "[memory] cur used memory (vmrss ): %15s",
2633 vmpeak, vmsize, vmhwm, vmrss);
2634
2635#elif defined(__APPLE__)
2636 struct task_basic_info t_info;
2637 mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
2638
2639 if(KERN_SUCCESS != task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count))
2640 {
2641 fprintf(stderr, "[memory] task memory info unknown.\n");
2642 return;
2643 }
2644
2645 // Report in kB, to match output of /proc on Linux.
2646 fprintf(stderr, "[memory] max address space (vmpeak): %15s\n"
2647 "[memory] cur address space (vmsize): %12llu kB\n"
2648 "[memory] max used memory (vmhwm ): %15s\n"
2649 "[memory] cur used memory (vmrss ): %12llu kB\n",
2650 "unknown", (uint64_t)t_info.virtual_size / 1024, "unknown", (uint64_t)t_info.resident_size / 1024);
2651#elif defined (_WIN32)
2652 //Based on: http://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process
2653 MEMORYSTATUSEX memInfo;
2654 memInfo.dwLength = sizeof(MEMORYSTATUSEX);
2655 GlobalMemoryStatusEx(&memInfo);
2656 // DWORDLONG totalVirtualMem = memInfo.ullTotalPageFile;
2657
2658 // Virtual Memory currently used by current process:
2659 PROCESS_MEMORY_COUNTERS_EX pmc;
2660 GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS *)&pmc, sizeof(pmc));
2661 size_t virtualMemUsedByMe = pmc.PagefileUsage;
2662 size_t virtualMemUsedByMeMax = pmc.PeakPagefileUsage;
2663
2664 // Max Physical Memory currently used by current process
2665 size_t physMemUsedByMeMax = pmc.PeakWorkingSetSize;
2666
2667 // Physical Memory currently used by current process
2668 size_t physMemUsedByMe = pmc.WorkingSetSize;
2669
2670
2671 fprintf(stderr, "[memory] max address space (vmpeak): %12llu kB\n"
2672 "[memory] cur address space (vmsize): %12llu kB\n"
2673 "[memory] max used memory (vmhwm ): %12llu kB\n"
2674 "[memory] cur used memory (vmrss ): %12llu Kb\n",
2675 virtualMemUsedByMeMax / 1024, virtualMemUsedByMe / 1024, physMemUsedByMeMax / 1024,
2676 physMemUsedByMe / 1024);
2677
2678#else
2679 fprintf(stderr, "dt_print_mem_usage() currently unsupported on this platform\n");
2680#endif
2681}
2682
2683void dt_concat_path_file(char destination[DT_PATH_MAX], const char path[DT_PATH_MAX], const char *const file)
2684{
2685 g_strlcpy(destination, path, sizeof(char) * DT_PATH_MAX);
2686 g_strlcat(destination, G_DIR_SEPARATOR_S, sizeof(char) * DT_PATH_MAX);
2687 g_strlcat(destination, file, sizeof(char) * DT_PATH_MAX);
2688}
2689
2690// clang-format off
2691// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
2692// vim: shiftwidth=2 expandtab tabstop=2 cindent
2693// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
2694// clang-format on
void dt_accels_connect_accels(dt_accels_t *accels)
Actually enable accelerators after having loaded user config.
void dt_accels_cleanup(dt_accels_t *accels)
int dt_gui_gtk_init(dt_gui_gtk_t *gui)
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void init(dt_imageio_module_format_t *self)
Definition avif.c:157
void dt_bauhaus_cleanup(dt_bauhaus_t *bauhaus)
Definition bauhaus.c:1349
dt_bauhaus_t * dt_bauhaus_init()
Definition bauhaus.c:1231
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
static const dt_adaptation_t kind
void dt_culling_mode_to_selection()
Definition collection.c:897
void dt_collection_cleanup_global(void)
Definition collection.c:148
void dt_colorlabels_cleanup(void)
const float f
void dt_colorprofiles_cleanup(void)
Persist the display/soft-proof settings to conf, flush the derived matrix/LUT memo,...
void dt_colorprofiles_init(void)
Build the module's single instance: register every built-in profile, load the color/in and color/out ...
The colour-profile module's API: which profiles exist, and how to apply one.
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
void dt_conf_cleanup(dt_conf_t *cf)
Free everything cf owns. No dt_conf_*() call is valid afterwards.
int dt_conf_get_bool(const char *name)
void dt_conf_init(dt_conf_t *cf, const char *filename, GSList *override_entries)
Populate cf from filename and from the generated defaults.
gchar * dt_conf_get_string(const char *name)
Read the stored string for name as a private copy.
void dt_conf_set_int(const char *name, int val)
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.
void dt_conf_set_string(const char *name, const char *val)
int32_t dt_image_import(const int32_t film_id, const char *filename, gboolean raise_signals)
void dt_image_xmp_mode_refresh_from_conf(void)
#define PACKAGE_BUGREPORT
#define DT_BUILD_CPU_MODE
#define DT_BUILD_CXX_COMPILER
#define DT_BUILD_C_COMPILER
const char darktable_package_string[]
#define DT_BUILD_CXX_FLAGS
#define GETTEXT_PACKAGE
#define DT_BUILD_TYPE
#define DT_BUILD_C_FLAGS
const char darktable_last_commit_year[]
void dt_ctl_switch_mode_to(const char *mode)
Definition control.c:705
void dt_control_init(dt_control_t *s)
Definition control.c:89
void dt_toast_log(const char *msg,...)
Definition control.c:875
void dt_control_set_mouse_over_id(int32_t value)
Definition control.c:998
void dt_control_log(const char *msg,...)
Definition control.c:828
void dt_control_queue_redraw_center()
Request a redraw of the centre view.
Definition control.c:928
void dt_control_shutdown(dt_control_t *s)
Definition control.c:465
void dt_control_cleanup(dt_control_t *s)
Definition control.c:493
void dt_control_crawler_show_image_list(GList *images)
Definition crawler.c:650
GList * dt_control_crawler_run(void)
Definition crawler.c:236
void dt_printers_abort_discovery(void)
Definition cups_print.c:212
void dt_vprint(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:2134
void dt_show_times(const dt_times_t *start, const char *prefix)
Definition darktable.c:2147
static void _preferences_changed(gpointer instance, gpointer user_data)
Definition darktable.c:814
void dt_invalidate_system_available_mem(void)
Definition darktable.c:2367
int dt_get_num_openmp_threads(void)
Number of OpenMP threads the application decided to use.
Definition darktable.c:517
int dt_load_from_string(const gchar *input, gboolean open_image_in_dr, gboolean *single_image)
Definition darktable.c:389
static GLogWriterOutput _gtk_log_writer_filter(GLogLevelFlags log_level, const GLogField *fields, gsize n_fields, gpointer user_data)
Definition darktable.c:227
size_t dt_get_system_available_mem(void)
Definition darktable.c:2348
struct dt_develop_t * dt_dev_get_global(void)
Definition darktable.c:527
struct dt_undo_t * dt_undo_get_global(void)
Definition darktable.c:610
void dt_cleanup()
Definition darktable.c:1868
double dt_get_start_wtime(void)
Definition darktable.c:2089
int dt_worker_threads()
Definition darktable.c:2390
int32_t dt_get_debug_flags(void)
Definition darktable.c:2094
static void _database_renamed(const char *new_library_name)
Definition darktable.c:709
struct dt_dbus_t * dt_dbus_get_global(void)
Definition darktable.c:640
static gint64 _sys_mem_probe_time_us
Definition darktable.c:2346
static void _dt_drain_main_context(const int max_iters)
Definition darktable.c:1860
GList * dt_iop_get_modules_so(void)
Definition darktable.c:532
struct dt_lib_t * dt_lib_get_global(void)
Definition darktable.c:620
static void _doc_screenshot_lib_modules(void *inventory)
Definition darktable.c:838
static void _pipeline_message(const char *message)
Definition darktable.c:741
static void _image_imported(const int32_t imgid)
Definition darktable.c:754
const char * dt_install_id(void)
Definition darktable.c:359
darktable_t darktable
Definition darktable.c:213
void dt_print_mem_usage()
Definition darktable.c:2595
static const dt_pixelpipe_cache_observer_t _pixelpipe_cache_observer
Definition darktable.c:670
static dt_mipmap_cache_settings_t _mipmap_settings_from_conf(void)
Definition darktable.c:682
struct dt_view_manager_t * dt_view_manager_get_global(void)
Definition darktable.c:598
static size_t _sys_mem_probe_value
Definition darktable.c:2345
static void _pixelpipe_cache_warn(const char *message)
Definition darktable.c:659
void dt_dev_set_global(struct dt_develop_t *dev)
Definition darktable.c:542
static dt_pthread_mutex_t _main_message_lock
Definition darktable.c:580
dt_pthread_mutex_t * dt_pipeline_threadsafe_mutex(void)
Definition darktable.c:603
void * dt_alloc_align(size_t size)
Allocate cacheline-aligned memory.
Definition darktable.c:507
GList * dt_ioppr_get_iop_order_rules_global(void)
Definition darktable.c:537
char * dt_get_main_message_copy(void)
Definition darktable.c:582
void dt_capabilities_remove(char *capability)
Definition darktable.c:2578
static void _metadata_notify(const dt_metadata_notice_t kind, const char *message)
Definition darktable.c:722
size_t dt_get_memory_pressure_floor(void)
Definition darktable.c:2427
int dt_init(int argc, char *argv[], const gboolean init_gui, const gboolean load_data)
Definition darktable.c:884
struct dt_imageio_t * dt_imageio_get_global(void)
Definition darktable.c:625
size_t dt_get_total_mem(void)
Definition darktable.c:2422
static void _metadata_geotags_changed(const GList *imgs)
Definition darktable.c:748
struct dt_l10n_t * dt_l10n_get_global(void)
Definition darktable.c:635
#define DT_SYS_MEM_PROBE_PERIOD_US
Definition darktable.c:2342
static const char * _history_operation_name(const char *operation)
Definition darktable.c:795
size_t dt_get_mipmap_mem()
Definition darktable.c:2417
struct dt_gui_gtk_t * dt_gui_get_global(void)
Definition darktable.c:522
const char * dt_session_id(void)
Definition darktable.c:345
static void _pixelpipe_cache_ready(uint64_t hash, uint64_t producer_node_key)
Definition darktable.c:664
static void _history_toast(const char *message)
Definition darktable.c:765
struct dt_control_signal_t * dt_control_signal_get_global(void)
Definition darktable.c:615
static void _history_notify(const char *message)
Definition darktable.c:760
static size_t _get_total_memory()
Definition darktable.c:458
int32_t dt_get_signal_debug_acts(void)
Definition darktable.c:2099
static void _pipeline_busy(const char *message_or_null)
Definition darktable.c:733
char * dt_version_major_minor()
The application version, truncated to <major>.<minor>.
Definition darktable.c:314
void dt_print_nts(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:2122
struct dt_points_t * dt_points_get_global(void)
Definition darktable.c:630
struct dt_control_t * dt_control_get_global(void)
Definition darktable.c:650
static size_t _get_container_mem_limit(void)
Definition darktable.c:2377
void dt_configure_runtime_performance(dt_sys_resources_t *resources, gboolean init_gui)
Definition darktable.c:2432
void dt_gui_set_themes(GList *themes)
Definition darktable.c:552
void dt_capabilities_add(char *capability)
Definition darktable.c:2567
void dt_concat_path_file(char destination[4096], const char path[4096], const char *const file)
Append a constant filename to a variable, stack-based, fixed-sized, directory, and add a / in-between...
Definition darktable.c:2683
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
Definition darktable.c:645
static GMutex _sys_mem_probe_lock
Definition darktable.c:2344
gboolean dt_supported_image(const gchar *filename)
Definition darktable.c:381
static void _doc_screenshot_iop_modules(void *inventory)
Definition darktable.c:850
void dt_capabilities_cleanup()
Definition darktable.c:2588
static void _history_changed(const dt_history_change_t what)
Definition darktable.c:770
void dt_show_times_f(const dt_times_t *start, const char *prefix, const char *suffix,...)
Definition darktable.c:2161
GList * dt_gui_get_themes(void)
Definition darktable.c:547
static gboolean _presets_can_autoapply(const gchar *operation)
Definition darktable.c:801
size_t dt_get_available_mem()
Definition darktable.c:2395
int dt_capabilities_check(char *capability)
Definition darktable.c:2554
static int usage(const char *argv0)
Definition darktable.c:261
static void _database_settings_from_conf(void)
Definition darktable.c:695
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:2109
gboolean dt_get_signal_debug(const int signal)
Definition darktable.c:2104
void dt_set_main_message(char *message)
Definition darktable.c:590
static void _metadata_tags_changed(void)
Definition darktable.c:714
#define CHKSIGDBG(sig)
static size_t _probe_system_available_mem(void)
Definition darktable.c:2185
static void _xmp_mode_preferences_changed(gpointer instance, gpointer user_data)
Definition darktable.c:868
static void _updates_notify(const char *version, const char *url)
Definition darktable.c:879
static void _history_images_changed(const GList *imgs)
Definition darktable.c:788
void dt_database_set_renamed_handler(dt_database_renamed_handler_t handler)
Definition database.c:3599
void dt_database_optimize(void)
Definition database.c:4022
void dt_database_set_settings(const dt_database_settings_t *settings)
Definition database.c:3638
char ** dt_database_snaps_to_remove(void)
Definition database.c:4380
void dt_database_close(void)
Definition database.c:3721
gboolean dt_database_snapshot(void)
Definition database.c:4090
void dt_database_perform_maintenance(void)
Definition database.c:3855
void dt_database_cleanup_busy_statements(void)
Definition database.c:3833
gboolean dt_database_maybe_maintenance(const gboolean closing_time)
Definition database.c:3942
dt_database_open_result_t dt_database_open(const dt_database_params_t *params)
Definition database.c:3604
gboolean dt_database_maybe_snapshot(void)
Definition database.c:4199
dt_database_open_result_t
Definition database.h:74
@ DT_DATABASE_OPEN_FAILED
Definition database.h:76
@ DT_DATABASE_OPEN_LOCKED
Definition database.h:82
void dt_database_gui_register_handlers(void)
gboolean dt_database_show_error(void)
void dt_datetime_init()
Definition datetime.c:34
void dt_dev_history_cleanup(void)
Cleanup cached statements or state used by history I/O.
void dt_dev_pixelpipe_cache_wait_dump_pending(const char *reason)
Dump pending GUI cache wait requests for lifecycle debugging.
gchar * directory
documentation root given after –doc, or NULL
void dt_gui_doc_screenshot_register_source(const char *section, dt_gui_doc_screenshot_source_t source)
void dt_gui_doc_screenshot_set_directory(const char *path)
void dt_gui_doc_screenshot_enable(void)
void dt_gui_doc_screenshot_add_target(void *inventory, GtkWidget *widget, const char *name)
GtkWidget * status
result of the last capture
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
void dt_exif_set_exiv2_taglist()
Definition exif.cc:271
void dt_exif_init()
Definition exif.cc:2403
void dt_exif_cleanup()
Definition exif.cc:2443
What a photograph says about itself: the EXIF, IPTC and XMP tags a camera and a cataloguer write,...
void dt_loc_get_sharedir(char *sharedir, size_t bufsize)
void dt_loc_get_localedir(char *localedir, size_t bufsize)
void dt_loc_init(const char *datadir, const char *moduledir, const char *localedir, const char *configdir, const char *cachedir, const char *tmpdir, const char *kerneldir)
void dt_loc_get_user_config_dir(char *configdir, size_t bufsize)
int dt_film_new(dt_film_t *film, const char *directory)
Definition film.c:129
int dt_film_open(const int32_t id)
Definition film.c:113
void dt_film_set_folder_status()
Definition film.c:394
int dt_film_import(const char *dirname)
Definition film.c:187
dt_job_t * dt_pathlist_import_create(int argc, char *argv[])
Definition film_jobs.c:121
void dt_folder_survey_cleanup()
Release folder survey state after control workers have stopped.
gboolean dt_folder_survey_session_was_active()
TRUE when the previous application session quit while monitoring.
void dt_folder_survey_stop()
Stop new scans before control workers begin shutting down.
void dt_folder_survey_init()
Initialize the folder survey state from the persisted configuration.
gboolean dt_folder_survey_propose_resume()
Propose to resume an interrupted studio session at application start.
@ DT_FP_MODE_FAST
Definition fp_mode.h:40
ssize_t getline(char **lineptr, size_t *n, FILE *stream)
Definition getdelim.c:157
void dt_gui_presets_init()
void dt_gui_presets_cleanup()
void dt_gui_throttle_set_timeout_ms(guint timeout_ms)
int dt_gui_throttle_get_runtime_us(void)
void dt_gui_throttle_cleanup(void)
void dt_gui_throttle_init(int saved_runtime_us_in)
void dt_guides_cleanup(void)
Definition guides.c:858
void dt_history_set_operation_name_resolver(dt_history_operation_name_resolver_t resolver)
void dt_history_set_toast_handler(dt_history_toast_handler_t handler)
void dt_history_set_images_changed_handler(dt_history_images_changed_handler_t handler)
void dt_history_set_changed_handler(dt_history_changed_handler_t handler)
void dt_history_set_message_handler(dt_history_message_handler_t handler)
Install the handler, or NULL to remove it. Messages raised with none installed are dropped.
Everything the history, styles and presets code says to the outside world: messages for the user,...
dt_history_change_t
What changed. Each value stands for one signal this code used to raise itself.
@ DT_HISTORY_CHANGE_DEVELOP
@ DT_HISTORY_CHANGE_TAGS
@ DT_HISTORY_CHANGE_STYLES
void dt_presets_set_autoapply_resolver(dt_presets_autoapply_resolver_t resolver)
void dt_history_repository_cleanup(void)
void dt_image_cache_init(const gboolean verbose)
Initialise the cache.
void dt_image_cache_connect_info_changed_first(const struct dt_control_signal_t *ctlsig)
void dt_image_cache_cleanup(void)
gboolean dt_image_ext_is_supported(const char *ext)
void dt_image_notify_set_imported_handler(dt_image_imported_handler_t handler)
Install the handler, or NULL to remove it.
common/image.c states that an image entered the library; whoever is showing the collection decides wh...
void dt_imageio_cleanup(dt_imageio_t *iio)
void dt_imageio_init(dt_imageio_t *iio)
void dt_iop_set_darktable_iop_table()
Definition imageop.c:1626
const gchar * dt_iop_get_localized_name(const gchar *op)
Definition imageop.c:1651
void dt_iop_load_modules_so(void)
Definition imageop.c:970
void dt_iop_unload_modules_so()
Definition imageop.c:1060
GList * dt_ioppr_get_iop_order_list(int32_t imgid, gboolean sorted)
Load the order list for an image from the DB.
Definition iop_order.c:1100
GList * dt_ioppr_get_iop_order_rules()
Return the list of ordering rules (prev/next constraints).
Definition iop_order.c:836
int dt_ioppr_check_so_iop_order(GList *iop_list, GList *iop_order_list)
Check whether any module .so is missing an iop_order entry.
Definition iop_order.c:1934
int dt_control_add_job(dt_control_t *control, dt_job_queue_t queue_id, _dt_job_t *job)
Definition jobs.c:407
@ DT_JOB_QUEUE_USER_BG
Definition jobs.h:56
dt_l10n_t * dt_l10n_init(gboolean init_list)
Definition l10n.c:313
gboolean dt_lib_presets_can_autoapply(dt_lib_module_t *mod)
Definition lib.c:1319
void dt_lib_init(dt_lib_t *lib)
Definition lib.c:1123
void dt_lib_cleanup(dt_lib_t *lib)
Definition lib.c:1131
dt_debug_thread_t
Debug channels, selected at runtime with -d <channel>.
Definition logging.h:48
@ DT_DEBUG_LIGHTTABLE
Definition logging.h:60
@ DT_DEBUG_UNDO
Definition logging.h:69
@ DT_DEBUG_INPUT
Definition logging.h:64
@ DT_DEBUG_PRINT
Definition logging.h:65
@ DT_DEBUG_OPENCL
Definition logging.h:57
@ DT_DEBUG_GTK
Definition logging.h:54
@ DT_DEBUG_PIPE
Definition logging.h:76
@ DT_DEBUG_PIPECACHE
Definition logging.h:56
@ DT_DEBUG_HISTORY
Definition logging.h:75
@ DT_DEBUG_CAMERA_SUPPORT
Definition logging.h:66
@ DT_DEBUG_NAN
Definition logging.h:61
@ DT_DEBUG_DEMOSAIC
Definition logging.h:72
@ DT_DEBUG_MEMORY
Definition logging.h:59
@ DT_DEBUG_PERF
Definition logging.h:55
@ DT_DEBUG_VERBOSE
Definition logging.h:78
@ DT_DEBUG_PARAMS
Definition logging.h:71
@ DT_DEBUG_CONTROL
Definition logging.h:52
@ DT_DEBUG_COLORPROFILE
Definition logging.h:79
@ DT_DEBUG_CACHE
Definition logging.h:51
@ DT_DEBUG_ALWAYS
Definition logging.h:49
@ DT_DEBUG_SIGNAL
Definition logging.h:70
@ DT_DEBUG_SHORTCUTS
Definition logging.h:73
@ DT_DEBUG_IMAGEIO
Definition logging.h:68
@ DT_DEBUG_DEV
Definition logging.h:53
@ DT_DEBUG_NOCACHE_REUSE
Definition logging.h:80
@ DT_DEBUG_IMPORT
Definition logging.h:77
@ DT_DEBUG_IOPORDER
Definition logging.h:67
@ DT_DEBUG_MASKS
Definition logging.h:62
@ DT_DEBUG_TILING
Definition logging.h:74
@ DT_DEBUG_SQL
Definition logging.h:58
@ DT_DEBUG_LUA
Definition logging.h:63
#define DT_DEBUG_SUPERVISOR
Definition logging.h:87
float *const restrict const size_t k
#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
static void * dt_alloc_align_internal(size_t size)
Platform back-end for dt_alloc_align(). Call dt_alloc_align() instead.
Definition mem_alloc.h:122
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
void dt_metadata_cleanup(void)
void dt_metadata_init()
void dt_metadata_set_geotags_changed_handler(dt_metadata_geotags_changed_handler_t handler)
void dt_metadata_set_tags_changed_handler(dt_metadata_tags_changed_handler_t handler)
void dt_metadata_set_notify_handler(dt_metadata_notify_handler_t handler)
Install the handler, or NULL to remove it. Messages raised with none installed are dropped.
Everything this module says to the outside world: messages for the user, and the fact that the tag vo...
dt_metadata_notice_t
Which affordance the message belongs in. The two are not interchangeable, and the module knows which ...
@ DT_METADATA_NOTICE_TOAST
void dt_mipmap_cache_init(const dt_mipmap_cache_settings_t *settings, const gboolean verbose)
Initialise the cache.
void dt_mipmap_cache_cleanup(void)
size_t size
Definition mipmap_cache.c:3
void dt_mipmap_cache_set_settings(const dt_mipmap_cache_settings_t *settings)
Apply new settings to a running cache.
@ DT_MIPMAP_BLOCKING
@ DT_MIPMAP_FULL
#define dt_mipmap_cache_get(B, C, D, E, F)
#define dt_mipmap_cache_release(B)
void dt_noiseprofile_set_path(const char *alternative)
void dt_noiseprofile_cleanup(void)
void dt_opencl_note_crash_backtrace(const char *backtrace, size_t backtrace_len)
Tell the OpenCL module that the process crashed, and let it judge whether the crash was its driver's ...
Definition opencl.c:1202
int dt_opencl_is_inited(void)
Definition opencl.c:3255
void dt_opencl_cleanup(void)
Definition opencl.c:1601
void dt_opencl_clear_driver_crash_streak(void)
Definition opencl.c:1575
gboolean dt_opencl_finish(const int devid)
Definition opencl.c:1671
void dt_opencl_init(const gboolean exclude_opencl, const gboolean print_statistics)
Definition opencl.c:1260
int dt_opencl_get_num_devices(void)
Number of usable OpenCL devices; 0 when OpenCL is unavailable.
Definition opencl.c:2002
#define omp_get_max_threads()
Definition openmp.h:90
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
Definition paths.h:57
void dt_pipeline_set_message_handler(dt_pipeline_message_handler_t handler)
Install the handler, or NULL to remove it. Messages raised with none installed are dropped.
void dt_pipeline_set_busy_handler(dt_pipeline_busy_handler_t handler)
Everything the pixel pipeline says to whoever is watching: messages for the user, and the busy banner...
void dt_dev_pixelpipe_cache_cleanup(void)
void dt_dev_pixelpipe_cache_get_usage(size_t *current, size_t *max)
gboolean dt_dev_pixelpipe_cache_init(size_t max_memory, const gboolean verbose, const gboolean verbose_detail)
Reserve the cache's arena and start it.
void dt_dev_pixelpipe_cache_set_handlers(dt_pixelpipe_cache_warn_handler_t warn, dt_pixelpipe_cache_ready_handler_t ready, const dt_pixelpipe_cache_observer_t *observer)
Install the handlers. Call once, from the orchestrator, before any pipe runs.
gboolean dt_dev_pixelpipe_cache_is_ready(void)
Has the pixelpipe cache been initialised? Callers that run before dt_dev_pixelpipe_cache_init() succe...
static void dt_points_cleanup(dt_points_t *p)
Definition points.h:86
static void dt_points_init(dt_points_t *p, const unsigned int num_threads)
Definition points.h:66
void dt_control_progress_init(struct dt_control_t *control)
Definition progress.c:230
void copy(TYPE *dest, TYPE *source, size_t num_el)
Copy a flat buffer used to initialize test matrices.
void dt_set_rlimits()
void dt_selection_cleanup_global(void)
Definition selection.c:90
void dt_sentry_shutdown(void)
Definition sentry.c:683
void dt_sentry_init(const gboolean have_gui)
Definition sentry.c:679
void dt_sentry_add_crash_observer(dt_sentry_crash_observer_t observer)
Register a function to be handed the backtrace when the process crashes.
void dt_control_signal_cleanup(dt_control_signal_t *ctlsig)
Definition signal.c:292
dt_control_signal_t * dt_control_signal_init()
Definition signal.c:259
void dt_control_signal_connect(const dt_control_signal_t *ctlsig, dt_signal_t signal, GCallback cb, gpointer user_data)
Definition signal.c:467
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:386
@ DT_DEBUG_SIGNAL_ACT_DISCONNECT
Definition signal.h:348
@ DT_DEBUG_SIGNAL_ACT_CONNECT
Definition signal.h:347
@ DT_DEBUG_SIGNAL_ACT_RAISE
Definition signal.h:346
@ DT_DEBUG_SIGNAL_ACT_PRINT_TRACE
Definition signal.h:349
@ DT_SIGNAL_DEVELOP_INITIALIZE
This signal is raised when darktable.develop is initialized.
Definition signal.h:172
@ DT_SIGNAL_METADATA_CHANGED
This signal is raised when metadata status (shown/hidden) or value has changed.
Definition signal.h:142
@ DT_SIGNAL_VIEWMANAGER_THUMBTABLE_ACTIVATE
Definition signal.h:98
@ DT_SIGNAL_ACTIVE_IMAGES_CHANGE
This signal is raised when image shown in the main view change no param, no returned value.
Definition signal.h:67
@ DT_SIGNAL_CONTROL_REDRAW_ALL
This signal is raised when dt_control_queue_redraw() is called. no param, no returned value.
Definition signal.h:72
@ DT_SIGNAL_MASK_CHANGED
Definition signal.h:315
@ DT_SIGNAL_FOLDER_SURVEY_CHANGED
Raised when the folder survey starts or stops monitoring. no param, no returned value.
Definition signal.h:337
@ DT_SIGNAL_DEVELOP_HISTORY_CHANGE
This signal is raised when develop history is changed no param, no returned value.
Definition signal.h:207
@ DT_SIGNAL_DEVELOP_IMAGE_CHANGED
This signal is raised when image is changed in darkroom.
Definition signal.h:224
@ DT_SIGNAL_CONTROL_PROFILE_USER_CHANGED
This signal is raised when a profile is changed by the user 1 uint32_t : the profile type that has ch...
Definition signal.h:245
@ DT_SIGNAL_IMAGE_EXPORT_TMPFILE
This signal is raised after an image has been exported to a file, but before it is sent to facebook/p...
Definition signal.h:264
@ DT_SIGNAL_IMAGES_ORDER_CHANGE
This signal is raised to request image order change.
Definition signal.h:153
@ DT_SIGNAL_DEVELOP_PREVIEW_PIPE_FINISHED
This signal is raised when develop preview pipe process is finished no param, no returned value.
Definition signal.h:177
@ DT_SIGNAL_STYLE_CHANGED
This signal is raised when a style is added/deleted/changed
Definition signal.h:150
@ DT_SIGNAL_CACHELINE_READY
This signal is raised when one cacheline write lock is released. 1 : uint64_t cacheline hash no retur...
Definition signal.h:188
@ DT_SIGNAL_DARKROOM_UI_CHANGED
Signal that the darkroom GUI color changed.
Definition signal.h:227
@ DT_SIGNAL_DEVELOP_UI_PIPE_FINISHED
This signal is raised when pipe is finished and the gui is attached no param, no returned value.
Definition signal.h:182
@ DT_SIGNAL_FILMROLLS_CHANGED
This signal is raised when a filmroll is deleted/changed but not imported.
Definition signal.h:159
@ DT_SIGNAL_GEOTAG_CHANGED
This signal is raised when a geotag is added/deleted/changed
Definition signal.h:139
@ DT_SIGNAL_MOUSE_OVER_IMAGE_CHANGE
This signal is raised when mouse hovers over image thumbs both on lighttable and in the filmstrip....
Definition signal.h:62
@ DT_SIGNAL_CONTROL_TOAST_REDRAW
This signal is raised when dt_control_toast_redraw() is called. no param, no returned value.
Definition signal.h:291
@ DT_SIGNAL_DEVELOP_MODULE_MOVED
This signal is raised when order of modules in pipeline is changed.
Definition signal.h:221
@ DT_SIGNAL_IMAGE_INFO_CHANGED
This signal is raised when any of image info has changed
Definition signal.h:147
@ DT_SIGNAL_PREFERENCES_CHANGE
This signal is raised after preferences have been changed no parameters no return.
Definition signal.h:276
@ DT_SIGNAL_CONTROL_REDRAW_CENTER
This signal is raised when dt_control_queue_redraw_center() is called. no param, no returned value.
Definition signal.h:77
@ DT_SIGNAL_DEVELOP_MODULEGROUPS_SET
This signal is raised to request a modulegroups update. 1 : dt_iop_module_t *module,...
Definition signal.h:194
@ DT_SIGNAL_FILMROLLS_REMOVED
This signal is raised only when a filmroll is removed.
Definition signal.h:162
@ DT_SIGNAL_TAG_CHANGED
This signal is raised when a tag is added/deleted/changed
Definition signal.h:133
@ DT_SIGNAL_IMAGEIO_STORAGE_CHANGE
This signal is raised when a new storage module is loaded noparameters no return.
Definition signal.h:270
@ DT_SIGNAL_VIEWMANAGER_FILMSTRIP_ACTIVATE
This signal is raised when a thumb is single-clicked in the filmstrip. Views that want filmstrip clic...
Definition signal.h:106
@ DT_SIGNAL_DEVELOP_MODULE_REMOVE
This signal is raised when a module is removed from the history stack 1 module no returned value.
Definition signal.h:218
@ DT_SIGNAL_IMAGE_LOADED
This signal is raised when an asynchronous darkroom image load finishes. 1 : uint32_t the load reques...
Definition signal.h:234
@ DT_SIGNAL_SELECTION_CHANGED
This signal is raised when the selection is changed no param, no returned value.
Definition signal.h:130
@ DT_SIGNAL_CONTROL_PICKERDATA_READY
This signal is raised when new color picker data are available in darkroom. no param,...
Definition signal.h:296
@ DT_SIGNAL_CONTROL_PROFILE_CHANGED
This signal is raised when the screen profile has changed no param, no returned value.
Definition signal.h:239
@ DT_SIGNAL_COUNT
Definition signal.h:340
@ DT_SIGNAL_VIEWMANAGER_FILMSTRIP_DRAG_BEGIN
This signal is raised when a drag starts from the filmstrip. Views that need filmstrip drags to commi...
Definition signal.h:114
@ DT_SIGNAL_IMAGE_IMPORT
This signal is raised when a new image is imported (not cloned) 1 uint32_t : the new image id no retu...
Definition signal.h:251
@ DT_SIGNAL_COLLECTION_CHANGED
This signal is raised when collection changed. To avoid leaking the list, dt_collection_t is connecte...
Definition signal.h:125
@ DT_SIGNAL_CONTROL_LOG_REDRAW
This signal is raised when dt_control_log_redraw() is called. no param, no returned value.
Definition signal.h:286
@ DT_SIGNAL_CONTROL_NAVIGATION_REDRAW
This signal is raised when dt_control_navigation_redraw() is called. no param, no returned value.
Definition signal.h:281
@ DT_SIGNAL_METADATA_UPDATE
Definition signal.h:308
@ DT_SIGNAL_DEVELOP_HISTORY_WILL_CHANGE
This signal is raised when develop history is about to be changed 1 : GList * the current history 2 :...
Definition signal.h:202
@ DT_SIGNAL_VIEWMANAGER_VIEW_CHANGED
This signal is raised by viewmanager when a view has changed. 1 : dt_view_t * the old view 2 : dt_vie...
Definition signal.h:84
void dt_gui_splash_close(void)
Definition splash.c:698
void dt_styles_cleanup(void)
unsigned __int64 uint64_t
Definition strptime.c:75
struct dt_dbus_t * dbus
Definition darktable.h:195
struct dt_undo_t * undo
Definition darktable.h:196
struct dt_lib_t * lib
Definition darktable.h:186
int32_t unmuted_signal_dbg_acts
Definition darktable.h:225
struct dt_imageio_t * imageio
Definition darktable.h:194
int32_t num_openmp_threads
Definition darktable.h:174
struct dt_l10n_t * l10n
Definition darktable.h:197
struct dt_gui_gtk_t * gui
Definition darktable.h:190
GList * capabilities
Definition darktable.h:183
GList * iop
Definition darktable.h:177
struct dt_sys_resources_t dtresources
Definition darktable.h:227
dt_pthread_mutex_t capabilities_threadsafe
Definition darktable.h:200
GList * iop_order_list
Definition darktable.h:178
GList * iop_order_rules
Definition darktable.h:179
struct dt_control_signal_t * signals
Definition darktable.h:189
struct dt_bauhaus_t * bauhaus
Definition darktable.h:191
GList * themes
Definition darktable.h:224
int32_t unmuted
Definition darktable.h:176
struct dt_develop_t * develop
Definition darktable.h:185
struct dt_points_t * points
Definition darktable.h:193
dt_pthread_mutex_t pipeline_threadsafe
Definition darktable.h:205
struct dt_view_manager_t * view_manager
Definition darktable.h:187
gboolean unmuted_signal_dbg[DT_SIGNAL_COUNT]
Definition darktable.h:226
char * main_message
Definition darktable.h:230
char * progname
Definition darktable.h:214
struct dt_conf_t * conf
Definition darktable.h:184
double start_wtime
Definition darktable.h:223
struct dt_control_t * control
Definition darktable.h:188
One key/value pair handed back by dt_conf_all_string_entries().
Definition conf.h:126
char * key
Definition conf.h:128
char * value
Definition conf.h:130
The whole configuration state. One instance lives at darktable.conf.
Definition conf.h:99
pthread_t * thread
Definition control.h:250
dt_pthread_mutex_t run_mutex
Definition control.h:247
int32_t running
Definition control.h:245
dt_pthread_mutex_t log_mutex
Definition control.h:231
const char * alternative
Definition database.h:60
GDBusConnection * dbus_connection
Definition dbus.h:39
cairo_surface_t * surface
dt_accels_t * accels
dt_ui_t * ui
GtkWidget * scroll_to[2]
gboolean culling_mode
char plugin_name[128]
Definition lib.h:81
GModule *void * data
Definition lib.h:79
Definition lib.h:53
Everything about the mipmap cache that the USER decides.
size_t max_memory
RAM budget for the thumbnail LRU, in bytes. A soft quota, not a hard limit.
int embedded_jpg
Whether to prefer the embedded JPEG over decoding (lighttable/embedded_jpg).
int cache_quality
JPEG quality for thumbnails written to disk (database_cache_quality).
gboolean disk_backend
Write generated thumbnails to the on-disk cache (cache_disk_backend).
The supervisor's view of the cache. All four may be NULL; active gates the other three so the cache p...
double clock
Definition times.h:39
double user
Definition times.h:40
void dt_supervisor_cacheline_delete(const uint64_t hash, const size_t size, const int owner_pipe_id, const char *name)
Definition supervisor.c:982
void dt_supervisor_init(void)
Definition supervisor.c:283
void dt_supervisor_rekey(const uint64_t old_hash, const uint64_t new_hash)
void dt_supervisor_cacheline_read(const uint64_t hash, const size_t size)
Definition supervisor.c:952
void dt_supervisor_cleanup(void)
Definition supervisor.c:292
static gboolean dt_supervisor_active(void)
Definition supervisor.h:95
#define DT_MEMORY_PRESSURE_FLOOR_DEFAULT
void dt_set_signal_handlers()
void dt_set_darktable_tags()
Definition tags.c:510
void dt_tags_cleanup(void)
Definition tags.c:1296
void dt_telemetry_shutdown(void)
Definition telemetry.c:451
void dt_telemetry_init(const gboolean have_gui)
Definition telemetry.c:447
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29
static void dt_get_times(dt_times_t *t)
Definition times.h:50
static double dt_get_wtime(void)
Definition times.h:43
void dt_undo_cleanup(dt_undo_t *self)
Definition undo.c:76
dt_undo_t * dt_undo_init(void)
Definition undo.c:50
void dt_updates_init(const gboolean have_gui, dt_updates_notify_fn notify)
Definition updates.c:199
void dt_updates_shutdown(void)
Definition updates.c:223
The nightly update check.
gchar * dt_util_normalize_path(const gchar *_input)
Definition utility.c:683
void dt_view_manager_cleanup(dt_view_manager_t *vm)
Definition view.c:130
void dt_view_manager_init(dt_view_manager_t *vm)
Definition view.c:113
void dt_view_manager_gui_init(dt_view_manager_t *vm)
Definition view.c:121
#define dt_gui_freeze_begin()
#define dt_gui_freeze_end()
void dt_ui_cleanup_titlebar(dt_ui_t *ui)
void dt_ui_cleanup_main_table(dt_ui_t *ui)
void dt_ui_init_global_menu(dt_ui_t *ui)
GtkWidget * dt_ui_main_window(dt_ui_t *ui)