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 KiB: /proc/meminfo's "kB" is 1024 bytes, and the other
458// platforms divide a byte count by 1024.
459static inline size_t _get_total_memory()
460{
461#if defined(__linux__)
462 FILE *f = g_fopen("/proc/meminfo", "rb");
463 if(IS_NULL_PTR(f)) return 0;
464 size_t mem = 0;
465 char *line = NULL;
466 size_t len = 0;
467 int first = 1, found = 0;
468 // return "MemTotal" or the value from the first line
469 while(!found && getline(&line, &len, f) != -1)
470 {
471 char *colon = strchr(line, ':');
472 if(IS_NULL_PTR(colon)) continue;
473 found = !strncmp(line, "MemTotal:", 9);
474 if(found || first) mem = atol(colon + 1);
475 first = 0;
476 }
477 fclose(f);
478 if(len > 0)
479 {
480 dt_free(line);
481 }
482 return mem;
483#elif defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) \
484 || defined(__OpenBSD__)
485#if defined(__APPLE__)
486 int mib[2] = { CTL_HW, HW_MEMSIZE };
487#elif defined(HW_PHYSMEM64)
488 int mib[2] = { CTL_HW, HW_PHYSMEM64 };
489#else
490 int mib[2] = { CTL_HW, HW_PHYSMEM };
491#endif
492 uint64_t physical_memory;
493 size_t length = sizeof(uint64_t);
494 sysctl(mib, 2, (void *)&physical_memory, &length, (void *)NULL, 0);
495 return physical_memory / 1024;
496#elif defined _WIN32
497 MEMORYSTATUSEX memInfo;
498 memInfo.dwLength = sizeof(MEMORYSTATUSEX);
499 GlobalMemoryStatusEx(&memInfo);
500 return memInfo.ullTotalPhys / (uint64_t)1024;
501#else
502 // assume 2GB until we have a better solution.
503 fprintf(stderr, "Unknown memory size. Assuming 2GB\n");
504 return 2097152;
505#endif
506}
507
508void *dt_alloc_align(size_t size)
509{
511}
512
513/* Singleton accessors: the orchestrator BINDS the application-wide instances to the
514 * lower-level libs that declare these symbols (caches/pixelpipe_cache.h and
515 * common/openmp.h). This keeps those libs free of darktable.h — they link
516 * against two functions instead of importing the whole application struct. */
517
522
524{
525 return darktable.gui;
526}
527
529{
530 return darktable.develop;
531}
532
534{
535 return darktable.iop;
536}
537
542
544{
545 darktable.develop = dev;
546}
547
549{
550 return darktable.themes;
551}
552
553void dt_gui_set_themes(GList *themes)
554{
555 g_list_free_full(darktable.themes, dt_free_gpointer);
556 darktable.themes = themes;
557}
558
559/* The string is written by pipeline worker threads and read by the GUI thread painting the
560 * banner, so it carries its own lock rather than borrowing control->log_mutex: the borrowed
561 * one was taken by the single writer at its CALL SITE, which left the invariant unenforceable
562 * -- and left the reader, dt_control_draw_busy_msg(), holding no lock at all while a worker
563 * dt_free()d the very pointer it had handed to pango. That fired once per module per frame
564 * whenever the darkroom was rendering.
565 *
566 * A private lock also keeps this independent of dt_control_t's lifetime, which is freed at
567 * darktable.c's teardown while this string is not. */
568/* Static rather than initialised in dt_init() because this string is written from worker
569 * threads: a lock that is valid from program start has no window in which it is not.
570 *
571 * dt_pthread_mutex_t now wraps exactly one pthread_mutex_t -- the ~1.8 kB of _DEBUG
572 * instrumentation that used to trail it is gone -- so this initialiser is complete rather
573 * than relying on C11 6.7.9p21 zero-fill for the remainder.
574 *
575 * One consequence: this is one of the two locks in the tree that are NOT recursive.
576 * PTHREAD_MUTEX_INITIALIZER takes no attribute, and there is no portable static recursive
577 * initialiser (glibc hides PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP behind _GNU_SOURCE,
578 * mingw spells it without the _NP, neither is visible here). It guards a strdup and a
579 * pointer swap, calls nothing that could re-enter, and giving up the from-program-start
580 * validity to gain recursion would be the worse trade. See system/dtpthread.h. */
581static dt_pthread_mutex_t _main_message_lock = { PTHREAD_MUTEX_INITIALIZER };
582
590
598
603
604dt_pthread_mutex_t *dt_pipeline_threadsafe_mutex(void)
605{
607}
608
609
610
612{
613 return darktable.undo;
614}
615
620
622{
623 return darktable.lib;
624}
625
627{
628 return darktable.imageio;
629}
630
632{
633 return darktable.points;
634}
635
637{
638 return darktable.l10n;
639}
640
642{
643 return darktable.dbus;
644}
645
647{
648 return darktable.bauhaus;
649}
650
652{
653 return darktable.control;
654}
655
656
657/* --- pixelpipe cache handlers ------------------------------------------------
658 * See dt_dev_pixelpipe_cache_set_handlers(). These are the application's answers to the
659 * cache's three announcements; the cache itself names none of these subsystems. */
660static void _pixelpipe_cache_warn(const char *message)
661{
662 dt_control_log("%s", message);
663}
664
665static void _pixelpipe_cache_ready(uint64_t hash, uint64_t producer_node_key)
666{
668 producer_node_key);
669}
670
677
678
679/* The mipmap cache's user-facing settings live in conf; the cache does not read conf. The
680 * application owns that translation, here and in the preference-change handler below, which is
681 * what makes the lifecycle of these four visible: read at startup, re-read when the user
682 * changes one, never anywhere else. */
684{
687 s.disk_backend = dt_conf_get_bool("cache_disk_backend");
688 s.embedded_jpg = dt_conf_get_int("lighttable/embedded_jpg");
689 s.cache_quality = dt_conf_get_int("database_cache_quality");
690 return s;
691}
692
693/* Same arrangement for the database's maintenance and snapshot policy. These were read
694 * with dt_conf_* from five places inside database.c, several of them deep in a decision
695 * the user never sees. */
697{
698 dt_database_settings_t s = { 0 };
699 s.maintenance_check = dt_conf_get_string("database/maintenance_check");
700 s.maintenance_freepage_ratio = dt_conf_get_int("database/maintenance_freepage_ratio");
701 s.create_snapshot = dt_conf_get_string("database/create_snapshot");
702 s.keep_snapshots = dt_conf_get_int("database/keep_snapshots");
706}
707
708/* The database moved the legacy pre-XDG library file and settled on a new name for it.
709 * Persisting that is ours: the module does not write conf. */
710static void _database_renamed(const char *new_library_name)
711{
712 dt_conf_set_string("database", new_library_name);
713}
714
719
720/* src/metadata states what it did; where that appears is ours to decide. Installed
721 * unconditionally: dt_control_log()/dt_toast_log() are themselves no-ops without a GUI, so
722 * this keeps the headless behaviour the direct calls had. */
723static void _metadata_notify(const dt_metadata_notice_t kind, const char *message)
724{
726 dt_toast_log("%s", message);
727 else
728 dt_control_log("%s", message);
729}
730
731/* The pipeline worker names what it is chewing on; the banner and its repaint are ours.
732 * Called from worker threads, as the calls it replaces were -- dt_set_main_message()
733 * under log_mutex and the centre redraw are both worker-safe. */
734static void _pipeline_busy(const char *message_or_null)
735{
736 // dt_set_main_message() takes the string's own lock. Do NOT reintroduce an outer
737 // control->log_mutex here: it guards the message LOG, not this, and it bought nothing.
738 dt_set_main_message(message_or_null ? g_strdup(message_or_null) : NULL);
740}
741
742static void _pipeline_message(const char *message)
743{
744 dt_control_log("%s", message);
745}
746
747/* The geotag list is copied here, at the raise site, exactly where the old call sites
748 * copied it: the signal takes ownership of what it is given. */
749static void _metadata_geotags_changed(const GList *imgs)
750{
752 g_list_copy((GList *)imgs), 0);
753}
754
759
760/* History, styles and presets state what happened; turning that into a signal is ours. */
761static void _history_notify(const char *message)
762{
763 dt_control_log("%s", message);
764}
765
766static void _history_toast(const char *message)
767{
768 dt_toast_log("%s", message);
769}
770
786
787/* The copy is made here, at the raise site, exactly where the call site used to make it:
788 * the signal takes ownership of the list it is given, and the caller keeps its own. */
789static void _history_images_changed(const GList *imgs)
790{
792 g_list_copy((GList *)imgs));
793}
794
795/* Only the side that loaded the modules knows what an operation is called. */
796static const char *_history_operation_name(const char *operation)
797{
798 return dt_iop_get_localized_name(operation);
799}
800
801/* Only the side of the application that owns the panels can answer this. */
802static gboolean _presets_can_autoapply(const gchar *operation)
803{
804 for(const GList *lib_modules = dt_lib_get_global()->plugins; lib_modules;
805 lib_modules = g_list_next(lib_modules))
806 {
807 dt_lib_module_t *lib_module = (dt_lib_module_t *)lib_modules->data;
808 if(!strcmp(lib_module->plugin_name, operation)) return dt_lib_presets_can_autoapply(lib_module);
809 }
810 return TRUE;
811}
812
813/* The two parameters are the GTK signal signature, not ours; neither carries anything we
814 * need, since the settings are read from conf either way. */
815static void _preferences_changed(gpointer instance, gpointer user_data)
816{
817 (void)instance;
818 (void)user_data;
819
823}
824
825/* Same "read at startup, re-read on change, never anywhere else" lifecycle as the mipmap cache
826 * settings above, for the "write_sidecar_files" preference: dt_image_get_xmp_mode() is on the
827 * per-image hot path and reads a cache instead of conf directly. */
828/* Module inventories for the documentation capture panel (gui/actions/doc_screenshot.h).
829 *
830 * They live HERE, and that is deliberate. The panel lists tool modules and darkroom modules,
831 * which are dt_lib_module_t and dt_iop_module_t -- two and three layers above gui/, where the
832 * panel is. Reading them from there inverted the include graph four times over. The
833 * orchestrator is the one place that sits above every module by construction, so it is the
834 * only place that may legally see both lists; the panel asks for (widget, name) pairs and
835 * these hand them over.
836 *
837 * Called on every refresh of the panel, so they read the live lists rather than a snapshot.
838 */
839static void _doc_screenshot_lib_modules(void *inventory)
840{
841 // Tool modules of every view: the ones belonging to the view we are not in are unmapped,
842 // so they show up greyed out instead of disappearing from the inventory.
843 for(GList *item = dt_lib_get_global()->plugins; item; item = g_list_next(item))
844 {
845 dt_lib_module_t *module = (dt_lib_module_t *)item->data;
846 GtkWidget *target = IS_NULL_PTR(module->expander) ? module->widget : module->expander;
847 dt_gui_doc_screenshot_add_target(inventory, target, module->common_fields.name);
848 }
849}
850
851static void _doc_screenshot_iop_modules(void *inventory)
852{
853 // This list is only populated while an image is open in darkroom.
854 for(GList *item = dt_dev_get_global()->iop; item; item = g_list_next(item))
855 {
856 dt_iop_module_t *module = (dt_iop_module_t *)item->data;
857 if(IS_NULL_PTR(module->gui) || IS_NULL_PTR(module->gui->expander)) continue;
858
859 // Several instances of the same module share a name: keep them apart in the tree, and
860 // therefore in the file names too.
861 gchar *label = (module->multi_name[0] != '\0')
862 ? g_strdup_printf("%s (%s)", module->common_fields.name, module->multi_name)
863 : g_strdup(module->common_fields.name);
864 dt_gui_doc_screenshot_add_target(inventory, module->gui->expander, label);
865 dt_free(label);
866 }
867}
868
869static void _xmp_mode_preferences_changed(gpointer instance, gpointer user_data)
870{
871 (void)instance;
872 (void)user_data;
873
875}
876
877
878// Nightly update check found a newer build (GUI thread). Help > Update to the latest
879// nightly build opens the same URL; here we only say so.
880static void _updates_notify(const char *version, const char *url)
881{
882 dt_control_log(_("A newer nightly build is available (%s).\nHelp ▸ Update to the latest nightly build"), version);
883}
884
885int dt_init(int argc, char *argv[], const gboolean init_gui, const gboolean load_data)
886{
887 double start_wtime = dt_get_wtime();
888
889#ifndef _WIN32
890 if(getuid() == 0 || geteuid() == 0)
891 printf(
892 "WARNING: either your user id or the effective user id are 0. are you running darktable as root?\n");
893#endif
894
895 dt_fp_init(DT_FP_MODE_FAST);
896
898
899#ifdef M_MMAP_THRESHOLD
900 mallopt(M_MMAP_THRESHOLD, 128 * 1024); /* use mmap() for large allocations */
901#endif
902
903 // make sure that stack/frame limits are good (musl)
905
906 // init all pointers to 0:
907 memset(&darktable, 0, sizeof(darktable_t));
908
909 darktable.start_wtime = start_wtime;
910
911 darktable.progname = argv[0];
912
913 darktable.main_message = NULL;
914
915 // FIXME: move there into dt_database_t
918
919 darktable.control = (dt_control_t *)calloc(1, sizeof(dt_control_t));
920
921 // database
922 char *dbfilename_from_command = NULL;
923 char *noiseprofiles_from_command = NULL;
924 char *datadir_from_command = NULL;
925 char *moduledir_from_command = NULL;
926 char *localedir_from_command = NULL;
927 char *tmpdir_from_command = NULL;
928 char *configdir_from_command = NULL;
929 char *cachedir_from_command = NULL;
930 char *kerneldir_from_command = NULL;
931
932#ifdef HAVE_OPENCL
933 gboolean exclude_opencl = FALSE;
934 gboolean print_statistics = (strstr(argv[0], "ansel-cltest") == NULL);
935#endif
936
938#ifdef _OPENMP
940#endif
941
942 darktable.unmuted = 0;
943 gboolean cpu_threads_from_cli = FALSE;
944
945 GSList *config_override = NULL;
946 for(int k = 1; k < argc; k++)
947 {
948#ifdef _WIN32
949 if(!strcmp(argv[k], "/?"))
950 {
951 return usage(argv[0]);
952 }
953#endif
954 if(argv[k][0] == '-')
955 {
956 if(!strcmp(argv[k], "--help") || !strcmp(argv[k], "-h"))
957 {
958 return usage(argv[0]);
959 }
960 else if(!strcmp(argv[k], "--version"))
961 {
962 printf("this is %s\ncopyright (c) 2009-2022 Johannes Hanika, (c) 2022-%s Aurélien Pierre\n" PACKAGE_BUGREPORT "\n\ncompile options:\n"
963 " bit depth is %" G_GSIZE_FORMAT " bit\n"
964#ifdef _DEBUG
965 " debug build\n"
966#else
967 " normal build\n"
968#endif
969#ifdef _OPENMP
970 " OpenMP support enabled\n"
971#else
972 " OpenMP support disabled\n"
973#endif
974
975#ifdef HAVE_OPENCL
976 " OpenCL support enabled\n"
977#else
978 " OpenCL support disabled\n"
979#endif
980
981#ifdef USE_COLORDGTK
982 " Colord support enabled\n"
983#else
984 " Colord support disabled\n"
985#endif
986
987#ifdef HAVE_OPENEXR
988 " OpenEXR support enabled\n"
989#else
990 " OpenEXR support disabled\n"
991#endif
992 ,
995 CHAR_BIT * sizeof(void *)
996 );
997 return 1;
998 }
999 else if(!strcmp(argv[k], "--library") && argc > k + 1)
1000 {
1001 dbfilename_from_command = argv[++k];
1002 argv[k-1] = NULL;
1003 argv[k] = NULL;
1004 }
1005 else if(!strcmp(argv[k], "--datadir") && argc > k + 1)
1006 {
1007 datadir_from_command = argv[++k];
1008 argv[k-1] = NULL;
1009 argv[k] = NULL;
1010 }
1011 else if(!strcmp(argv[k], "--moduledir") && argc > k + 1)
1012 {
1013 moduledir_from_command = argv[++k];
1014 argv[k-1] = NULL;
1015 argv[k] = NULL;
1016 }
1017 else if(!strcmp(argv[k], "--tmpdir") && argc > k + 1)
1018 {
1019 tmpdir_from_command = argv[++k];
1020 argv[k-1] = NULL;
1021 argv[k] = NULL;
1022 }
1023 else if(!strcmp(argv[k], "--configdir") && argc > k + 1)
1024 {
1025 configdir_from_command = argv[++k];
1026 argv[k-1] = NULL;
1027 argv[k] = NULL;
1028 }
1029 else if(!strcmp(argv[k], "--cachedir") && argc > k + 1)
1030 {
1031 cachedir_from_command = argv[++k];
1032 argv[k-1] = NULL;
1033 argv[k] = NULL;
1034 }
1035 else if(!strcmp(argv[k], "--localedir") && argc > k + 1)
1036 {
1037 localedir_from_command = argv[++k];
1038 argv[k-1] = NULL;
1039 argv[k] = NULL;
1040 }
1041 else if(!strcmp(argv[k], "--kerneldir") && argc > k + 1)
1042 {
1043 kerneldir_from_command = argv[++k];
1044 argv[k-1] = NULL;
1045 argv[k] = NULL;
1046 }
1047 else if(argv[k][1] == 'd' && argc > k + 1)
1048 {
1049 if(!strcmp(argv[k + 1], "all"))
1050 darktable.unmuted = 0xffffffff & ~DT_DEBUG_VERBOSE; // enable all debug information except verbose
1051 else if(!strcmp(argv[k + 1], "cache"))
1052 darktable.unmuted |= DT_DEBUG_CACHE; // enable debugging for lib/film/cache module
1053 else if(!strcmp(argv[k + 1], "control"))
1054 darktable.unmuted |= DT_DEBUG_CONTROL; // enable debugging for scheduler module
1055 else if(!strcmp(argv[k + 1], "dev"))
1056 darktable.unmuted |= DT_DEBUG_DEV; // develop module
1057 else if(!strcmp(argv[k + 1], "gtk"))
1058 darktable.unmuted |= DT_DEBUG_GTK; // GTK widgets and display setup
1059 else if(!strcmp(argv[k + 1], "input"))
1060 darktable.unmuted |= DT_DEBUG_INPUT; // input devices
1061 else if(!strcmp(argv[k + 1], "pipecache"))
1062 darktable.unmuted |= DT_DEBUG_PIPECACHE; // pipeline cache
1063 else if(!strcmp(argv[k + 1], "perf"))
1064 darktable.unmuted |= DT_DEBUG_PERF; // performance measurements
1065 else if(!strcmp(argv[k + 1], "opencl"))
1066 darktable.unmuted |= DT_DEBUG_OPENCL; // gpu accel via opencl
1067 else if(!strcmp(argv[k + 1], "sql"))
1068 darktable.unmuted |= DT_DEBUG_SQL; // SQLite3 queries
1069 else if(!strcmp(argv[k + 1], "memory"))
1070 darktable.unmuted |= DT_DEBUG_MEMORY; // some stats on mem usage now and then.
1071 else if(!strcmp(argv[k + 1], "lighttable"))
1072 darktable.unmuted |= DT_DEBUG_LIGHTTABLE; // lighttable related stuff.
1073 else if(!strcmp(argv[k + 1], "nan"))
1074 darktable.unmuted |= DT_DEBUG_NAN; // check for NANs when processing the pipe.
1075 else if(!strcmp(argv[k + 1], "masks"))
1076 darktable.unmuted |= DT_DEBUG_MASKS; // masks related stuff.
1077 else if(!strcmp(argv[k + 1], "lua"))
1078 darktable.unmuted |= DT_DEBUG_LUA; // lua errors are reported on console
1079 else if(!strcmp(argv[k + 1], "print"))
1080 darktable.unmuted |= DT_DEBUG_PRINT; // print errors are reported on console
1081 else if(!strcmp(argv[k + 1], "camsupport"))
1082 darktable.unmuted |= DT_DEBUG_CAMERA_SUPPORT; // camera support warnings are reported on console
1083 else if(!strcmp(argv[k + 1], "colorprofile"))
1084 darktable.unmuted |= DT_DEBUG_COLORPROFILE; // color profile handling
1085 else if(!strcmp(argv[k + 1], "nocache_reuse"))
1086 darktable.unmuted |= DT_DEBUG_NOCACHE_REUSE; // disable reusable pixelpipe cache buffers
1087 else if(!strcmp(argv[k + 1], "ioporder"))
1088 darktable.unmuted |= DT_DEBUG_IOPORDER; // iop order information are reported on console
1089 else if(!strcmp(argv[k + 1], "imageio"))
1090 darktable.unmuted |= DT_DEBUG_IMAGEIO; // image importing or exporting messages on console
1091 else if(!strcmp(argv[k + 1], "undo"))
1092 darktable.unmuted |= DT_DEBUG_UNDO; // undo/redo
1093 else if(!strcmp(argv[k + 1], "signal"))
1094 darktable.unmuted |= DT_DEBUG_SIGNAL; // signal information on console
1095 else if(!strcmp(argv[k + 1], "params"))
1096 darktable.unmuted |= DT_DEBUG_PARAMS; // iop module params checks on console
1097 else if(!strcmp(argv[k + 1], "demosaic"))
1099 else if(!strcmp(argv[k + 1], "shortcuts"))
1101 else if(!strcmp(argv[k + 1], "tiling"))
1103 else if(!strcmp(argv[k + 1], "verbose"))
1105 else if(!strcmp(argv[k + 1], "pipe"))
1107 else if(!strcmp(argv[k + 1], "history"))
1109 else if(!strcmp(argv[k + 1], "import"))
1111 else if(!strcmp(argv[k + 1], "supervisor"))
1112 darktable.unmuted |= DT_DEBUG_SUPERVISOR; // high-level event supervisor (NDJSON)
1113 else
1114 return usage(argv[0]);
1115 k++;
1116 argv[k-1] = NULL;
1117 argv[k] = NULL;
1118 }
1119 else if(!strcmp(argv[k], "--d-signal-act") && argc > k + 1)
1120 {
1121 if(!strcmp(argv[k + 1], "all"))
1122 darktable.unmuted_signal_dbg_acts = 0xffffffff; // enable all signal debug information
1123 else if(!strcmp(argv[k + 1], "raise"))
1124 darktable.unmuted_signal_dbg_acts |= DT_DEBUG_SIGNAL_ACT_RAISE; // enable debugging for signal raising
1125 else if(!strcmp(argv[k + 1], "connect"))
1126 darktable.unmuted_signal_dbg_acts |= DT_DEBUG_SIGNAL_ACT_CONNECT; // enable debugging for signal connection
1127 else if(!strcmp(argv[k + 1], "disconnect"))
1128 darktable.unmuted_signal_dbg_acts |= DT_DEBUG_SIGNAL_ACT_DISCONNECT; // enable debugging for signal disconnection
1129 else if(!strcmp(argv[k + 1], "print-trace"))
1130 {
1131#ifdef DT_HAVE_SIGNAL_TRACE
1132 darktable.unmuted_signal_dbg_acts |= DT_DEBUG_SIGNAL_ACT_PRINT_TRACE; // enable printing of signal tracing
1133#else
1134 fprintf(stderr, "[signal] print-trace not available, skipping\n");
1135#endif
1136 }
1137 else
1138 return usage(argv[0]);
1139 k++;
1140 argv[k-1] = NULL;
1141 argv[k] = NULL;
1142 }
1143 else if(!strcmp(argv[k], "--d-signal") && argc > k + 1)
1144 {
1145 gchar *str = g_ascii_strup(argv[k+1], -1);
1146
1147 #define CHKSIGDBG(sig) else if(!g_strcmp0(str, #sig)) do {darktable.unmuted_signal_dbg[sig] = TRUE;} while (0)
1148 if(!g_strcmp0(str, "ALL"))
1149 {
1150 for(int sig=0; sig<DT_SIGNAL_COUNT; sig++)
1152 }
1194
1195 else
1196 {
1197 fprintf(stderr, "unknown signal name: '%s'. use 'ALL' to enable debug for all or use full signal name\n", str);
1198 return usage(argv[0]);
1199 }
1200 dt_free(str);
1201 #undef CHKSIGDBG
1202 k++;
1203 argv[k-1] = NULL;
1204 argv[k] = NULL;
1205 }
1206 else if(argv[k][1] == 't' && argc > k + 1)
1207 {
1208 darktable.num_openmp_threads = CLAMP(atol(argv[k + 1]), 1, 100);
1209 printf("[dt_init] using %d threads for openmp parallel sections\n", darktable.num_openmp_threads);
1210 k++;
1211 argv[k-1] = NULL;
1212 argv[k] = NULL;
1213 cpu_threads_from_cli = TRUE;
1214 }
1215 else if(!strcmp(argv[k], "--conf") && argc > k + 1)
1216 {
1217 gchar *keyval = g_strdup(argv[++k]), *c = keyval;
1218 argv[k-1] = NULL;
1219 argv[k] = NULL;
1220 gchar *end = keyval + strlen(keyval);
1221 while(*c != '=' && c < end) c++;
1222 if(*c == '=' && *(c + 1) != '\0')
1223 {
1224 *c++ = '\0';
1226 entry->key = g_strdup(keyval);
1227 entry->value = g_strdup(c);
1228 config_override = g_slist_append(config_override, entry);
1229 }
1230 dt_free(keyval);
1231 }
1232 else if(!strcmp(argv[k], "--noiseprofiles") && argc > k + 1)
1233 {
1234 noiseprofiles_from_command = argv[++k];
1235 argv[k-1] = NULL;
1236 argv[k] = NULL;
1237 }
1238 else if(!strcmp(argv[k], "--disable-opencl"))
1239 {
1240#ifdef HAVE_OPENCL
1241 exclude_opencl = TRUE;
1242#endif
1243 argv[k] = NULL;
1244 }
1245 else if(!strcmp(argv[k], "--doc"))
1246 {
1247 // Documentation mode: unlocks the widget-screenshot panel in the "Run" menu. Both
1248 // the flag and the directory belong to that module, the only thing that reads them
1249 // back. The optional directory is the root of the documentation tree to write into.
1250 //
1251 // It is consumed only when it really is an existing directory, so that
1252 // `ansel --doc IMG_1234.RAW` still opens the raw file rather than swallowing it.
1253 argv[k] = NULL;
1254 if(argc > k + 1 && !IS_NULL_PTR(argv[k + 1]) && g_file_test(argv[k + 1], G_FILE_TEST_IS_DIR))
1255 {
1257 argv[k] = NULL;
1258 }
1262 }
1263 else if(!strcmp(argv[k], "--debug"))
1264 {
1265 argv[k] = NULL;
1266 }
1267 else if(!strcmp(argv[k], "--"))
1268 {
1269 // "--" confuses the argument parser of glib/gtk. remove it.
1270 argv[k] = NULL;
1271 break;
1272 }
1273#ifdef __APPLE__
1274 else if(!strncmp(argv[k], "-psn_", 5))
1275 {
1276 // "-psn_*" argument is added automatically by macOS and should be ignored
1277 argv[k] = NULL;
1278 }
1279#endif
1280 else
1281 return usage(argv[0]); // fail on unrecognized options
1282 }
1283 }
1284
1285 // remove the NULLs to not confuse gtk_init() later.
1286 for(int i = 1; i < argc; i++)
1287 {
1288 int k;
1289 for(k = i; k < argc; k++)
1290 if(!IS_NULL_PTR(argv[k])) break;
1291
1292 if(k > i)
1293 {
1294 k -= i;
1295 for(int j = i + k; j < argc; j++)
1296 {
1297 argv[j-k] = argv[j];
1298 argv[j] = NULL;
1299 }
1300 argc -= k;
1301 }
1302 }
1303
1304 // get valid directories
1305 dt_loc_init(datadir_from_command, moduledir_from_command, localedir_from_command, configdir_from_command, cachedir_from_command, tmpdir_from_command, kerneldir_from_command);
1306
1307 fprintf(stdout, "[build] version: %s\n", darktable_package_string);
1308 fprintf(stdout, "[build] type: %s | cpu mode: %s\n", DT_BUILD_TYPE, DT_BUILD_CPU_MODE);
1309 fprintf(stdout, "[build] c compiler: %s\n", DT_BUILD_C_COMPILER);
1310 fprintf(stdout, "[build] c flags: %s\n", DT_BUILD_C_FLAGS);
1311 fprintf(stdout, "[build] c++ compiler: %s\n", DT_BUILD_CXX_COMPILER);
1312 fprintf(stdout, "[build] c++ flags: %s\n", DT_BUILD_CXX_FLAGS);
1313
1315 {
1316 fprintf(stderr, "[memory] at startup\n");
1318 }
1319
1320 char sharedir[DT_PATH_MAX] = { 0 };
1321 dt_loc_get_sharedir(sharedir, sizeof(sharedir));
1322
1323 // we have to have our share dir in XDG_DATA_DIRS,
1324 // otherwise GTK+ won't find our logo for the about screen (and maybe other things)
1325 {
1326 const gchar *xdg_data_dirs = g_getenv("XDG_DATA_DIRS");
1327 gchar *new_xdg_data_dirs = NULL;
1328 gboolean set_env = TRUE;
1329 if(!IS_NULL_PTR(xdg_data_dirs) && *xdg_data_dirs != '\0')
1330 {
1331 // check if sharedir is already in there
1332 gboolean found = FALSE;
1333 gchar **tokens = g_strsplit(xdg_data_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
1334 // xdg_data_dirs is neither NULL nor empty => !IS_NULL_PTR(tokens)
1335 for(char **iter = tokens; !IS_NULL_PTR(*iter); iter++)
1336 if(!strcmp(sharedir, *iter))
1337 {
1338 found = TRUE;
1339 break;
1340 }
1341 g_strfreev(tokens);
1342 if(found)
1343 set_env = FALSE;
1344 else
1345 new_xdg_data_dirs = g_strjoin(G_SEARCHPATH_SEPARATOR_S, sharedir, xdg_data_dirs, NULL);
1346 }
1347 else
1348 {
1349#ifndef _WIN32
1350 // see http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html for a reason to use those as a
1351 // default
1352 if(!g_strcmp0(sharedir, "/usr/local/share")
1353 || !g_strcmp0(sharedir, "/usr/local/share/")
1354 || !g_strcmp0(sharedir, "/usr/share") || !g_strcmp0(sharedir, "/usr/share/"))
1355 new_xdg_data_dirs = g_strdup("/usr/local/share/" G_SEARCHPATH_SEPARATOR_S "/usr/share/");
1356 else
1357 new_xdg_data_dirs = g_strdup_printf("%s" G_SEARCHPATH_SEPARATOR_S "/usr/local/share/" G_SEARCHPATH_SEPARATOR_S
1358 "/usr/share/", sharedir);
1359#else
1360 set_env = FALSE;
1361#endif
1362 }
1363
1364 if(set_env) g_setenv("XDG_DATA_DIRS", new_xdg_data_dirs, 1);
1365 dt_print(DT_DEBUG_DEV, "new_xdg_data_dirs: %s\n", new_xdg_data_dirs);
1366 dt_free(new_xdg_data_dirs);
1367 }
1368
1369 setlocale(LC_ALL, "");
1370 char localedir[DT_PATH_MAX] = { 0 };
1371 dt_loc_get_localedir(localedir, sizeof(localedir));
1372 bindtextdomain(GETTEXT_PACKAGE, localedir);
1373 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
1374 textdomain(GETTEXT_PACKAGE);
1375
1376 if(init_gui)
1377 {
1378 // I doubt that connecting to dbus for ansel-cli makes sense
1379 darktable.dbus = NULL; //dt_dbus_init();
1380
1381 // make sure that we have no stale global progress bar visible. thus it's run as early as possible
1383 }
1384
1385 // thread-safe init:
1386 dt_exif_init();
1387 char datadir[DT_PATH_MAX] = { 0 };
1388 dt_loc_get_user_config_dir(datadir, sizeof(datadir));
1389 char anselrc[DT_PATH_MAX] = { 0 };
1390 dt_concat_path_file(anselrc, datadir, "anselrc");
1391
1392 // initialize the config backend. this needs to be done first...
1393 darktable.conf = (dt_conf_t *)calloc(1, sizeof(dt_conf_t));
1394 dt_conf_init(darktable.conf, anselrc, config_override);
1395 g_slist_free_full(config_override, dt_free_gpointer);
1396
1397 // set the interface language and prepare selection for prefs
1398 darktable.l10n = dt_l10n_init(init_gui);
1399
1400 dt_confgen_init();
1401 // The throttle's persisted state and timeout preference are configuration, so they are
1402 // supplied here rather than read inside it.
1403 dt_gui_throttle_init(dt_conf_get_int("processing/gui_throttle_runtime_us"));
1404 dt_gui_throttle_set_timeout_ms((guint)MAX(dt_conf_get_int("processing/timeout"), 0));
1405
1406 // Needs to run after dt_confgen_init()
1407 // Don't override cli argument if any
1408 if(!cpu_threads_from_cli)
1409 {
1410 const int user_threads = dt_conf_get_int("cpu_threads");
1411 if(user_threads > 0) darktable.num_openmp_threads = user_threads;
1412 }
1413
1414#ifdef _OPENMP
1415 omp_set_num_threads(darktable.num_openmp_threads);
1416#endif
1417
1418 // we need this REALLY early so that error messages can be shown, however after gtk_disable_setlocale
1419 if(init_gui)
1420 {
1421 g_log_set_writer_func(_gtk_log_writer_filter, NULL, NULL);
1422 gtk_init(&argc, &argv);
1423
1424 darktable.themes = NULL;
1425 }
1426
1427 // build the colour-profile module's own list; it owns it, we do not hold it
1429
1430 // initialize datetime data
1432
1433 // initialize the database
1434 //
1435 // Every user preference the database acts on is read here and handed over, so that the
1436 // SQL layer never reads conf itself and "when does this take effect" has one answer.
1444
1445 gchar *configured_library = dt_conf_get_string("database");
1446 const dt_database_params_t db_params = { .alternative = dbfilename_from_command,
1447 .library = configured_library,
1448 .load_data = load_data,
1449 .has_gui = init_gui,
1450 .verbose = (dt_get_debug_flags() & DT_DEBUG_SQL) != 0 };
1451
1452 gboolean recheck_needed = TRUE;
1453 while (recheck_needed)
1454 {
1455 // Before, not after: dt_database_open() can hit a read-only or corrupt database and needs
1456 // to ask the user what to do about it, and dt_gui_gtk_init() -- where every other backend
1457 // handler is registered -- only runs much further down. This is the only place that knows
1458 // this early whether there will be anybody to ask.
1459 if(init_gui) dt_database_gui_register_handlers();
1460
1461 const dt_database_open_result_t opened = dt_database_open(&db_params);
1462 if(opened == DT_DATABASE_OPEN_FAILED)
1463 {
1464 printf("ERROR : cannot open database\n");
1465 dt_free(configured_library);
1467 return 1;
1468 }
1469 else if(opened == DT_DATABASE_OPEN_LOCKED)
1470 {
1471 gboolean error = FALSE;
1472
1473 if (init_gui)
1474 {
1475 gboolean image_loaded_elsewhere = FALSE;
1476#ifndef MAC_INTEGRATION
1477 // send the images to the other instance via dbus
1478 fprintf(stderr, "trying to open the images in the running instance\n");
1479
1481 {
1482 GDBusConnection *connection = NULL;
1483 for(int i = 1; i < argc; i++)
1484 {
1485 // make the filename absolute ...
1486 if(argv[i] == NULL || *argv[i] == '\0') continue;
1487 gchar *filename = dt_util_normalize_path(argv[i]);
1488 if(IS_NULL_PTR(filename)) continue;
1489 if(IS_NULL_PTR(connection)) connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
1490 // ... and send it to the running instance of darktable
1491 image_loaded_elsewhere = g_dbus_connection_call_sync(connection, "org.darktable.service", "/darktable",
1492 "org.darktable.service.Remote", "Open",
1493 g_variant_new("(s)", filename), NULL,
1494 G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL) != NULL;
1495 dt_free(filename);
1496 }
1497 if(connection) g_object_unref(connection);
1498 }
1499#endif
1500 if(!image_loaded_elsewhere)
1501 // Reporting CONSUMES the pending error.
1503 }
1504 if(error)
1505 {
1506 fprintf(stderr, "ERROR: can't acquire database lock, aborting.\n");
1507 dt_free(configured_library);
1509 return error;
1510 }
1511 else
1512 {
1513 // Close before retrying. The loop used to jump straight back to
1514 // dt_database_init(), abandoning the half-open database it had just been handed
1515 // -- its two filename strings and, when only one of the two lock files had been
1516 // taken, that lock file too. dt_database_open() refuses to open over an open
1517 // connection, so the leak is now a compile-time-visible step instead.
1519 continue;
1520 }
1521 }
1522 recheck_needed = FALSE;
1523 }
1524
1525 dt_free(configured_library);
1526
1527 //db maintenance on startup (if configured to do so)
1529 {
1531 }
1532
1533 // init darktable tags table
1535
1536 // The signal system exists to tell GUI widgets about backend events -- every raise is
1537 // already dead in a GUI-less process (dt_control_signal_raise() bails when the control
1538 // system is not running, and only the GUI starts it), so only the GUI gets the machinery.
1539 // The connect/raise surface treats a NULL system as "not in this process" and no-ops.
1540 darktable.signals = init_gui ? dt_control_signal_init() : NULL;
1541
1542 /* src/metadata reports that the tag vocabulary changed; turning that into the GTK signal
1543 * its consumers already listen for is ours. Installed HERE, not with the other handlers
1544 * further up: the signal system does not exist until the line above, and nothing can
1545 * edit a tag before it does. */
1551 // Same reason for these two: they raise signals, so they wait for the signal system.
1554 // Critical: ensure image cache gets refreshed BEFORE any other IMAGE_INFO_CHANGED handlers.
1555 // This handler reloads dt_image_t from DB so all downstream callbacks see fresh metadata.
1557
1558 if(init_gui)
1559 {
1561 }
1562 else
1563 {
1564 if(dbfilename_from_command && !strcmp(dbfilename_from_command, ":memory:"))
1565 dt_gui_presets_init(); // init preset db schema.
1569 }
1570
1571 // we initialize grouping early because it's needed for collection init
1572 // idem for folder reachability
1573 if(init_gui)
1574 {
1575 darktable.gui = (dt_gui_gtk_t *)calloc(1, sizeof(dt_gui_gtk_t));
1576 memset(darktable.gui->scroll_to, 0, sizeof(darktable.gui->scroll_to));
1578 }
1579
1580 // The collection and selection are lighttable state: dt_gui_gtk_init() creates them.
1581 // A GUI-less process (ansel-cli) runs without either -- their modules' public entry
1582 // points treat "not created" as a no-op, so shared code needs no guards.
1583
1584 /* capabilities set to NULL */
1585 darktable.capabilities = NULL;
1586
1587
1588 // Re-assert our handlers once the third-party libraries above are up. This used to compensate
1589 // for GraphicsMagick's InitializeMagick(), which stole all of them; that library is gone, but
1590 // the call is cheap and idempotent (system_signal_handling.c counts its invocations), and it
1591 // keeps the guarantee that whatever init ran before this point cannot leave us without a
1592 // SIGSEGV handler. Crash reporting is initialized after it, deliberately.
1594
1595#ifdef _OPENMP
1596 // Re-assert our thread count last, after every library above has initialised.
1597 //
1598 // omp_set_num_threads() writes only the CALLING thread's ICV, and a library that sizes its own
1599 // pool from omp_get_num_procs() publishes that by calling it -- a process-wide side effect on a
1600 // library-local decision. GraphicsMagick's InitializeMagick() did exactly that from here, which
1601 // silently overrode `-t N` and the "CPU cores" preference for every parallel region entered from
1602 // this thread afterwards: invisible in the GUI, where pixel work runs on control worker threads
1603 // that set their own count in dt_control_work(), and total in ansel-cli, where the export
1604 // pipeline runs on this very thread.
1605 //
1606 // Both of the libraries known to have done it -- GraphicsMagick and G'MIC -- have since been
1607 // removed, so nothing in the current dependency set is known to clobber the count. This stays
1608 // anyway, and deliberately unconditional: it costs one call at startup, the failure mode is
1609 // silent, and it took an LD_PRELOAD shim to find the last one. Keep it after every library init.
1610 omp_set_num_threads(darktable.num_openmp_threads);
1611#endif
1612
1613 // noiseprofiles.json is parsed lazily by common/noiseprofiles.c on first lookup;
1614 // only the --noiseprofiles override needs to reach it now.
1615 if(noiseprofiles_from_command) dt_noiseprofile_set_path(noiseprofiles_from_command);
1616
1617 // The GUI must be initialized before the views, because the init()
1618 // functions of the views depend on darktable.control->accels_* to register
1619 // their keyboard accelerators
1620
1621 // TODO : Make a single call to unified GUI API initializing everything graphical at once.
1622 // The current tangled mess is a nightmare to maintain.
1623
1624 if(init_gui)
1625 {
1627 {
1628 fprintf(stderr, "ERROR: can't init gui, aborting.\n");
1630 return 1;
1631 }
1633 }
1634 else
1635 darktable.gui = NULL;
1636
1637 // This needs to run after gui init because we init cache lines size with window size
1638 // but before image cache init and pipeline cache init (aka dev init aka darkroom init aka viewmanager init)
1639 // because we init its size here
1641
1644
1645 // check whether we were able to load darkroom view. if we failed, we'll crash everywhere later on.
1647 {
1648 fprintf(stderr, "ERROR: can't init develop system, aborting.\n");
1650 return 1;
1651 }
1652
1653 // The arena is only a virtual-memory reservation (physical pages get committed on
1654 // use), so init only fails on exhausted address space or a pathological requested
1655 // size. Rather than aborting outright, retry smaller: a shrunken cache degrades
1656 // performance, an abort loses the session.
1657 size_t pipecache_size = darktable.dtresources.pixelpipe_memory;
1658 dt_dev_pixelpipe_cache_init(pipecache_size,
1661 while(!dt_dev_pixelpipe_cache_is_ready() && pipecache_size / 2 >= (size_t)512 * 1024 * 1024)
1662 {
1663 pipecache_size /= 2;
1664 fprintf(stderr,
1665 "WARNING: can't reserve %" G_GSIZE_FORMAT " MiB of virtual memory for the pixelpipe cache, "
1666 "retrying with %" G_GSIZE_FORMAT " MiB. Check your memory settings.\n",
1667 2 * pipecache_size / (1024 * 1024), pipecache_size / (1024 * 1024));
1668 dt_dev_pixelpipe_cache_init(pipecache_size,
1671 }
1672 darktable.dtresources.pixelpipe_memory = pipecache_size;
1673
1674 /* The cache announces three things -- it is full, a cacheline became readable, and the
1675 * supervisor's bookkeeping -- and used to do it by calling dt_control_log(), raising
1676 * DT_SIGNAL_CACHELINE_READY and calling dt_supervisor_*() itself. That put control/ and
1677 * develop/ inside a module that is otherwise pure storage. The orchestrator wires them
1678 * here instead: the cache says what happened, the application decides who hears it. */
1682 {
1683 fprintf(stderr, "ERROR: can't init pixelpipe cache, aborting.\n");
1685 return 1;
1686 }
1687
1688 // High-level event supervisor registry (active only under -d supervisor).
1690
1691 darktable.points = (dt_points_t *)calloc(1, sizeof(dt_points_t));
1693
1694 // must come before mipmap_cache, because that one will need to access
1695 // image dimensions stored in here:
1697
1699 dt_mipmap_cache_init(&mipmap_settings, (dt_get_debug_flags() & DT_DEBUG_CACHE) != 0);
1700
1701 /* Re-tell the cache whenever the user changes one of its four settings. */
1703 G_CALLBACK(_preferences_changed), NULL);
1704
1707 G_CALLBACK(_xmp_mode_preferences_changed), NULL);
1708
1709#ifdef HAVE_OPENCL
1710 dt_opencl_init(exclude_opencl, print_statistics);
1711 // Show the splash only while compiling OpenCL kernels (triggered from opencl.c),
1712 // then close it immediately so the rest of the startup stays splash-free.
1714#endif
1715
1716 darktable.imageio = (dt_imageio_t *)calloc(1, sizeof(dt_imageio_t));
1718
1719 // load default iop order
1721 // load iop order rules
1723 // load the darkroom mode plugins once:
1725 // check if all modules have a iop order assigned
1727 {
1728 fprintf(stderr, "ERROR: iop order looks bad, aborting.\n");
1730 return 1;
1731 }
1732
1733 // set up memory.darktable_iop_names table
1735
1736 // set up the list of exiv2 metadata
1738
1739 // init metadata flags
1741
1742 if(init_gui)
1743 {
1744 darktable.lib = (dt_lib_t *)calloc(1, sizeof(dt_lib_t));
1746
1747 // prevent bauhaus widgets from sending value-changed signals
1748 // because some of them expect user interactions.
1750
1751 // init the gui part of views
1753
1755
1756 // initialize undo struct
1758
1759 // Global menu inherits many parts of the GUI,
1760 // so it should be inited last
1762 }
1763
1765 {
1766 fprintf(stderr, "[memory] after successful startup\n");
1768 }
1769
1770 if(init_gui)
1771 {
1772 // we have to call dt_ctl_switch_mode_to() here already to not run into a lua deadlock.
1773 // having another call later is ok
1774 dt_ctl_switch_mode_to("lighttable");
1775
1776#ifndef MAC_INTEGRATION
1777 // load image(s) specified on cmdline.
1778 // this has to happen after lua is initialized as image import can run lua code
1779 if (argc == 2)
1780 {
1781 // If only one image is listed, attempt to load it in darkroom
1782 (void)dt_load_from_string(argv[1], TRUE, NULL);
1783 }
1784 else if (argc > 2)
1785 {
1786 // when multiple names are given, fire up a background job to import them
1788 }
1789#endif
1790 }
1791
1792 // Make sure that the database and xmp files are in sync. This is a background job on
1793 // purpose: it costs one directory listing per film roll, so on a network-mounted library it
1794 // takes seconds to minutes, and it used to run to completion right here on the startup
1795 // path -- before dt_control_init(), before the main window existed. It asks the user about
1796 // images whose xmp files are newer than the db entry itself, once it knows of any.
1797 // FIXME: is this also useful in non-gui mode?
1798 if(init_gui && dt_conf_get_bool("run_crawler_on_start"))
1799 {
1801 }
1802
1803 if(init_gui)
1804 {
1805 // The user config is already loaded from gui/application.c, right after dt_accels_init()
1806 // and before any widget/menu is built -- loading it again here would re-read the
1807 // still-on-disk (unsaved) file and clobber any normalization dt_accels_connect_accels()
1808 // already applied to the live GtkAccelMap in the meantime (e.g. an old Ctrl-flavored
1809 // save recognized as today's platform-native default and resynced accordingly).
1811 //gtk_window_add_accel_group(GTK_WINDOW(dt_ui_main_window(darktable.gui->ui)), darktable.gui->accels->global_accels);
1812
1813 // Studio capture folder survey: restore the persisted comparison state and,
1814 // once the main loop runs and the window is mapped, propose to resume a
1815 // session that was monitoring when the application was last closed.
1818 g_idle_add((GSourceFunc)dt_folder_survey_propose_resume, NULL);
1819 }
1820
1822
1823 // On first launch, ask once for consent to the opt-in data flows (crash reports
1824 // and usage analytics) in a single dialog, before initializing either module so
1825 // their enabled flags are set when they read them.
1826 dt_privacy_ask_consent(init_gui);
1827
1828 // Initialize crash reporting last, after the final dt_set_signal_handlers() so
1829 // sentry's handler sits on top and chains down into our gdb/drmingw fallback.
1830 dt_sentry_init(init_gui);
1831
1832#ifdef HAVE_OPENCL
1833 /* Connect the crash reporter to the OpenCL module, which is the only place that knows
1834 * whether a crash was its driver's doing. Wired here rather than inside either one so
1835 * neither has to include the other: sentry supplies backtraces without knowing what a GPU
1836 * is, and opencl judges them without knowing that sentry exists.
1837 *
1838 * Guarded because opencl.h declares nothing without HAVE_OPENCL -- a build with OpenCL
1839 * compiled out has no such function to point at, and no GPU driver to blame either. */
1841#endif
1842
1843 // Opt-in usage analytics (PostHog) - separate toggle from crash reporting.
1844 dt_telemetry_init(init_gui);
1845
1846 // Nightly builds: once a day, ask ansel.photos/nightly.json whether a newer build
1847 // exists for this format. Its own toggle (updates/enabled), no telemetry involved.
1848 // The toast is ours to post: the module lives in common/ and does not know control/.
1850
1851 dt_print(DT_DEBUG_CONTROL, "[init] startup took %f seconds\n", dt_get_wtime() - start_wtime);
1852
1853 return 0;
1854}
1855
1856static void _dt_drain_main_context(const int max_iters)
1857{
1858 if(max_iters <= 0) return;
1859 GMainContext *ctx = g_main_context_default();
1860 for(int i = 0; i < max_iters && g_main_context_pending(ctx); i++)
1861 g_main_context_iteration(ctx, FALSE);
1862}
1863
1865{
1866 const int init_gui = (!IS_NULL_PTR(darktable.gui));
1867
1868 // Flush crash reporting and mark this session as a clean exit. Done early so
1869 // events are sent while the rest of the app is still up; the clean-session
1870 // counter it writes is persisted later by dt_conf_cleanup().
1872
1873 // Stop the update check first: it is the one that may still post to the GUI thread.
1875
1876 // Flush and stop usage analytics.
1878
1879 // Restore selection if exiting on culling mode to be sure it's saved in DB
1882
1883 // Restore auto-computed zoom level to user-defined
1884 dt_conf_set_int("plugins/lighttable/images_in_row", dt_conf_get_int("plugins/lighttable/images_in_row_backup"));
1885
1886 // last chance to ask user for any input...
1887
1888 const gboolean perform_maintenance = dt_database_maybe_maintenance(TRUE);
1889 const gboolean perform_snapshot = dt_database_maybe_snapshot();
1890 gchar **snaps_to_remove = NULL;
1891 if(perform_snapshot)
1892 {
1893 snaps_to_remove = dt_database_snaps_to_remove();
1894 }
1895
1896#ifdef HAVE_PRINT
1898#endif
1899
1900 // anything that asks user for input should be placed before this line
1901
1902 if(init_gui)
1903 {
1906
1907
1908 // hide main window and do rest of the cleanup in the background
1909 gtk_widget_hide(dt_ui_main_window(darktable.gui->ui));
1910
1912 //dt_dbus_destroy(darktable.dbus);
1913
1914 // Stop control workers before unloading views and libs. They can still be
1915 // processing lighttable-side jobs while shutdown is tearing down modules.
1919
1921
1924 }
1925
1926 dt_dev_pixelpipe_cache_wait_dump_pending("app-cleanup-before-view-manager");
1929
1930 if(init_gui)
1931 {
1934
1936
1939
1940 /* Force GTK to teardown the toplevel widget tree now, while the main
1941 * context still exists. This helps release style/cairo resources that
1942 * would otherwise stay alive until process exit. */
1943 GtkWidget *main_window = dt_ui_main_window(darktable.gui->ui);
1944 if(GTK_IS_WIDGET(main_window))
1945 gtk_widget_destroy(main_window);
1946
1947 dt_gui_gtk_t *gui = darktable.gui;
1948 darktable.gui = NULL;
1950 dt_free(gui->ui);
1951 dt_free(gui);
1952 }
1953
1960
1961 dt_collection_cleanup_global(); // no-ops in a GUI-less process: never created there
1963
1964 // Mipmap cleanup may still consult the image cache for paths.
1967
1969 dt_conf_set_int("processing/gui_throttle_runtime_us", dt_gui_throttle_get_runtime_us());
1971 // Needs conf alive: a clean exit with OpenCL running is what clears the driver-crash streak.
1978 g_list_free_full(darktable.iop_order_list, dt_free_gpointer);
1980 g_list_free_full(darktable.iop_order_rules, dt_free_gpointer);
1982
1983#ifdef HAVE_OPENCL
1985 {
1986 for(int i = 0; i < dt_opencl_get_num_devices(); i++)
1988 }
1989#endif
1990
1993
1995
1996 dt_guides_cleanup(); // module-private list: a no-op when the GUI never registered any
1997
1998 if(perform_maintenance)
1999 {
2002 }
2003
2005 if(perform_snapshot)
2006 {
2007 if(dt_database_snapshot() && snaps_to_remove)
2008 {
2009 int i = 0;
2010 while(snaps_to_remove[i])
2011 {
2012 // make file to remove writable, mostly problem on windows.
2013 g_chmod(snaps_to_remove[i], S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
2014
2015 dt_print(DT_DEBUG_SQL, "[db backup] removing old snap: %s... ", snaps_to_remove[i]);
2016 const int retunlink = g_remove(snaps_to_remove[i++]);
2017 dt_print(DT_DEBUG_SQL, "%s\n", retunlink == 0 ? "success" : "failed!");
2018 }
2019 }
2020 }
2021 if(snaps_to_remove)
2022 {
2023 g_strfreev(snaps_to_remove);
2024 }
2026
2027 if(init_gui)
2028 {
2030 }
2031
2033
2034 if(init_gui)
2035 {
2038 }
2039 else
2040 {
2043 }
2045
2047 darktable.signals = NULL;
2048
2050
2053
2055
2056 /* Stop GLib pooled workers first, then release the current thread default
2057 * PangoCairo font map before finalizing Fontconfig caches. */
2058 if(init_gui)
2059 {
2060 g_thread_pool_stop_unused_threads();
2061#if !defined(_WIN32) && !defined(__APPLE__)
2062 PangoFontMap *fontmap = pango_cairo_font_map_get_default();
2063 gboolean use_fontconfig_backend = FALSE;
2064
2065 if(fontmap && PANGO_IS_CAIRO_FONT_MAP(fontmap))
2066 {
2067 const cairo_font_type_t font_backend
2068 = pango_cairo_font_map_get_font_type(PANGO_CAIRO_FONT_MAP(fontmap));
2069 use_fontconfig_backend = (font_backend == CAIRO_FONT_TYPE_FT);
2070 }
2071
2072 if(use_fontconfig_backend && fontmap && g_type_is_a(G_OBJECT_TYPE(fontmap), pango_fc_font_map_get_type()))
2073 pango_fc_font_map_shutdown((PangoFcFontMap *)fontmap);
2074 if(use_fontconfig_backend) FcFini();
2075#endif
2076 pango_cairo_font_map_set_default(NULL);
2077 }
2078}
2079
2081{
2082 return darktable.start_wtime;
2083}
2084
2086{
2087 return darktable.unmuted;
2088}
2089
2091{
2093}
2094
2095gboolean dt_get_signal_debug(const int signal)
2096{
2097 return darktable.unmuted_signal_dbg[signal];
2098}
2099
2100void dt_print(dt_debug_thread_t thread, const char *msg, ...)
2101{
2103 {
2104 printf("%f ", dt_get_wtime() - darktable.start_wtime);
2105 va_list ap;
2106 va_start(ap, msg);
2107 g_vprintf(msg, ap);
2108 va_end(ap);
2109 fflush(stdout);
2110 }
2111}
2112
2113void dt_print_nts(dt_debug_thread_t thread, const char *msg, ...)
2114{
2116 {
2117 va_list ap;
2118 va_start(ap, msg);
2119 g_vprintf(msg, ap);
2120 va_end(ap);
2121 fflush(stdout);
2122 }
2123}
2124
2125void dt_vprint(dt_debug_thread_t thread, const char *msg, ...)
2126{
2128 {
2129 printf("%f ", dt_get_wtime() - darktable.start_wtime);
2130 va_list ap;
2131 va_start(ap, msg);
2132 g_vprintf(msg, ap);
2133 va_end(ap);
2134 fflush(stdout);
2135 }
2136}
2137
2138void dt_show_times(const dt_times_t *start, const char *prefix)
2139{
2140 /* Skip all the calculations an everything if -d perf isn't on */
2142 {
2143 dt_times_t end;
2144 dt_get_times(&end);
2145 char buf[140]; /* Arbitrary size, should be lots big enough for everything used in DT */
2146 snprintf(buf, sizeof(buf), "%s took %.3f secs (%.3f CPU)", prefix, end.clock - start->clock,
2147 end.user - start->user);
2148 dt_print(DT_DEBUG_PERF, "%s\n", buf);
2149 }
2150}
2151
2152void dt_show_times_f(const dt_times_t *start, const char *prefix, const char *suffix, ...)
2153{
2154 /* Skip all the calculations an everything if -d perf isn't on */
2156 {
2157 dt_times_t end;
2158 dt_get_times(&end);
2159 char buf[160]; /* Arbitrary size, should be lots big enough for everything used in DT */
2160 const int n = snprintf(buf, sizeof(buf), "%s took %.3f secs (%.3f CPU) ", prefix, end.clock - start->clock,
2161 end.user - start->user);
2162 if(n < sizeof(buf) - 1)
2163 {
2164 va_list ap;
2165 va_start(ap, suffix);
2166 vsnprintf(buf + n, sizeof(buf) - n, suffix, ap);
2167 va_end(ap);
2168 }
2169 dt_print(DT_DEBUG_PERF, "%s\n", buf);
2170 }
2171}
2172
2173#if defined(_WIN32)
2174#include <windows.h>
2175
2177{
2178 MEMORYSTATUSEX status;
2179 status.dwLength = sizeof(status);
2180 if(GlobalMemoryStatusEx(&status))
2181 return (size_t)status.ullAvailPhys; // Includes reclaimable
2182 else
2183 return 0;
2184}
2185
2186#elif defined(__APPLE__)
2187#include <mach/mach.h>
2188
2189static size_t _probe_system_available_mem(void)
2190{
2191 mach_port_t host = mach_host_self();
2192 vm_statistics64_data_t vmstat;
2193 mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
2194 if(host_statistics64(host, HOST_VM_INFO64, (host_info64_t)&vmstat, &count) != KERN_SUCCESS) return 0;
2195
2196 size_t page_size;
2197 host_page_size(host, &page_size);
2198
2199 // Free + inactive (reclaimable)
2200 return (vmstat.free_count + vmstat.inactive_count) * page_size;
2201}
2202
2203#elif defined(__linux__)
2204#include <string.h>
2205
2206// A cgroup v2 memory.max limit (container, Flatpak sandbox, systemd slice) caps us
2207// before the system-wide MemAvailable does: the kernel enforces it with a per-cgroup
2208// OOM kill while /proc/meminfo still reports plenty of available RAM. Walk our own
2209// cgroup path up to the root and report the tightest limit (out_limit) and the
2210// tightest remaining slack including reclaimable pages (out_available), each
2211// SIZE_MAX when no level sets a limit.
2212static void _probe_cgroup_v2(size_t *out_limit, size_t *out_available)
2213{
2214 size_t tightest = SIZE_MAX;
2215 size_t tightest_limit = SIZE_MAX;
2216 *out_limit = SIZE_MAX;
2217 *out_available = SIZE_MAX;
2218
2219 FILE *f = g_fopen("/proc/self/cgroup", "r");
2220 if(IS_NULL_PTR(f)) return;
2221
2222 char line[512];
2223 char path[512] = "";
2224 while(fgets(line, sizeof(line), f))
2225 {
2226 // cgroup v2 unified hierarchy entry: "0::/user.slice/..."
2227 if(!strncmp(line, "0::", 3))
2228 {
2229 g_strlcpy(path, line + 3, sizeof(path));
2230 char *newline = strchr(path, '\n');
2231 if(newline) *newline = '\0';
2232 break;
2233 }
2234 }
2235 fclose(f);
2236 if(path[0] == '\0') return;
2237
2238 while(TRUE)
2239 {
2240 char file[1024];
2241 snprintf(file, sizeof(file), "/sys/fs/cgroup%s/memory.max", path);
2242 FILE *fmax = g_fopen(file, "r");
2243 if(fmax)
2244 {
2245 // The file contains either a byte count or the literal "max" (no limit),
2246 // which simply fails the numeric scan.
2247 unsigned long long max_bytes = 0;
2248 if(fscanf(fmax, "%llu", &max_bytes) == 1 && max_bytes > 0)
2249 {
2250 unsigned long long cur_bytes = max_bytes;
2251 snprintf(file, sizeof(file), "/sys/fs/cgroup%s/memory.current", path);
2252 FILE *fcur = g_fopen(file, "r");
2253 if(fcur)
2254 {
2255 if(fscanf(fcur, "%llu", &cur_bytes) != 1) cur_bytes = max_bytes;
2256 fclose(fcur);
2257 }
2258
2259 // memory.current still charges pages the kernel could drop at will: the page
2260 // cache and — critically for us — our own MADV_FREE'd arena pages, which land
2261 // on the cgroup's inactive file LRU. Count that list as available, the same
2262 // way system-wide MemAvailable does, or the slack of a busy cgroup would read
2263 // ~0 even though our own freed cache is fully reclaimable.
2264 unsigned long long inactive_file = 0;
2265 snprintf(file, sizeof(file), "/sys/fs/cgroup%s/memory.stat", path);
2266 FILE *fstat = g_fopen(file, "r");
2267 if(fstat)
2268 {
2269 char stat_line[256];
2270 while(fgets(stat_line, sizeof(stat_line), fstat))
2271 if(sscanf(stat_line, "inactive_file %llu", &inactive_file) == 1) break;
2272 fclose(fstat);
2273 }
2274
2275 const size_t slack = (max_bytes > cur_bytes) ? (size_t)(max_bytes - cur_bytes) : 0;
2276 const size_t available = slack + (size_t)inactive_file;
2277 if(available < tightest) tightest = available;
2278 if((size_t)max_bytes < tightest_limit) tightest_limit = (size_t)max_bytes;
2279 }
2280 fclose(fmax);
2281 }
2282
2283 char *slash = strrchr(path, '/');
2284 if(IS_NULL_PTR(slash) || slash == path) break;
2285 *slash = '\0';
2286 }
2287
2288 *out_limit = tightest_limit;
2289 *out_available = tightest;
2290}
2291
2292static size_t _probe_system_available_mem(void)
2293{
2294 FILE *f = g_fopen("/proc/meminfo", "r");
2295 if(IS_NULL_PTR(f)) return 0;
2296
2297 char line[256];
2298 size_t available_kb = 0;
2299 size_t available = 0;
2300
2301 while(fgets(line, sizeof(line), f))
2302 {
2303 if(sscanf(line, "MemAvailable: %" G_GSIZE_FORMAT " kB", &available_kb) == 1)
2304 {
2305 available = available_kb * 1024; // kB to bytes
2306 break;
2307 }
2308 }
2309 fclose(f);
2310
2311 size_t cgroup_limit = SIZE_MAX;
2312 size_t cgroup_available = SIZE_MAX;
2313 _probe_cgroup_v2(&cgroup_limit, &cgroup_available);
2314 if(cgroup_available != SIZE_MAX) available = MIN(available, cgroup_available);
2315
2316 return available;
2317}
2318
2319#else
2320static size_t _probe_system_available_mem(void)
2321{
2322 return 0; // Unsupported platform: 0 = "no information", not "out of memory"
2323}
2324#endif
2325
2326/* Short-lived cache of the system probe. Measured at 61 µs per probe (16 µs for
2327 * /proc/meminfo, 45 µs walking the cgroup tree), which the tiling planners alone
2328 * would pay ~30 times per pipeline run — 1.8 ms of a 16 ms realtime frame. The
2329 * cached value is at most DT_SYS_MEM_PROBE_PERIOD_US old; callers that just changed
2330 * the situation themselves (the pixelpipe pressure valve, right after shedding
2331 * cache) call dt_invalidate_system_available_mem() to force the next read to be
2332 * ground truth. */
2333#define DT_SYS_MEM_PROBE_PERIOD_US 50000 // 50 ms
2334
2336static size_t _sys_mem_probe_value = 0;
2337static gint64 _sys_mem_probe_time_us = 0;
2338
2340{
2341 g_mutex_lock(&_sys_mem_probe_lock);
2342
2343 const gint64 now = g_get_monotonic_time();
2345 {
2346 const size_t cached = _sys_mem_probe_value;
2347 g_mutex_unlock(&_sys_mem_probe_lock);
2348 return cached;
2349 }
2350
2351 const size_t available = _probe_system_available_mem();
2352 _sys_mem_probe_value = available;
2354 g_mutex_unlock(&_sys_mem_probe_lock);
2355 return available;
2356}
2357
2359{
2360 g_mutex_lock(&_sys_mem_probe_lock);
2362 g_mutex_unlock(&_sys_mem_probe_lock);
2363}
2364
2365// Tightest container/cgroup memory limit this process runs under, SIZE_MAX when
2366// uncontained. This is the envelope the kernel actually OOM-enforces on us,
2367// regardless of how much RAM the machine has.
2368static size_t _get_container_mem_limit(void)
2369{
2370#if defined(__linux__)
2371 size_t cgroup_limit = SIZE_MAX;
2372 size_t cgroup_available = SIZE_MAX;
2373 _probe_cgroup_v2(&cgroup_limit, &cgroup_available);
2374 return cgroup_limit;
2375#else
2376 return SIZE_MAX;
2377#endif
2378}
2379
2380
2382{
2383 return dt_conf_get_int("worker_threads");
2384}
2385
2387{
2388 size_t cache_used = 0;
2389 size_t cache_max = 0;
2390 dt_dev_pixelpipe_cache_get_usage(&cache_used, &cache_max);
2391 const size_t budget_left = cache_max - cache_used;
2392
2393 // The budget is only a startup-time plan: cap it by what the system can actually
2394 // back right now without dropping under the pressure floor (issue #1083), so
2395 // tiled modules plan tile sizes that will survive the allocation-time pressure
2396 // valve in pixelpipe_cache.c. Half of our own current cache usage counts as
2397 // room too: it is LRU-evictable, and the valve will evict it on demand — our own
2398 // cache must never be what forces a module into tiling.
2399 const size_t sys_available = dt_get_system_available_mem();
2400 if(sys_available == 0) return budget_left; // no information on this platform
2401
2402 const size_t pressure_floor = dt_get_memory_pressure_floor();
2403 const size_t sys_room = ((sys_available > pressure_floor) ? sys_available - pressure_floor : 0)
2404 + cache_used / 2;
2405 return MIN(budget_left, sys_room);
2406}
2407
2409{
2411}
2412
2414{
2416}
2417
2422
2423void dt_configure_runtime_performance(dt_sys_resources_t *resources, gboolean init_gui)
2424{
2425 size_t physical_memory = _get_total_memory() * 1024;
2426
2427 // A container/cgroup memory limit (Flatpak sandbox, systemd slice, docker...) is
2428 // the envelope the kernel actually OOM-enforces on us: inside it, the machine's
2429 // physical RAM is irrelevant, so it IS our total memory for budgeting purposes.
2430 const size_t container_limit = _get_container_mem_limit();
2431 if(container_limit != SIZE_MAX && (physical_memory == 0 || container_limit < physical_memory))
2432 {
2434 "[MEMORY CONFIGURATION] container/cgroup memory limit detected: %" G_GSIZE_FORMAT
2435 " MiB — using it as the total RAM\n", container_limit / (1024 * 1024));
2436 physical_memory = container_limit;
2437 }
2438
2439 resources->total_memory = physical_memory;
2440
2441 const size_t threads = darktable.num_openmp_threads;
2442 const size_t mem = resources->total_memory / (1024 * 1024);
2443 const size_t bits = CHAR_BIT * sizeof(void *);
2444 const gboolean sufficient = (mem >= 4096 && threads >= 2);
2445
2446 dt_print(DT_DEBUG_MEMORY, "[MEMORY CONFIGURATION] found a %s %" G_GSIZE_FORMAT "-bit system with %" G_GSIZE_FORMAT " cores\n",
2447 (sufficient) ? "sufficient" : "low performance", bits, threads);
2448
2449 // Override RAM detection with user config
2450 if(dt_conf_get_int64("host_memory_limit") > 0)
2451 resources->total_memory = dt_conf_get_int64("host_memory_limit") * 1024 * 1024;
2452
2453 // A host_memory_limit above the physical RAM would make us plan caches the system
2454 // can never back: the OS OOM-killer, not us, would then enforce the difference by
2455 // killing the app without a message (issue #1083). The user limit can only shrink
2456 // the detected RAM, never grow it.
2457 if(physical_memory > 0 && resources->total_memory > physical_memory)
2458 {
2459 fprintf(stderr,
2460 "MEMORY WARNING: host_memory_limit (%" G_GSIZE_FORMAT " MiB) exceeds the physical RAM "
2461 "(%" G_GSIZE_FORMAT " MiB) and was clamped to it.\n",
2462 resources->total_memory / (1024 * 1024), physical_memory / (1024 * 1024));
2463 resources->total_memory = physical_memory;
2464 }
2465
2466 // Keep OS headroom between 1 GB and a third of the system RAM
2467 resources->headroom_memory = dt_conf_get_int64("memory_os_headroom") * 1024 * 1024;
2468 resources->headroom_memory
2469 = CLAMP(resources->headroom_memory, 1024 * 1024 * 1024, resources->total_memory / 3);
2470
2471 // Runtime memory-pressure floor: while running, whenever the SYSTEM-wide available
2472 // RAM drops below this — whether we or another application consumed it — the
2473 // pixelpipe cache sheds entries and returns their pages to the OS instead of
2474 // letting the system OOM-killer pick a victim (issue #1083). This is a live
2475 // safety net on top of the static budgets below, which are only plans.
2476 // Conf default 0 = auto: half the OS headroom.
2477 // The bounds scale with the envelope: on a normal machine the floor stays within
2478 // [512 MB, total/4], but inside a small container keeping 512 MB free would eat
2479 // the whole allotment, so the lower bound relaxes to total/8 there.
2480 // An ABSOLUTE reserve, not a fraction of anything. What the kernel and other
2481 // applications need in order to keep breathing does not scale with how much RAM the
2482 // machine has: 200 MiB is about as useful on a 4 GB laptop as on a 128 GB workstation.
2483 //
2484 // Deriving it from the headroom (previously half of it) made the floor grow with the
2485 // machine, which is backwards -- a 31 GB system ended up reserving 5175 MiB, so once
2486 // free RAM dipped under that the pixelpipe cache refused EVERY allocation, including
2487 // ones of a few kilobytes, and the application could not even start. Reserving a large
2488 // share of a large machine also wastes precisely the memory the user bought it for.
2489 int64_t pressure_floor = dt_conf_get_int64("memory_pressure_floor") * 1024 * 1024;
2490 if(pressure_floor <= 0) pressure_floor = DT_MEMORY_PRESSURE_FLOOR_DEFAULT;
2491 // Only a sanity clamp for hand-set values: never negative, and never so large on a
2492 // small machine that the floor swallows the whole envelope.
2493 resources->pressure_floor_memory = CLAMP(pressure_floor, 0, (int64_t)resources->total_memory / 4);
2494
2495 // Keep mipmap cache between 256 MB and a sixth of the system RAM
2496 resources->mipmap_memory = dt_conf_get_int64("memory_mipmap_cache") * 1024 * 1024;
2497 resources->mipmap_memory
2498 = CLAMP(resources->mipmap_memory, 256 * 1024 * 1024, resources->total_memory / 6);
2499
2500 // 6 temp copies of 24 Mpx RGBA float32 at full res
2501 const size_t min_pipecache_memory = 6 * 6000 * 4000 * 4 * sizeof(float);
2502
2503 // Pipeline cache gets the rest. Need to cast as int otherwise, negative values saturate the uint64 to MAX_UINT or something
2504 resources->pixelpipe_memory = MAX((int64_t)resources->total_memory
2505 - (int64_t)resources->mipmap_memory
2506 - (int64_t)resources->headroom_memory,
2507 (int64_t)min_pipecache_memory);
2508
2509 if(resources->pixelpipe_memory == min_pipecache_memory)
2510 {
2511 fprintf(stderr,
2512 "MEMORY WARNING: your pixelpipe cache allocated RAM is too small for your typical raw size.\n"
2513 "MEMORY WARNING: reduce your OS/apps headroom, or your thumbnail cache size.\n"
2514 "MEMORY WARNING: you may also simply need more RAM or need to reset the config key host_memory.\n"
2515 "MEMORY WARNING: we shrank the thumbnails cache to the bare minimum to leave enough space for pixelpipe cache.\n");
2516 resources->mipmap_memory = MAX((int64_t)resources->total_memory
2517 - (int64_t)resources->headroom_memory
2518 - (int64_t)resources->pixelpipe_memory,
2519 (int64_t)128 * 1024 * 1024);
2520 }
2521
2522 // Print
2523 dt_print(DT_DEBUG_MEMORY | DT_DEBUG_CACHE, _("[MEMORY CONFIGURATION] Total system RAM: %" G_GSIZE_FORMAT " MiB\n"),
2524 resources->total_memory / (1024 * 1024));
2525
2526 dt_print(DT_DEBUG_MEMORY | DT_DEBUG_CACHE, _("[MEMORY CONFIGURATION] OS & Apps RAM headroom: %" G_GSIZE_FORMAT " MiB\n"),
2527 resources->headroom_memory / (1024 * 1024));
2528
2529 dt_print(DT_DEBUG_MEMORY | DT_DEBUG_CACHE, _("[MEMORY CONFIGURATION] Lightable thumbnails cache size: %" G_GSIZE_FORMAT " MiB\n"),
2530 resources->mipmap_memory / (1024 * 1024));
2531
2532 dt_print(DT_DEBUG_MEMORY | DT_DEBUG_CACHE, _("[MEMORY CONFIGURATION] Pixelpipe cache size: %" G_GSIZE_FORMAT " MiB\n"),
2533 resources->pixelpipe_memory / (1024 * 1024));
2534
2535 dt_print(DT_DEBUG_MEMORY | DT_DEBUG_CACHE, _("[MEMORY CONFIGURATION] System memory pressure floor: %" G_GSIZE_FORMAT " MiB\n"),
2536 resources->pressure_floor_memory / (1024 * 1024));
2537
2538 dt_print(DT_DEBUG_MEMORY | DT_DEBUG_CACHE, _("[MEMORY CONFIGURATION] Worker threads: %i\n"), dt_worker_threads());
2539
2540 if(resources->total_memory < resources->headroom_memory + resources->mipmap_memory + resources->pixelpipe_memory)
2541 dt_control_log(_("CRITICAL WARNING: Ansel will not be able to use the RAM you allocated it.\n"
2542 "Review your memory settings or add more RAM to your system."));
2543}
2544
2545int dt_capabilities_check(char *capability)
2546{
2547 for(GList *capabilities = darktable.capabilities; capabilities; capabilities = g_list_next(capabilities))
2548 {
2549 if(!strcmp(capabilities->data, capability))
2550 {
2551 return TRUE;
2552 }
2553 }
2554 return FALSE;
2555}
2556
2557
2558void dt_capabilities_add(char *capability)
2559{
2561
2562 if(!dt_capabilities_check(capability))
2563 darktable.capabilities = g_list_append(darktable.capabilities, capability);
2564
2566}
2567
2568
2577
2578
2584
2585
2587{
2588 fprintf(stdout, "[memory] Currently-free and reclaimable memory detected: %lu MiB\n", dt_get_system_available_mem() / (1024 * 1024));
2589
2590#if defined(__linux__)
2591 char *line = NULL;
2592 size_t len = 128;
2593 char vmsize[64];
2594 char vmpeak[64];
2595 char vmrss[64];
2596 char vmhwm[64];
2597 FILE *f;
2598
2599 char pidstatus[128];
2600 snprintf(pidstatus, sizeof(pidstatus), "/proc/%u/status", (uint32_t)getpid());
2601
2602 f = g_fopen(pidstatus, "r");
2603 if(IS_NULL_PTR(f)) return;
2604
2605 /* read memory size data from /proc/pid/status */
2606 while(getline(&line, &len, f) != -1)
2607 {
2608 if(!strncmp(line, "VmPeak:", 7))
2609 g_strlcpy(vmpeak, line + 8, sizeof(vmpeak));
2610 else if(!strncmp(line, "VmSize:", 7))
2611 g_strlcpy(vmsize, line + 8, sizeof(vmsize));
2612 else if(!strncmp(line, "VmRSS:", 6))
2613 g_strlcpy(vmrss, line + 8, sizeof(vmrss));
2614 else if(!strncmp(line, "VmHWM:", 6))
2615 g_strlcpy(vmhwm, line + 8, sizeof(vmhwm));
2616 }
2617 dt_free(line);
2618 fclose(f);
2619
2620 fprintf(stderr, "[memory] max address space (vmpeak): %15s"
2621 "[memory] cur address space (vmsize): %15s"
2622 "[memory] max used memory (vmhwm ): %15s"
2623 "[memory] cur used memory (vmrss ): %15s",
2624 vmpeak, vmsize, vmhwm, vmrss);
2625
2626#elif defined(__APPLE__)
2627 struct task_basic_info t_info;
2628 mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
2629
2630 if(KERN_SUCCESS != task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count))
2631 {
2632 fprintf(stderr, "[memory] task memory info unknown.\n");
2633 return;
2634 }
2635
2636 // Report in kB, to match output of /proc on Linux.
2637 fprintf(stderr, "[memory] max address space (vmpeak): %15s\n"
2638 "[memory] cur address space (vmsize): %12llu kB\n"
2639 "[memory] max used memory (vmhwm ): %15s\n"
2640 "[memory] cur used memory (vmrss ): %12llu kB\n",
2641 "unknown", (uint64_t)t_info.virtual_size / 1024, "unknown", (uint64_t)t_info.resident_size / 1024);
2642#elif defined (_WIN32)
2643 //Based on: http://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process
2644 MEMORYSTATUSEX memInfo;
2645 memInfo.dwLength = sizeof(MEMORYSTATUSEX);
2646 GlobalMemoryStatusEx(&memInfo);
2647 // DWORDLONG totalVirtualMem = memInfo.ullTotalPageFile;
2648
2649 // Virtual Memory currently used by current process:
2650 PROCESS_MEMORY_COUNTERS_EX pmc;
2651 GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS *)&pmc, sizeof(pmc));
2652 size_t virtualMemUsedByMe = pmc.PagefileUsage;
2653 size_t virtualMemUsedByMeMax = pmc.PeakPagefileUsage;
2654
2655 // Max Physical Memory currently used by current process
2656 size_t physMemUsedByMeMax = pmc.PeakWorkingSetSize;
2657
2658 // Physical Memory currently used by current process
2659 size_t physMemUsedByMe = pmc.WorkingSetSize;
2660
2661
2662 fprintf(stderr, "[memory] max address space (vmpeak): %12llu kB\n"
2663 "[memory] cur address space (vmsize): %12llu kB\n"
2664 "[memory] max used memory (vmhwm ): %12llu kB\n"
2665 "[memory] cur used memory (vmrss ): %12llu Kb\n",
2666 virtualMemUsedByMeMax / 1024, virtualMemUsedByMe / 1024, physMemUsedByMeMax / 1024,
2667 physMemUsedByMe / 1024);
2668
2669#else
2670 fprintf(stderr, "dt_print_mem_usage() currently unsupported on this platform\n");
2671#endif
2672}
2673
2674void dt_concat_path_file(char destination[DT_PATH_MAX], const char path[DT_PATH_MAX], const char *const file)
2675{
2676 g_strlcpy(destination, path, sizeof(char) * DT_PATH_MAX);
2677 g_strlcat(destination, G_DIR_SEPARATOR_S, sizeof(char) * DT_PATH_MAX);
2678 g_strlcat(destination, file, sizeof(char) * DT_PATH_MAX);
2679}
2680
2681// clang-format off
2682// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
2683// vim: shiftwidth=2 expandtab tabstop=2 cindent
2684// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
2685// 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:701
void dt_control_init(dt_control_t *s)
Definition control.c:89
void dt_toast_log(const char *msg,...)
Definition control.c:871
void dt_control_set_mouse_over_id(int32_t value)
Definition control.c:994
void dt_control_log(const char *msg,...)
Definition control.c:824
void dt_control_queue_redraw_center()
Request a redraw of the centre view.
Definition control.c:924
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_run_in_background(void)
Definition crawler.c:569
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:2125
void dt_show_times(const dt_times_t *start, const char *prefix)
Definition darktable.c:2138
static void _preferences_changed(gpointer instance, gpointer user_data)
Definition darktable.c:815
void dt_invalidate_system_available_mem(void)
Definition darktable.c:2358
int dt_get_num_openmp_threads(void)
Number of OpenMP threads the application decided to use.
Definition darktable.c:518
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:2339
struct dt_develop_t * dt_dev_get_global(void)
Definition darktable.c:528
struct dt_undo_t * dt_undo_get_global(void)
Definition darktable.c:611
void dt_cleanup()
Definition darktable.c:1864
double dt_get_start_wtime(void)
Definition darktable.c:2080
int dt_worker_threads()
Definition darktable.c:2381
int32_t dt_get_debug_flags(void)
Definition darktable.c:2085
static void _database_renamed(const char *new_library_name)
Definition darktable.c:710
struct dt_dbus_t * dt_dbus_get_global(void)
Definition darktable.c:641
static gint64 _sys_mem_probe_time_us
Definition darktable.c:2337
static void _dt_drain_main_context(const int max_iters)
Definition darktable.c:1856
GList * dt_iop_get_modules_so(void)
Definition darktable.c:533
struct dt_lib_t * dt_lib_get_global(void)
Definition darktable.c:621
static void _doc_screenshot_lib_modules(void *inventory)
Definition darktable.c:839
static void _pipeline_message(const char *message)
Definition darktable.c:742
static void _image_imported(const int32_t imgid)
Definition darktable.c:755
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:2586
static const dt_pixelpipe_cache_observer_t _pixelpipe_cache_observer
Definition darktable.c:671
static dt_mipmap_cache_settings_t _mipmap_settings_from_conf(void)
Definition darktable.c:683
struct dt_view_manager_t * dt_view_manager_get_global(void)
Definition darktable.c:599
static size_t _sys_mem_probe_value
Definition darktable.c:2336
static void _pixelpipe_cache_warn(const char *message)
Definition darktable.c:660
void dt_dev_set_global(struct dt_develop_t *dev)
Definition darktable.c:543
static dt_pthread_mutex_t _main_message_lock
Definition darktable.c:581
dt_pthread_mutex_t * dt_pipeline_threadsafe_mutex(void)
Definition darktable.c:604
void * dt_alloc_align(size_t size)
Allocate cacheline-aligned memory.
Definition darktable.c:508
GList * dt_ioppr_get_iop_order_rules_global(void)
Definition darktable.c:538
char * dt_get_main_message_copy(void)
Definition darktable.c:583
void dt_capabilities_remove(char *capability)
Definition darktable.c:2569
static void _metadata_notify(const dt_metadata_notice_t kind, const char *message)
Definition darktable.c:723
size_t dt_get_memory_pressure_floor(void)
Definition darktable.c:2418
int dt_init(int argc, char *argv[], const gboolean init_gui, const gboolean load_data)
Definition darktable.c:885
struct dt_imageio_t * dt_imageio_get_global(void)
Definition darktable.c:626
size_t dt_get_total_mem(void)
Definition darktable.c:2413
static void _metadata_geotags_changed(const GList *imgs)
Definition darktable.c:749
struct dt_l10n_t * dt_l10n_get_global(void)
Definition darktable.c:636
#define DT_SYS_MEM_PROBE_PERIOD_US
Definition darktable.c:2333
static const char * _history_operation_name(const char *operation)
Definition darktable.c:796
size_t dt_get_mipmap_mem()
Definition darktable.c:2408
struct dt_gui_gtk_t * dt_gui_get_global(void)
Definition darktable.c:523
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:665
static void _history_toast(const char *message)
Definition darktable.c:766
struct dt_control_signal_t * dt_control_signal_get_global(void)
Definition darktable.c:616
static void _history_notify(const char *message)
Definition darktable.c:761
static size_t _get_total_memory()
Definition darktable.c:459
int32_t dt_get_signal_debug_acts(void)
Definition darktable.c:2090
static void _pipeline_busy(const char *message_or_null)
Definition darktable.c:734
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:2113
struct dt_points_t * dt_points_get_global(void)
Definition darktable.c:631
struct dt_control_t * dt_control_get_global(void)
Definition darktable.c:651
static size_t _get_container_mem_limit(void)
Definition darktable.c:2368
void dt_configure_runtime_performance(dt_sys_resources_t *resources, gboolean init_gui)
Definition darktable.c:2423
void dt_gui_set_themes(GList *themes)
Definition darktable.c:553
void dt_capabilities_add(char *capability)
Definition darktable.c:2558
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:2674
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
Definition darktable.c:646
static GMutex _sys_mem_probe_lock
Definition darktable.c:2335
gboolean dt_supported_image(const gchar *filename)
Definition darktable.c:381
static void _doc_screenshot_iop_modules(void *inventory)
Definition darktable.c:851
void dt_capabilities_cleanup()
Definition darktable.c:2579
static void _history_changed(const dt_history_change_t what)
Definition darktable.c:771
void dt_show_times_f(const dt_times_t *start, const char *prefix, const char *suffix,...)
Definition darktable.c:2152
GList * dt_gui_get_themes(void)
Definition darktable.c:548
static gboolean _presets_can_autoapply(const gchar *operation)
Definition darktable.c:802
size_t dt_get_available_mem()
Definition darktable.c:2386
int dt_capabilities_check(char *capability)
Definition darktable.c:2545
static int usage(const char *argv0)
Definition darktable.c:261
static void _database_settings_from_conf(void)
Definition darktable.c:696
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:2100
gboolean dt_get_signal_debug(const int signal)
Definition darktable.c:2095
void dt_set_main_message(char *message)
Definition darktable.c:591
static void _metadata_tags_changed(void)
Definition darktable.c:715
#define CHKSIGDBG(sig)
static size_t _probe_system_available_mem(void)
Definition darktable.c:2176
static void _xmp_mode_preferences_changed(gpointer instance, gpointer user_data)
Definition darktable.c:869
static void _updates_notify(const char *version, const char *url)
Definition darktable.c:880
static void _history_images_changed(const GList *imgs)
Definition darktable.c:789
void dt_database_set_renamed_handler(dt_database_renamed_handler_t handler)
Definition database.c:3627
void dt_database_optimize(void)
Definition database.c:4050
void dt_database_set_settings(const dt_database_settings_t *settings)
Definition database.c:3666
char ** dt_database_snaps_to_remove(void)
Definition database.c:4408
void dt_database_close(void)
Definition database.c:3749
gboolean dt_database_snapshot(void)
Definition database.c:4118
void dt_database_perform_maintenance(void)
Definition database.c:3883
void dt_database_cleanup_busy_statements(void)
Definition database.c:3861
gboolean dt_database_maybe_maintenance(const gboolean closing_time)
Definition database.c:3970
dt_database_open_result_t dt_database_open(const dt_database_params_t *params)
Definition database.c:3632
gboolean dt_database_maybe_snapshot(void)
Definition database.c:4227
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:409
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:1732
const gchar * dt_iop_get_localized_name(const gchar *op)
Definition imageop.c:1757
void dt_iop_load_modules_so(void)
Definition imageop.c:1073
void dt_iop_unload_modules_so()
Definition imageop.c:1163
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:251
dt_pthread_mutex_t run_mutex
Definition control.h:248
int32_t running
Definition control.h:246
dt_pthread_mutex_t log_mutex
Definition control.h:232
const char * alternative
Definition database.h:60
GDBusConnection * dbus_connection
Definition dbus.h:39
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)