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