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
83
84#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
85#include <malloc.h>
86#endif
87#ifdef __APPLE__
88#include <sys/malloc.h>
89#endif
90
91#include "common/collection.h"
92#include "common/colorspaces.h"
93#include "common/colorlabels.h"
94#include "common/darktable.h"
95#include "common/datetime.h"
96#include "common/exif.h"
97#include "common/history.h"
99#include "common/selection.h"
101#include "common/sentry.h"
102#include "common/telemetry.h"
104#include "bauhaus/bauhaus.h"
105#include "gui/presets.h"
106#include "gui/splash.h"
107
108#include "common/file_location.h"
109#include "common/film.h"
110#include "common/folder_survey.h"
111#include "common/grealpath.h"
112#include "common/image.h"
113#include "common/image_cache.h"
115#include "common/iop_order.h"
116#include "common/l10n.h"
117#include "common/metadata.h"
118#include "common/mipmap_cache.h"
119#include "common/noiseprofiles.h"
120#include "common/opencl.h"
121#include "common/points.h"
123#include "common/tags.h"
124#include "common/styles.h"
125#include "common/undo.h"
126#include "common/fp_mode.h"
127#include "control/conf.h"
128#include "control/control.h"
129#include "control/crawler.h"
132#include "control/signal.h"
133#include "develop/blend.h"
135#include "develop/imageop.h"
136#include "develop/supervisor.h"
137
138#include "gui/gtk.h"
139#include "gui/gui_throttle.h"
140#include "gui/guides.h"
141#include "gui/presets.h"
142#include "libs/lib.h"
143#include "views/view.h"
144#include "conf_gen.h"
145
146#include <errno.h>
147#if !defined(_WIN32) && !defined(__APPLE__)
148#include <fontconfig/fontconfig.h>
149#endif
150#include <glib.h>
151#include <glib/gstdio.h>
152#include <pango/pangocairo.h>
153#include <stdint.h>
154#include <stdio.h>
155#include <stdlib.h>
156#include <string.h>
157#include <sys/param.h>
158#include <sys/types.h>
159#include <unistd.h>
160#include <locale.h>
161#include <limits.h>
162
163#if defined(__x86_64__) || defined(__i386__)
164#include <xmmintrin.h>
165#endif
166
167#ifdef HAVE_GRAPHICSMAGICK
168#include <magick/api.h>
169#elif defined HAVE_IMAGEMAGICK
170#include <MagickWand/MagickWand.h>
171#endif
172
173#include "dbus.h"
174
175#if defined(__SUNOS__)
176#include <sys/varargs.h>
177#endif
178
179#ifdef _OPENMP
180#include <omp.h>
181#endif
182
184
185#if !defined(_WIN32) && !defined(__APPLE__)
186typedef struct _PangoFcFontMap PangoFcFontMap;
187extern GType pango_fc_font_map_get_type(void);
189#endif
190
197static GLogWriterOutput _gtk_log_writer_filter(GLogLevelFlags log_level, const GLogField *fields,
198 gsize n_fields, gpointer user_data)
199{
200 const gchar *message = NULL;
201
202 for(gsize k = 0; k < n_fields; k++)
203 {
204 if(g_strcmp0(fields[k].key, "MESSAGE")) continue;
205
206 message = fields[k].value;
207 break;
208 }
209
210 // Silence only warnings/errors that come from default Adwaita CSS or desktop theme
211 // because there is nothing we can do about those.
212 // Yes, default Adwaita GTK CSS is still using deprecated GTK stuff in 2026...
213 // Even those morons can't keep up with the pace of their own deprecations.
214 if(message)
215 {
216 if(!g_strcmp0(message, "Unable to load dot from the cursor theme"))
217 return G_LOG_WRITER_HANDLED;
218
219 if(g_str_has_prefix(message, "Theme parsing error:")
220 && g_str_has_suffix(message, "The :insensitive pseudo-class is deprecated. Use :disabled instead."))
221 return G_LOG_WRITER_HANDLED;
222
223 if(g_str_has_prefix(message, "Theme parsing error:")
224 && g_str_has_suffix(message, "The :inconsistent pseudo-class is deprecated. Use :indeterminate instead."))
225 return G_LOG_WRITER_HANDLED;
226 }
227
228 return g_log_writer_default(log_level, fields, n_fields, user_data);
229}
230
231static int usage(const char *argv0)
232{
233#ifdef _WIN32
234 char *logfile = g_build_filename(g_get_user_cache_dir(), "ansel", "ansel-log.txt", NULL);
235#endif
236 // clang-format off
237 printf("usage: %s [options] [IMG_1234.{RAW,..}|image_folder/]\n", argv0);
238 printf("\n");
239 printf("options:\n");
240 printf("\n");
241 printf(" --cachedir <user cache directory>\n");
242 printf(" --conf <key>=<value>\n");
243 printf(" --configdir <user config directory>\n");
244 printf(" -d {all,cache,camctl,camsupport,colorprofile,control,demosaic,dev,gtk,history,imageio,import,\n");
245 printf(" input,ioporder,lighttable,lua,masks,memory,nan,nocache_reuse,opencl,params,\n");
246 printf(" perf,pipe,pipecache,print,pwstorage,signal,sql,shortcuts,tiling,undo,verbose}\n");
247 printf(" --d-signal <signal> \n");
248 printf(" --d-signal-act <all,raise,connect,disconnect");
249 // clang-format on
250#ifdef DT_HAVE_SIGNAL_TRACE
251 printf(",print-trace");
252#endif
253 printf(">\n");
254 printf(" --datadir <data directory>\n");
255#ifdef HAVE_OPENCL
256 printf(" --disable-opencl\n");
257#endif
258 printf(" -h, --help");
259#ifdef _WIN32
260 printf(", /?");
261#endif
262 printf("\n");
263 printf(" --library <library file>\n");
264 printf(" --localedir <locale directory>\n");
265 printf(" --moduledir <module directory>\n");
266 printf(" --noiseprofiles <noiseprofiles json file>\n");
267 printf(" -t <num openmp threads>\n");
268 printf(" --tmpdir <tmp directory>\n");
269 printf(" --version\n");
270#ifdef _WIN32
271 printf("\n");
272 printf(" note: debug log and output will be written to this file:\n");
273 printf(" %s\n", logfile);
274#endif
275
276#ifdef _WIN32
277 dt_free(logfile);
278#endif
279
280 return 1;
281}
282
284{
285 char ver[100] = { 0 };
286 g_strlcpy(ver, darktable_package_string, sizeof(ver));
287 int count = -1;
288 char *start = ver;
289 for(char *p = ver; *p; p++)
290 {
291 // first look for a number
292 if(count == -1)
293 {
294 if(*p >= '0' && *p <= '9')
295 {
296 count++;
297 start = p;
298 }
299 }
300 // then check for <major>.<minor>
301 else
302 {
303 if(*p == '.' || *p == '+') count++;
304 if(count == 2)
305 {
306 *p = '\0';
307 break;
308 }
309 }
310 }
311 return g_strdup(start);
312}
313
314const char *dt_session_id(void)
315{
316 // Random per-run UUID, generated once and shared by crash reporting and usage
317 // analytics so a single session can be correlated across Sentry and PostHog.
318 static gchar *id = NULL;
319 static gsize init = 0;
320 if(g_once_init_enter(&init))
321 {
322 id = g_uuid_string_random();
323 g_once_init_leave(&init, 1);
324 }
325 return id;
326}
327
328const char *dt_install_id(void)
329{
330 // Anonymous, stable per-installation UUID, persisted in conf and shared by crash
331 // reporting (Sentry user id) and usage analytics (PostHog distinct_id) so the
332 // same user can be de-duplicated across both systems. Created lazily on first use.
333 static gchar *id = NULL;
334 static gsize init = 0;
335 if(g_once_init_enter(&init))
336 {
337 gchar *stored = dt_conf_get_string("telemetry/install_id");
338 if(!stored || !*stored)
339 {
340 g_free(stored);
341 stored = g_uuid_string_random();
342 dt_conf_set_string("telemetry/install_id", stored);
343 }
344 id = stored;
345 g_once_init_leave(&init, 1);
346 }
347 return id;
348}
349
350gboolean dt_supported_image(const gchar *filename)
351{
352 gboolean supported = FALSE;
353 char *ext = g_strrstr(filename, ".");
354 if(IS_NULL_PTR(ext))
355 return FALSE;
356 ext++;
357 for(const char **i = dt_supported_extensions; !IS_NULL_PTR(*i); i++)
358 if(!g_ascii_strncasecmp(ext, *i, strlen(*i)))
359 {
360 supported = TRUE;
361 break;
362 }
363 return supported;
364}
365
366int dt_load_from_string(const gchar *input, gboolean open_image_in_dr, gboolean *single_image)
367{
368 int32_t id = 0;
369 if(IS_NULL_PTR(input) || input[0] == '\0') return 0;
370
371 char *filename = dt_util_normalize_path(input);
372
373 if(IS_NULL_PTR(filename))
374 {
375 dt_control_log(_("found strange path `%s'"), input);
376 return 0;
377 }
378
379 if(g_file_test(filename, G_FILE_TEST_IS_DIR))
380 {
381 // import a directory into a film roll
382 id = dt_film_import(filename);
383 if(id)
384 {
385 dt_film_open(id);
386 dt_ctl_switch_mode_to("lighttable");
387 }
388 else
389 {
390 dt_control_log(_("error loading directory `%s'"), filename);
391 }
392 if(single_image) *single_image = FALSE;
393 }
394 else
395 {
396 // import a single image
397 gchar *directory = g_path_get_dirname((const gchar *)filename);
398 dt_film_t film;
399 const int filmid = dt_film_new(&film, directory);
400 id = dt_image_import(filmid, filename, TRUE);
401 dt_free(directory);
402 if(id)
403 {
404 dt_film_open(filmid);
405 // make sure buffers are loaded (load full for testing)
408 gboolean loaded = (!IS_NULL_PTR(buf.buf));
410 if(!loaded)
411 {
412 id = 0;
413 dt_control_log(_("file `%s' has unknown format!"), filename);
414 }
415 else
416 {
417 if(open_image_in_dr)
418 {
420 dt_ctl_switch_mode_to("darkroom");
421 }
422 }
423 }
424 else
425 {
426 dt_control_log(_("error loading file `%s'"), filename);
427 }
428 if(single_image) *single_image = TRUE;
429 }
430 dt_free(filename);
431 return id;
432}
433
434// Returns total system memory in kiloBytes
435static inline size_t _get_total_memory()
436{
437#if defined(__linux__)
438 FILE *f = g_fopen("/proc/meminfo", "rb");
439 if(IS_NULL_PTR(f)) return 0;
440 size_t mem = 0;
441 char *line = NULL;
442 size_t len = 0;
443 int first = 1, found = 0;
444 // return "MemTotal" or the value from the first line
445 while(!found && getline(&line, &len, f) != -1)
446 {
447 char *colon = strchr(line, ':');
448 if(IS_NULL_PTR(colon)) continue;
449 found = !strncmp(line, "MemTotal:", 9);
450 if(found || first) mem = atol(colon + 1);
451 first = 0;
452 }
453 fclose(f);
454 if(len > 0)
455 {
456 dt_free(line);
457 }
458 return mem;
459#elif defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) \
460 || defined(__OpenBSD__)
461#if defined(__APPLE__)
462 int mib[2] = { CTL_HW, HW_MEMSIZE };
463#elif defined(HW_PHYSMEM64)
464 int mib[2] = { CTL_HW, HW_PHYSMEM64 };
465#else
466 int mib[2] = { CTL_HW, HW_PHYSMEM };
467#endif
468 uint64_t physical_memory;
469 size_t length = sizeof(uint64_t);
470 sysctl(mib, 2, (void *)&physical_memory, &length, (void *)NULL, 0);
471 return physical_memory / 1024;
472#elif defined _WIN32
473 MEMORYSTATUSEX memInfo;
474 memInfo.dwLength = sizeof(MEMORYSTATUSEX);
475 GlobalMemoryStatusEx(&memInfo);
476 return memInfo.ullTotalPhys / (uint64_t)1024;
477#else
478 // assume 2GB until we have a better solution.
479 fprintf(stderr, "Unknown memory size. Assuming 2GB\n");
480 return 2097152;
481#endif
482}
483
484void *dt_alloc_align(size_t size)
485{
487}
488
489int dt_init(int argc, char *argv[], const gboolean init_gui, const gboolean load_data)
490{
491 double start_wtime = dt_get_wtime();
492
493#ifndef _WIN32
494 if(getuid() == 0 || geteuid() == 0)
495 printf(
496 "WARNING: either your user id or the effective user id are 0. are you running darktable as root?\n");
497#endif
498
499 dt_fp_init(DT_FP_MODE_FAST);
500
502
503#ifdef M_MMAP_THRESHOLD
504 mallopt(M_MMAP_THRESHOLD, 128 * 1024); /* use mmap() for large allocations */
505#endif
506
507 // make sure that stack/frame limits are good (musl)
509
510 // init all pointers to 0:
511 memset(&darktable, 0, sizeof(darktable_t));
512
513 darktable.start_wtime = start_wtime;
514
515 darktable.progname = argv[0];
516
517 darktable.main_message = NULL;
518
519 // FIXME: move there into dt_database_t
520 pthread_mutexattr_t recursive_locking;
521 pthread_mutexattr_init(&recursive_locking);
522 pthread_mutexattr_settype(&recursive_locking, PTHREAD_MUTEX_RECURSIVE);
525 // exiv2 and the Adobe XMP toolkit keep process-global state and are not thread-safe; this mutex
526 // serializes all exiv2 access (src/common/exif.cc). Make it recursive so a public exif function can
527 // hold it across its whole critical section while inner helpers (read_metadata_threadsafe) or
528 // re-entrant calls (e.g. variable expansion that reads metadata) re-lock it without deadlocking.
529 dt_pthread_mutex_init(&(darktable.exiv2_threadsafe), &recursive_locking);
533
534 darktable.control = (dt_control_t *)calloc(1, sizeof(dt_control_t));
535
536 // database
537 char *dbfilename_from_command = NULL;
538 char *noiseprofiles_from_command = NULL;
539 char *datadir_from_command = NULL;
540 char *moduledir_from_command = NULL;
541 char *localedir_from_command = NULL;
542 char *tmpdir_from_command = NULL;
543 char *configdir_from_command = NULL;
544 char *cachedir_from_command = NULL;
545 char *kerneldir_from_command = NULL;
546
547#ifdef HAVE_OPENCL
548 gboolean exclude_opencl = FALSE;
549 gboolean print_statistics = (strstr(argv[0], "ansel-cltest") == NULL);
550#endif
551
553#ifdef _OPENMP
555#endif
556
557 darktable.unmuted = 0;
558 gboolean cpu_threads_from_cli = FALSE;
559
560 GSList *config_override = NULL;
561 for(int k = 1; k < argc; k++)
562 {
563#ifdef _WIN32
564 if(!strcmp(argv[k], "/?"))
565 {
566 return usage(argv[0]);
567 }
568#endif
569 if(argv[k][0] == '-')
570 {
571 if(!strcmp(argv[k], "--help") || !strcmp(argv[k], "-h"))
572 {
573 return usage(argv[0]);
574 }
575 else if(!strcmp(argv[k], "--version"))
576 {
577 printf("this is %s\ncopyright (c) 2009-2022 Johannes Hanika, (c) 2022-%s Aurélien Pierre\n" PACKAGE_BUGREPORT "\n\ncompile options:\n"
578 " bit depth is %" G_GSIZE_FORMAT " bit\n"
579#ifdef _DEBUG
580 " debug build\n"
581#else
582 " normal build\n"
583#endif
584#ifdef _OPENMP
585 " OpenMP support enabled\n"
586#else
587 " OpenMP support disabled\n"
588#endif
589
590#ifdef HAVE_OPENCL
591 " OpenCL support enabled\n"
592#else
593 " OpenCL support disabled\n"
594#endif
595
596#ifdef USE_COLORDGTK
597 " Colord support enabled\n"
598#else
599 " Colord support disabled\n"
600#endif
601
602#ifdef HAVE_GRAPHICSMAGICK
603 " GraphicsMagick support enabled\n"
604#else
605 " GraphicsMagick support disabled\n"
606#endif
607
608#ifdef HAVE_IMAGEMAGICK
609 " ImageMagick support enabled\n"
610#else
611 " ImageMagick support disabled\n"
612#endif
613
614#ifdef HAVE_OPENEXR
615 " OpenEXR support enabled\n"
616#else
617 " OpenEXR support disabled\n"
618#endif
619 ,
622 CHAR_BIT * sizeof(void *)
623 );
624 return 1;
625 }
626 else if(!strcmp(argv[k], "--library") && argc > k + 1)
627 {
628 dbfilename_from_command = argv[++k];
629 argv[k-1] = NULL;
630 argv[k] = NULL;
631 }
632 else if(!strcmp(argv[k], "--datadir") && argc > k + 1)
633 {
634 datadir_from_command = argv[++k];
635 argv[k-1] = NULL;
636 argv[k] = NULL;
637 }
638 else if(!strcmp(argv[k], "--moduledir") && argc > k + 1)
639 {
640 moduledir_from_command = argv[++k];
641 argv[k-1] = NULL;
642 argv[k] = NULL;
643 }
644 else if(!strcmp(argv[k], "--tmpdir") && argc > k + 1)
645 {
646 tmpdir_from_command = argv[++k];
647 argv[k-1] = NULL;
648 argv[k] = NULL;
649 }
650 else if(!strcmp(argv[k], "--configdir") && argc > k + 1)
651 {
652 configdir_from_command = argv[++k];
653 argv[k-1] = NULL;
654 argv[k] = NULL;
655 }
656 else if(!strcmp(argv[k], "--cachedir") && argc > k + 1)
657 {
658 cachedir_from_command = argv[++k];
659 argv[k-1] = NULL;
660 argv[k] = NULL;
661 }
662 else if(!strcmp(argv[k], "--localedir") && argc > k + 1)
663 {
664 localedir_from_command = argv[++k];
665 argv[k-1] = NULL;
666 argv[k] = NULL;
667 }
668 else if(!strcmp(argv[k], "--kerneldir") && argc > k + 1)
669 {
670 kerneldir_from_command = argv[++k];
671 argv[k-1] = NULL;
672 argv[k] = NULL;
673 }
674 else if(argv[k][1] == 'd' && argc > k + 1)
675 {
676 if(!strcmp(argv[k + 1], "all"))
677 darktable.unmuted = 0xffffffff & ~DT_DEBUG_VERBOSE; // enable all debug information except verbose
678 else if(!strcmp(argv[k + 1], "cache"))
679 darktable.unmuted |= DT_DEBUG_CACHE; // enable debugging for lib/film/cache module
680 else if(!strcmp(argv[k + 1], "control"))
681 darktable.unmuted |= DT_DEBUG_CONTROL; // enable debugging for scheduler module
682 else if(!strcmp(argv[k + 1], "dev"))
683 darktable.unmuted |= DT_DEBUG_DEV; // develop module
684 else if(!strcmp(argv[k + 1], "gtk"))
685 darktable.unmuted |= DT_DEBUG_GTK; // GTK widgets and display setup
686 else if(!strcmp(argv[k + 1], "input"))
687 darktable.unmuted |= DT_DEBUG_INPUT; // input devices
688 else if(!strcmp(argv[k + 1], "pipecache"))
689 darktable.unmuted |= DT_DEBUG_PIPECACHE; // pipeline cache
690 else if(!strcmp(argv[k + 1], "perf"))
691 darktable.unmuted |= DT_DEBUG_PERF; // performance measurements
692 else if(!strcmp(argv[k + 1], "pwstorage"))
693 darktable.unmuted |= DT_DEBUG_PWSTORAGE; // pwstorage module
694 else if(!strcmp(argv[k + 1], "opencl"))
695 darktable.unmuted |= DT_DEBUG_OPENCL; // gpu accel via opencl
696 else if(!strcmp(argv[k + 1], "sql"))
697 darktable.unmuted |= DT_DEBUG_SQL; // SQLite3 queries
698 else if(!strcmp(argv[k + 1], "memory"))
699 darktable.unmuted |= DT_DEBUG_MEMORY; // some stats on mem usage now and then.
700 else if(!strcmp(argv[k + 1], "lighttable"))
701 darktable.unmuted |= DT_DEBUG_LIGHTTABLE; // lighttable related stuff.
702 else if(!strcmp(argv[k + 1], "nan"))
703 darktable.unmuted |= DT_DEBUG_NAN; // check for NANs when processing the pipe.
704 else if(!strcmp(argv[k + 1], "masks"))
705 darktable.unmuted |= DT_DEBUG_MASKS; // masks related stuff.
706 else if(!strcmp(argv[k + 1], "lua"))
707 darktable.unmuted |= DT_DEBUG_LUA; // lua errors are reported on console
708 else if(!strcmp(argv[k + 1], "print"))
709 darktable.unmuted |= DT_DEBUG_PRINT; // print errors are reported on console
710 else if(!strcmp(argv[k + 1], "camsupport"))
711 darktable.unmuted |= DT_DEBUG_CAMERA_SUPPORT; // camera support warnings are reported on console
712 else if(!strcmp(argv[k + 1], "colorprofile"))
713 darktable.unmuted |= DT_DEBUG_COLORPROFILE; // color profile handling
714 else if(!strcmp(argv[k + 1], "nocache_reuse"))
715 darktable.unmuted |= DT_DEBUG_NOCACHE_REUSE; // disable reusable pixelpipe cache buffers
716 else if(!strcmp(argv[k + 1], "ioporder"))
717 darktable.unmuted |= DT_DEBUG_IOPORDER; // iop order information are reported on console
718 else if(!strcmp(argv[k + 1], "imageio"))
719 darktable.unmuted |= DT_DEBUG_IMAGEIO; // image importing or exporting messages on console
720 else if(!strcmp(argv[k + 1], "undo"))
721 darktable.unmuted |= DT_DEBUG_UNDO; // undo/redo
722 else if(!strcmp(argv[k + 1], "signal"))
723 darktable.unmuted |= DT_DEBUG_SIGNAL; // signal information on console
724 else if(!strcmp(argv[k + 1], "params"))
725 darktable.unmuted |= DT_DEBUG_PARAMS; // iop module params checks on console
726 else if(!strcmp(argv[k + 1], "demosaic"))
728 else if(!strcmp(argv[k + 1], "shortcuts"))
730 else if(!strcmp(argv[k + 1], "tiling"))
732 else if(!strcmp(argv[k + 1], "verbose"))
734 else if(!strcmp(argv[k + 1], "pipe"))
736 else if(!strcmp(argv[k + 1], "history"))
738 else if(!strcmp(argv[k + 1], "import"))
740 else if(!strcmp(argv[k + 1], "supervisor"))
741 darktable.unmuted |= DT_DEBUG_SUPERVISOR; // high-level event supervisor (NDJSON)
742 else
743 return usage(argv[0]);
744 k++;
745 argv[k-1] = NULL;
746 argv[k] = NULL;
747 }
748 else if(!strcmp(argv[k], "--d-signal-act") && argc > k + 1)
749 {
750 if(!strcmp(argv[k + 1], "all"))
751 darktable.unmuted_signal_dbg_acts = 0xffffffff; // enable all signal debug information
752 else if(!strcmp(argv[k + 1], "raise"))
753 darktable.unmuted_signal_dbg_acts |= DT_DEBUG_SIGNAL_ACT_RAISE; // enable debugging for signal raising
754 else if(!strcmp(argv[k + 1], "connect"))
755 darktable.unmuted_signal_dbg_acts |= DT_DEBUG_SIGNAL_ACT_CONNECT; // enable debugging for signal connection
756 else if(!strcmp(argv[k + 1], "disconnect"))
757 darktable.unmuted_signal_dbg_acts |= DT_DEBUG_SIGNAL_ACT_DISCONNECT; // enable debugging for signal disconnection
758 else if(!strcmp(argv[k + 1], "print-trace"))
759 {
760#ifdef DT_HAVE_SIGNAL_TRACE
761 darktable.unmuted_signal_dbg_acts |= DT_DEBUG_SIGNAL_ACT_PRINT_TRACE; // enable printing of signal tracing
762#else
763 fprintf(stderr, "[signal] print-trace not available, skipping\n");
764#endif
765 }
766 else
767 return usage(argv[0]);
768 k++;
769 argv[k-1] = NULL;
770 argv[k] = NULL;
771 }
772 else if(!strcmp(argv[k], "--d-signal") && argc > k + 1)
773 {
774 gchar *str = g_ascii_strup(argv[k+1], -1);
775
776 #define CHKSIGDBG(sig) else if(!g_strcmp0(str, #sig)) do {darktable.unmuted_signal_dbg[sig] = TRUE;} while (0)
777 if(!g_strcmp0(str, "ALL"))
778 {
779 for(int sig=0; sig<DT_SIGNAL_COUNT; sig++)
781 }
823
824 else
825 {
826 fprintf(stderr, "unknown signal name: '%s'. use 'ALL' to enable debug for all or use full signal name\n", str);
827 return usage(argv[0]);
828 }
829 dt_free(str);
830 #undef CHKSIGDBG
831 k++;
832 argv[k-1] = NULL;
833 argv[k] = NULL;
834 }
835 else if(argv[k][1] == 't' && argc > k + 1)
836 {
837 darktable.num_openmp_threads = CLAMP(atol(argv[k + 1]), 1, 100);
838 printf("[dt_init] using %d threads for openmp parallel sections\n", darktable.num_openmp_threads);
839 k++;
840 argv[k-1] = NULL;
841 argv[k] = NULL;
842 cpu_threads_from_cli = TRUE;
843 }
844 else if(!strcmp(argv[k], "--conf") && argc > k + 1)
845 {
846 gchar *keyval = g_strdup(argv[++k]), *c = keyval;
847 argv[k-1] = NULL;
848 argv[k] = NULL;
849 gchar *end = keyval + strlen(keyval);
850 while(*c != '=' && c < end) c++;
851 if(*c == '=' && *(c + 1) != '\0')
852 {
853 *c++ = '\0';
855 entry->key = g_strdup(keyval);
856 entry->value = g_strdup(c);
857 config_override = g_slist_append(config_override, entry);
858 }
859 dt_free(keyval);
860 }
861 else if(!strcmp(argv[k], "--noiseprofiles") && argc > k + 1)
862 {
863 noiseprofiles_from_command = argv[++k];
864 argv[k-1] = NULL;
865 argv[k] = NULL;
866 }
867 else if(!strcmp(argv[k], "--disable-opencl"))
868 {
869#ifdef HAVE_OPENCL
870 exclude_opencl = TRUE;
871#endif
872 argv[k] = NULL;
873 }
874 else if(!strcmp(argv[k], "--debug"))
875 {
876 argv[k] = NULL;
877 }
878 else if(!strcmp(argv[k], "--"))
879 {
880 // "--" confuses the argument parser of glib/gtk. remove it.
881 argv[k] = NULL;
882 break;
883 }
884#ifdef __APPLE__
885 else if(!strncmp(argv[k], "-psn_", 5))
886 {
887 // "-psn_*" argument is added automatically by macOS and should be ignored
888 argv[k] = NULL;
889 }
890#endif
891 else
892 return usage(argv[0]); // fail on unrecognized options
893 }
894 }
895
896 // remove the NULLs to not confuse gtk_init() later.
897 for(int i = 1; i < argc; i++)
898 {
899 int k;
900 for(k = i; k < argc; k++)
901 if(!IS_NULL_PTR(argv[k])) break;
902
903 if(k > i)
904 {
905 k -= i;
906 for(int j = i + k; j < argc; j++)
907 {
908 argv[j-k] = argv[j];
909 argv[j] = NULL;
910 }
911 argc -= k;
912 }
913 }
914
915 // get valid directories
916 dt_loc_init(datadir_from_command, moduledir_from_command, localedir_from_command, configdir_from_command, cachedir_from_command, tmpdir_from_command, kerneldir_from_command);
917
918 fprintf(stdout, "[build] version: %s\n", darktable_package_string);
919 fprintf(stdout, "[build] type: %s | cpu mode: %s\n", DT_BUILD_TYPE, DT_BUILD_CPU_MODE);
920 fprintf(stdout, "[build] c compiler: %s\n", DT_BUILD_C_COMPILER);
921 fprintf(stdout, "[build] c flags: %s\n", DT_BUILD_C_FLAGS);
922 fprintf(stdout, "[build] c++ compiler: %s\n", DT_BUILD_CXX_COMPILER);
923 fprintf(stdout, "[build] c++ flags: %s\n", DT_BUILD_CXX_FLAGS);
924
926 {
927 fprintf(stderr, "[memory] at startup\n");
929 }
930
931 char sharedir[PATH_MAX] = { 0 };
932 dt_loc_get_sharedir(sharedir, sizeof(sharedir));
933
934 // we have to have our share dir in XDG_DATA_DIRS,
935 // otherwise GTK+ won't find our logo for the about screen (and maybe other things)
936 {
937 const gchar *xdg_data_dirs = g_getenv("XDG_DATA_DIRS");
938 gchar *new_xdg_data_dirs = NULL;
939 gboolean set_env = TRUE;
940 if(!IS_NULL_PTR(xdg_data_dirs) && *xdg_data_dirs != '\0')
941 {
942 // check if sharedir is already in there
943 gboolean found = FALSE;
944 gchar **tokens = g_strsplit(xdg_data_dirs, G_SEARCHPATH_SEPARATOR_S, 0);
945 // xdg_data_dirs is neither NULL nor empty => !IS_NULL_PTR(tokens)
946 for(char **iter = tokens; !IS_NULL_PTR(*iter); iter++)
947 if(!strcmp(sharedir, *iter))
948 {
949 found = TRUE;
950 break;
951 }
952 g_strfreev(tokens);
953 if(found)
954 set_env = FALSE;
955 else
956 new_xdg_data_dirs = g_strjoin(G_SEARCHPATH_SEPARATOR_S, sharedir, xdg_data_dirs, NULL);
957 }
958 else
959 {
960#ifndef _WIN32
961 // see http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html for a reason to use those as a
962 // default
963 if(!g_strcmp0(sharedir, "/usr/local/share")
964 || !g_strcmp0(sharedir, "/usr/local/share/")
965 || !g_strcmp0(sharedir, "/usr/share") || !g_strcmp0(sharedir, "/usr/share/"))
966 new_xdg_data_dirs = g_strdup("/usr/local/share/" G_SEARCHPATH_SEPARATOR_S "/usr/share/");
967 else
968 new_xdg_data_dirs = g_strdup_printf("%s" G_SEARCHPATH_SEPARATOR_S "/usr/local/share/" G_SEARCHPATH_SEPARATOR_S
969 "/usr/share/", sharedir);
970#else
971 set_env = FALSE;
972#endif
973 }
974
975 if(set_env) g_setenv("XDG_DATA_DIRS", new_xdg_data_dirs, 1);
976 dt_print(DT_DEBUG_DEV, "new_xdg_data_dirs: %s\n", new_xdg_data_dirs);
977 dt_free(new_xdg_data_dirs);
978 }
979
980 setlocale(LC_ALL, "");
981 char localedir[PATH_MAX] = { 0 };
982 dt_loc_get_localedir(localedir, sizeof(localedir));
983 bindtextdomain(GETTEXT_PACKAGE, localedir);
984 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
985 textdomain(GETTEXT_PACKAGE);
986
987 if(init_gui)
988 {
989 // I doubt that connecting to dbus for ansel-cli makes sense
990 darktable.dbus = NULL; //dt_dbus_init();
991
992 // make sure that we have no stale global progress bar visible. thus it's run as early as possible
994 }
995
996 // thread-safe init:
997 dt_exif_init();
998 char datadir[PATH_MAX] = { 0 };
999 dt_loc_get_user_config_dir(datadir, sizeof(datadir));
1000 char anselrc[PATH_MAX] = { 0 };
1001 dt_concat_path_file(anselrc, datadir, "anselrc");
1002
1003 // initialize the config backend. this needs to be done first...
1004 darktable.conf = (dt_conf_t *)calloc(1, sizeof(dt_conf_t));
1005 dt_conf_init(darktable.conf, anselrc, config_override);
1006 g_slist_free_full(config_override, dt_free_gpointer);
1007
1008 // set the interface language and prepare selection for prefs
1009 darktable.l10n = dt_l10n_init(init_gui);
1010
1011 dt_confgen_init();
1013
1014 // Needs to run after dt_confgen_init()
1015 // Don't override cli argument if any
1016 if(!cpu_threads_from_cli)
1017 {
1018 const int user_threads = dt_conf_get_int("cpu_threads");
1019 if(user_threads > 0) darktable.num_openmp_threads = user_threads;
1020 }
1021
1022#ifdef _OPENMP
1023 omp_set_num_threads(darktable.num_openmp_threads);
1024#endif
1025
1026 // we need this REALLY early so that error messages can be shown, however after gtk_disable_setlocale
1027 if(init_gui)
1028 {
1029 g_log_set_writer_func(_gtk_log_writer_filter, NULL, NULL);
1030 gtk_init(&argc, &argv);
1031
1032 darktable.themes = NULL;
1033 }
1034
1035 // get the list of color profiles
1037
1038 // initialize datetime data
1040
1041 // initialize the database
1042 gboolean recheck_needed = TRUE;
1043 while (recheck_needed)
1044 {
1045 darktable.db = dt_database_init(dbfilename_from_command, load_data, init_gui);
1047 {
1048 printf("ERROR : cannot open database\n");
1050 return 1;
1051 }
1053 {
1054 gboolean error = FALSE;
1055
1056 if (init_gui)
1057 {
1058 gboolean image_loaded_elsewhere = FALSE;
1059#ifndef MAC_INTEGRATION
1060 // send the images to the other instance via dbus
1061 fprintf(stderr, "trying to open the images in the running instance\n");
1062
1064 {
1065 GDBusConnection *connection = NULL;
1066 for(int i = 1; i < argc; i++)
1067 {
1068 // make the filename absolute ...
1069 if(argv[i] == NULL || *argv[i] == '\0') continue;
1070 gchar *filename = dt_util_normalize_path(argv[i]);
1071 if(IS_NULL_PTR(filename)) continue;
1072 if(IS_NULL_PTR(connection)) connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
1073 // ... and send it to the running instance of darktable
1074 image_loaded_elsewhere = g_dbus_connection_call_sync(connection, "org.darktable.service", "/darktable",
1075 "org.darktable.service.Remote", "Open",
1076 g_variant_new("(s)", filename), NULL,
1077 G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL) != NULL;
1078 dt_free(filename);
1079 }
1080 if(connection) g_object_unref(connection);
1081 }
1082#endif
1083 if(!image_loaded_elsewhere) error = dt_database_show_error(darktable.db);
1084 }
1085 if(error)
1086 {
1087 fprintf(stderr, "ERROR: can't acquire database lock, aborting.\n");
1089 return error;
1090 }
1091 else
1092 {
1093 // try again
1094 continue;
1095 }
1096 }
1097 recheck_needed = FALSE;
1098 }
1099
1100 //db maintenance on startup (if configured to do so)
1102 {
1104 }
1105
1106 // init darktable tags table
1108
1109 // Initialize the signal system
1111 // Critical: ensure image cache gets refreshed BEFORE any other IMAGE_INFO_CHANGED handlers.
1112 // This handler reloads dt_image_t from DB so all downstream callbacks see fresh metadata.
1114
1115 // Make sure that the database and xmp files are in sync
1116 // We need conf and db to be up and running for that which is the case here.
1117 // FIXME: is this also useful in non-gui mode?
1118 GList *changed_xmp_files = NULL;
1119 if(init_gui && dt_conf_get_bool("run_crawler_on_start"))
1120 {
1121 changed_xmp_files = dt_control_crawler_run();
1122 }
1123
1124 if(init_gui)
1125 {
1127 }
1128 else
1129 {
1130 if(dbfilename_from_command && !strcmp(dbfilename_from_command, ":memory:"))
1131 dt_gui_presets_init(); // init preset db schema.
1135 }
1136
1137 // we initialize grouping early because it's needed for collection init
1138 // idem for folder reachability
1139 if(init_gui)
1140 {
1141 darktable.gui = (dt_gui_gtk_t *)calloc(1, sizeof(dt_gui_gtk_t));
1142 memset(darktable.gui->scroll_to, 0, sizeof(darktable.gui->scroll_to));
1144 }
1145
1146 // initialize collection query
1148
1149 /* initialize selection */
1151
1152 /* capabilities set to NULL */
1153 darktable.capabilities = NULL;
1154
1155 // Initialize the password storage engine
1157
1159
1160#ifdef HAVE_GRAPHICSMAGICK
1161 /* GraphicsMagick init */
1162 InitializeMagick(darktable.progname);
1163
1164 // *SIGH*
1166
1167#elif defined HAVE_IMAGEMAGICK
1168
1169 /* ImageMagick init */
1170 MagickWandGenesis();
1171
1172#endif
1173
1174 darktable.noiseprofile_parser = dt_noiseprofile_init(noiseprofiles_from_command);
1175
1176 // The GUI must be initialized before the views, because the init()
1177 // functions of the views depend on darktable.control->accels_* to register
1178 // their keyboard accelerators
1179
1180 // TODO : Make a single call to unified GUI API initializing everything graphical at once.
1181 // The current tangled mess is a nightmare to maintain.
1182
1183 if(init_gui)
1184 {
1186 {
1187 fprintf(stderr, "ERROR: can't init gui, aborting.\n");
1189 return 1;
1190 }
1192 }
1193 else
1194 darktable.gui = NULL;
1195
1196 // This needs to run after gui init because we init cache lines size with window size
1197 // but before image cache init and pipeline cache init (aka dev init aka darkroom init aka viewmanager init)
1198 // because we init its size here
1200
1203
1204 // check whether we were able to load darkroom view. if we failed, we'll crash everywhere later on.
1206 {
1207 fprintf(stderr, "ERROR: can't init develop system, aborting.\n");
1209 return 1;
1210 }
1211
1214 {
1215 fprintf(stderr, "ERROR: can't init pixelpipe cache, aborting.\n");
1217 return 1;
1218 }
1219
1220 // High-level event supervisor registry (active only under -d supervisor).
1222
1223 darktable.points = (dt_points_t *)calloc(1, sizeof(dt_points_t));
1225
1226 // must come before mipmap_cache, because that one will need to access
1227 // image dimensions stored in here:
1230
1233
1234 darktable.opencl = (dt_opencl_t *)calloc(1, sizeof(dt_opencl_t));
1235#ifdef HAVE_OPENCL
1236 dt_opencl_init(darktable.opencl, exclude_opencl, print_statistics);
1237 // Show the splash only while compiling OpenCL kernels (triggered from opencl.c),
1238 // then close it immediately so the rest of the startup stays splash-free.
1240#endif
1241
1242 darktable.imageio = (dt_imageio_t *)calloc(1, sizeof(dt_imageio_t));
1244
1245 // load default iop order
1247 // load iop order rules
1249 // load the darkroom mode plugins once:
1251 // check if all modules have a iop order assigned
1253 {
1254 fprintf(stderr, "ERROR: iop order looks bad, aborting.\n");
1256 return 1;
1257 }
1258
1259 // set up memory.darktable_iop_names table
1261
1262 // set up the list of exiv2 metadata
1264
1265 // init metadata flags
1267
1268 if(init_gui)
1269 {
1270 darktable.lib = (dt_lib_t *)calloc(1, sizeof(dt_lib_t));
1272
1273 // prevent bauhaus widgets from sending value-changed signals
1274 // because some of them expect user interactions.
1276
1277 // init the gui part of views
1279
1281
1282 // initialize undo struct
1284
1285 // Global menu inherits many parts of the GUI,
1286 // so it should be inited last
1288 }
1289
1291 {
1292 fprintf(stderr, "[memory] after successful startup\n");
1294 }
1295
1296 if(init_gui)
1297 {
1298 // we have to call dt_ctl_switch_mode_to() here already to not run into a lua deadlock.
1299 // having another call later is ok
1300 dt_ctl_switch_mode_to("lighttable");
1301
1302#ifndef MAC_INTEGRATION
1303 // load image(s) specified on cmdline.
1304 // this has to happen after lua is initialized as image import can run lua code
1305 if (argc == 2)
1306 {
1307 // If only one image is listed, attempt to load it in darkroom
1308 (void)dt_load_from_string(argv[1], TRUE, NULL);
1309 }
1310 else if (argc > 2)
1311 {
1312 // when multiple names are given, fire up a background job to import them
1314 }
1315#endif
1316 }
1317
1318 // last but not least construct the popup that asks the user about images whose xmp files are newer than the
1319 // db entry
1320 if(init_gui && changed_xmp_files)
1321 {
1322 dt_control_crawler_show_image_list(changed_xmp_files);
1323 }
1324
1325 if(init_gui)
1326 {
1329 //gtk_window_add_accel_group(GTK_WINDOW(dt_ui_main_window(darktable.gui->ui)), darktable.gui->accels->global_accels);
1330
1331 // Studio capture folder survey: restore the persisted comparison state and,
1332 // once the main loop runs and the window is mapped, propose to resume a
1333 // session that was monitoring when the application was last closed.
1336 g_idle_add((GSourceFunc)dt_folder_survey_propose_resume, NULL);
1337 }
1338
1340
1341 // On first launch, ask once for consent to the opt-in data flows (crash reports
1342 // and usage analytics) in a single dialog, before initializing either module so
1343 // their enabled flags are set when they read them.
1344 dt_privacy_ask_consent(init_gui);
1345
1346 // Initialize crash reporting last, after the final dt_set_signal_handlers() so
1347 // sentry's handler sits on top and chains down into our gdb/drmingw fallback.
1348 dt_sentry_init(init_gui);
1349
1350 // Opt-in usage analytics (PostHog) - separate toggle from crash reporting.
1351 dt_telemetry_init(init_gui);
1352
1353 dt_print(DT_DEBUG_CONTROL, "[init] startup took %f seconds\n", dt_get_wtime() - start_wtime);
1354
1355 return 0;
1356}
1357
1358static void _dt_drain_main_context(const int max_iters)
1359{
1360 if(max_iters <= 0) return;
1361 GMainContext *ctx = g_main_context_default();
1362 for(int i = 0; i < max_iters && g_main_context_pending(ctx); i++)
1363 g_main_context_iteration(ctx, FALSE);
1364}
1365
1367{
1368 const int init_gui = (!IS_NULL_PTR(darktable.gui));
1369
1370 // Flush crash reporting and mark this session as a clean exit. Done early so
1371 // events are sent while the rest of the app is still up; the clean-session
1372 // counter it writes is persisted later by dt_conf_cleanup().
1374
1375 // Flush and stop usage analytics.
1377
1378 // Restore selection if exiting on culling mode to be sure it's saved in DB
1381
1382 // Restore auto-computed zoom level to user-defined
1383 dt_conf_set_int("plugins/lighttable/images_in_row", dt_conf_get_int("plugins/lighttable/images_in_row_backup"));
1384
1385 // last chance to ask user for any input...
1386
1387 const gboolean perform_maintenance = dt_database_maybe_maintenance(darktable.db, init_gui, TRUE);
1388 const gboolean perform_snapshot = dt_database_maybe_snapshot(darktable.db);
1389 gchar **snaps_to_remove = NULL;
1390 if(perform_snapshot)
1391 {
1392 snaps_to_remove = dt_database_snaps_to_remove(darktable.db);
1393 }
1394
1395#ifdef HAVE_PRINT
1397#endif
1398
1399 // anything that asks user for input should be placed before this line
1400
1401 if(init_gui)
1402 {
1405
1406 if(darktable.gui->surface)
1407 {
1408 cairo_surface_destroy(darktable.gui->surface);
1409 darktable.gui->surface = NULL;
1410 }
1411
1412 // hide main window and do rest of the cleanup in the background
1413 gtk_widget_hide(dt_ui_main_window(darktable.gui->ui));
1414
1416 //dt_dbus_destroy(darktable.dbus);
1417
1418 // Stop control workers before unloading views and libs. They can still be
1419 // processing lighttable-side jobs while shutdown is tearing down modules.
1423
1425
1428 }
1429
1430 dt_dev_pixelpipe_cache_wait_dump_pending("app-cleanup-before-view-manager");
1433
1434 if(init_gui)
1435 {
1438
1440
1443
1444 /* Force GTK to teardown the toplevel widget tree now, while the main
1445 * context still exists. This helps release style/cairo resources that
1446 * would otherwise stay alive until process exit. */
1447 GtkWidget *main_window = dt_ui_main_window(darktable.gui->ui);
1448 if(GTK_IS_WIDGET(main_window))
1449 gtk_widget_destroy(main_window);
1450
1451 dt_gui_gtk_t *gui = darktable.gui;
1452 darktable.gui = NULL;
1454 dt_free(gui->ui);
1455 dt_free(gui);
1456 }
1457
1465
1468
1469 // Mipmap cleanup may still consult the image cache for paths.
1474
1482 g_list_free_full(darktable.iop_order_list, dt_free_gpointer);
1484 g_list_free_full(darktable.iop_order_rules, dt_free_gpointer);
1486
1487#ifdef HAVE_OPENCL
1489 {
1490 for(int i = 0; i < darktable.opencl->num_devs; i++)
1492 }
1493#endif
1494
1497
1501
1502#ifdef HAVE_GRAPHICSMAGICK
1503 DestroyMagick();
1504#elif defined HAVE_IMAGEMAGICK
1505 MagickWandTerminus();
1506#endif
1507
1509
1510 if(perform_maintenance)
1511 {
1514 }
1515
1517 if(perform_snapshot)
1518 {
1519 if(dt_database_snapshot(darktable.db) && snaps_to_remove)
1520 {
1521 int i = 0;
1522 while(snaps_to_remove[i])
1523 {
1524 // make file to remove writable, mostly problem on windows.
1525 g_chmod(snaps_to_remove[i], S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
1526
1527 dt_print(DT_DEBUG_SQL, "[db backup] removing old snap: %s... ", snaps_to_remove[i]);
1528 const int retunlink = g_remove(snaps_to_remove[i++]);
1529 dt_print(DT_DEBUG_SQL, "%s\n", retunlink == 0 ? "success" : "failed!");
1530 }
1531 }
1532 }
1533 if(snaps_to_remove)
1534 {
1535 g_strfreev(snaps_to_remove);
1536 }
1538
1539 if(init_gui)
1540 {
1542 }
1543
1545 {
1546 g_object_unref(darktable.noiseprofile_parser);
1548 }
1549
1550 if(init_gui)
1551 {
1554 }
1555 else
1556 {
1559 }
1561
1563 darktable.signals = NULL;
1564
1566
1573
1575
1576 /* Stop GLib pooled workers first, then release the current thread default
1577 * PangoCairo font map before finalizing Fontconfig caches. */
1578 if(init_gui)
1579 {
1580 g_thread_pool_stop_unused_threads();
1581#if !defined(_WIN32) && !defined(__APPLE__)
1582 PangoFontMap *fontmap = pango_cairo_font_map_get_default();
1583 gboolean use_fontconfig_backend = FALSE;
1584
1585 if(fontmap && PANGO_IS_CAIRO_FONT_MAP(fontmap))
1586 {
1587 const cairo_font_type_t font_backend
1588 = pango_cairo_font_map_get_font_type(PANGO_CAIRO_FONT_MAP(fontmap));
1589 use_fontconfig_backend = (font_backend == CAIRO_FONT_TYPE_FT);
1590 }
1591
1592 if(use_fontconfig_backend && fontmap && g_type_is_a(G_OBJECT_TYPE(fontmap), pango_fc_font_map_get_type()))
1594 if(use_fontconfig_backend) FcFini();
1595#endif
1596 pango_cairo_font_map_set_default(NULL);
1597 }
1598}
1599
1600void dt_print(dt_debug_thread_t thread, const char *msg, ...)
1601{
1602 if(thread == DT_DEBUG_ALWAYS || (darktable.unmuted & thread))
1603 {
1604 printf("%f ", dt_get_wtime() - darktable.start_wtime);
1605 va_list ap;
1606 va_start(ap, msg);
1607 g_vprintf(msg, ap);
1608 va_end(ap);
1609 fflush(stdout);
1610 }
1611}
1612
1613void dt_print_nts(dt_debug_thread_t thread, const char *msg, ...)
1614{
1615 if(thread == DT_DEBUG_ALWAYS || (darktable.unmuted & thread))
1616 {
1617 va_list ap;
1618 va_start(ap, msg);
1619 g_vprintf(msg, ap);
1620 va_end(ap);
1621 fflush(stdout);
1622 }
1623}
1624
1625void dt_vprint(dt_debug_thread_t thread, const char *msg, ...)
1626{
1627 if(thread == DT_DEBUG_ALWAYS || ((darktable.unmuted & DT_DEBUG_VERBOSE) && (darktable.unmuted & thread)))
1628 {
1629 printf("%f ", dt_get_wtime() - darktable.start_wtime);
1630 va_list ap;
1631 va_start(ap, msg);
1632 g_vprintf(msg, ap);
1633 va_end(ap);
1634 fflush(stdout);
1635 }
1636}
1637
1638void dt_show_times(const dt_times_t *start, const char *prefix)
1639{
1640 /* Skip all the calculations an everything if -d perf isn't on */
1642 {
1643 dt_times_t end;
1644 dt_get_times(&end);
1645 char buf[140]; /* Arbitrary size, should be lots big enough for everything used in DT */
1646 snprintf(buf, sizeof(buf), "%s took %.3f secs (%.3f CPU)", prefix, end.clock - start->clock,
1647 end.user - start->user);
1648 dt_print(DT_DEBUG_PERF, "%s\n", buf);
1649 }
1650}
1651
1652void dt_show_times_f(const dt_times_t *start, const char *prefix, const char *suffix, ...)
1653{
1654 /* Skip all the calculations an everything if -d perf isn't on */
1656 {
1657 dt_times_t end;
1658 dt_get_times(&end);
1659 char buf[160]; /* Arbitrary size, should be lots big enough for everything used in DT */
1660 const int n = snprintf(buf, sizeof(buf), "%s took %.3f secs (%.3f CPU) ", prefix, end.clock - start->clock,
1661 end.user - start->user);
1662 if(n < sizeof(buf) - 1)
1663 {
1664 va_list ap;
1665 va_start(ap, suffix);
1666 vsnprintf(buf + n, sizeof(buf) - n, suffix, ap);
1667 va_end(ap);
1668 }
1669 dt_print(DT_DEBUG_PERF, "%s\n", buf);
1670 }
1671}
1672
1673#if defined(_WIN32)
1674#include <windows.h>
1675
1677{
1678 MEMORYSTATUSEX status;
1679 status.dwLength = sizeof(status);
1680 if(GlobalMemoryStatusEx(&status))
1681 return (size_t)status.ullAvailPhys; // Includes reclaimable
1682 else
1683 return 0;
1684}
1685
1686#elif defined(__APPLE__)
1687#include <mach/mach.h>
1688
1690{
1691 mach_port_t host = mach_host_self();
1692 vm_statistics64_data_t vmstat;
1693 mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
1694 if(host_statistics64(host, HOST_VM_INFO64, (host_info64_t)&vmstat, &count) != KERN_SUCCESS) return 0;
1695
1696 size_t page_size;
1697 host_page_size(host, &page_size);
1698
1699 // Free + inactive (reclaimable)
1700 return (vmstat.free_count + vmstat.inactive_count) * page_size;
1701}
1702
1703#elif defined(__linux__)
1704#include <string.h>
1705
1707{
1708 FILE *f = g_fopen("/proc/meminfo", "r");
1709 if(IS_NULL_PTR(f)) return 0;
1710
1711 char line[256];
1712 size_t available_kb = 0;
1713
1714 while(fgets(line, sizeof(line), f))
1715 {
1716 if(sscanf(line, "MemAvailable: %" G_GSIZE_FORMAT " kB", &available_kb) == 1)
1717 {
1718 fclose(f);
1719 return available_kb * 1024; // kB to bytes
1720 }
1721 }
1722
1723 fclose(f);
1724 return 0;
1725}
1726
1727#else
1729{
1730 return 0; // Unsupported platform
1731}
1732#endif
1733
1734
1736{
1737 return dt_conf_get_int("worker_threads");
1738}
1739
1744
1746{
1748}
1749
1750void dt_configure_runtime_performance(dt_sys_resources_t *resources, gboolean init_gui)
1751{
1752 resources->total_memory = _get_total_memory() * 1000;
1753
1754 const size_t threads = darktable.num_openmp_threads;
1755 const size_t mem = resources->total_memory / (1024 * 1024);
1756 const size_t bits = CHAR_BIT * sizeof(void *);
1757 const gboolean sufficient = (mem >= 4096 && threads >= 2);
1758
1759 dt_print(DT_DEBUG_MEMORY, "[MEMORY CONFIGURATION] found a %s %" G_GSIZE_FORMAT "-bit system with %" G_GSIZE_FORMAT " cores\n",
1760 (sufficient) ? "sufficient" : "low performance", bits, threads);
1761
1762 // Override RAM detection with user config
1763 if(dt_conf_get_int64("host_memory_limit") > 0)
1764 resources->total_memory = dt_conf_get_int64("host_memory_limit") * 1024 * 1024;
1765
1766 // Keep OS headroom between 1 GB and a third of the system RAM
1767 resources->headroom_memory = dt_conf_get_int64("memory_os_headroom") * 1024 * 1024;
1768 resources->headroom_memory
1769 = CLAMP(resources->headroom_memory, 1024 * 1024 * 1024, resources->total_memory / 3);
1770
1771 // Keep mipmap cache between 256 MB and a sixth of the system RAM
1772 resources->mipmap_memory = dt_conf_get_int64("memory_mipmap_cache") * 1024 * 1024;
1773 resources->mipmap_memory
1774 = CLAMP(resources->mipmap_memory, 256 * 1024 * 1024, resources->total_memory / 6);
1775
1776 // 6 temp copies of 24 Mpx RGBA float32 at full res
1777 const size_t min_pipecache_memory = 6 * 6000 * 4000 * 4 * sizeof(float);
1778
1779 // Pipeline cache gets the rest. Need to cast as int otherwise, negative values saturate the uint64 to MAX_UINT or something
1780 resources->pixelpipe_memory = MAX((int64_t)resources->total_memory
1781 - (int64_t)resources->mipmap_memory
1782 - (int64_t)resources->headroom_memory,
1783 (int64_t)min_pipecache_memory);
1784
1785 if(resources->pixelpipe_memory == min_pipecache_memory)
1786 {
1787 fprintf(stderr,
1788 "MEMORY WARNING: your pixelpipe cache allocated RAM is too small for your typical raw size.\n"
1789 "MEMORY WARNING: reduce your OS/apps headroom, or your thumbnail cache size.\n"
1790 "MEMORY WARNING: you may also simply need more RAM or need to reset the config key host_memory.\n"
1791 "MEMORY WARNING: we shrank the thumbnails cache to the bare minimum to leave enough space for pixelpipe cache.\n");
1792 resources->mipmap_memory = MAX((int64_t)resources->total_memory
1793 - (int64_t)resources->headroom_memory
1794 - (int64_t)resources->pixelpipe_memory,
1795 (int64_t)128 * 1024 * 1024);
1796 }
1797
1798 // Print
1799 dt_print(DT_DEBUG_MEMORY | DT_DEBUG_CACHE, _("[MEMORY CONFIGURATION] Total system RAM: %" G_GSIZE_FORMAT " MiB\n"),
1800 resources->total_memory / (1024 * 1024));
1801
1802 dt_print(DT_DEBUG_MEMORY | DT_DEBUG_CACHE, _("[MEMORY CONFIGURATION] OS & Apps RAM headroom: %" G_GSIZE_FORMAT " MiB\n"),
1803 resources->headroom_memory / (1024 * 1024));
1804
1805 dt_print(DT_DEBUG_MEMORY | DT_DEBUG_CACHE, _("[MEMORY CONFIGURATION] Lightable thumbnails cache size: %" G_GSIZE_FORMAT " MiB\n"),
1806 resources->mipmap_memory / (1024 * 1024));
1807
1808 dt_print(DT_DEBUG_MEMORY | DT_DEBUG_CACHE, _("[MEMORY CONFIGURATION] Pixelpipe cache size: %" G_GSIZE_FORMAT " MiB\n"),
1809 resources->pixelpipe_memory / (1024 * 1024));
1810
1811 dt_print(DT_DEBUG_MEMORY | DT_DEBUG_CACHE, _("[MEMORY CONFIGURATION] Worker threads: %i\n"), dt_worker_threads());
1812
1813 if(resources->total_memory < resources->headroom_memory + resources->mipmap_memory + resources->pixelpipe_memory)
1814 dt_control_log(_("CRITICAL WARNING: Ansel will not be able to use the RAM you allocated it.\n"
1815 "Review your memory settings or add more RAM to your system."));
1816}
1817
1818int dt_capabilities_check(char *capability)
1819{
1820 for(GList *capabilities = darktable.capabilities; capabilities; capabilities = g_list_next(capabilities))
1821 {
1822 if(!strcmp(capabilities->data, capability))
1823 {
1824 return TRUE;
1825 }
1826 }
1827 return FALSE;
1828}
1829
1830
1831void dt_capabilities_add(char *capability)
1832{
1834
1835 if(!dt_capabilities_check(capability))
1836 darktable.capabilities = g_list_append(darktable.capabilities, capability);
1837
1839}
1840
1841
1850
1851
1857
1858
1860{
1861 fprintf(stdout, "[memory] Currently-free and reclaimable memory detected: %lu MiB\n", get_usable_memory_bytes() / (1024 * 1024));
1862
1863#if defined(__linux__)
1864 char *line = NULL;
1865 size_t len = 128;
1866 char vmsize[64];
1867 char vmpeak[64];
1868 char vmrss[64];
1869 char vmhwm[64];
1870 FILE *f;
1871
1872 char pidstatus[128];
1873 snprintf(pidstatus, sizeof(pidstatus), "/proc/%u/status", (uint32_t)getpid());
1874
1875 f = g_fopen(pidstatus, "r");
1876 if(IS_NULL_PTR(f)) return;
1877
1878 /* read memory size data from /proc/pid/status */
1879 while(getline(&line, &len, f) != -1)
1880 {
1881 if(!strncmp(line, "VmPeak:", 7))
1882 g_strlcpy(vmpeak, line + 8, sizeof(vmpeak));
1883 else if(!strncmp(line, "VmSize:", 7))
1884 g_strlcpy(vmsize, line + 8, sizeof(vmsize));
1885 else if(!strncmp(line, "VmRSS:", 6))
1886 g_strlcpy(vmrss, line + 8, sizeof(vmrss));
1887 else if(!strncmp(line, "VmHWM:", 6))
1888 g_strlcpy(vmhwm, line + 8, sizeof(vmhwm));
1889 }
1890 dt_free(line);
1891 fclose(f);
1892
1893 fprintf(stderr, "[memory] max address space (vmpeak): %15s"
1894 "[memory] cur address space (vmsize): %15s"
1895 "[memory] max used memory (vmhwm ): %15s"
1896 "[memory] cur used memory (vmrss ): %15s",
1897 vmpeak, vmsize, vmhwm, vmrss);
1898
1899#elif defined(__APPLE__)
1900 struct task_basic_info t_info;
1901 mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
1902
1903 if(KERN_SUCCESS != task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count))
1904 {
1905 fprintf(stderr, "[memory] task memory info unknown.\n");
1906 return;
1907 }
1908
1909 // Report in kB, to match output of /proc on Linux.
1910 fprintf(stderr, "[memory] max address space (vmpeak): %15s\n"
1911 "[memory] cur address space (vmsize): %12llu kB\n"
1912 "[memory] max used memory (vmhwm ): %15s\n"
1913 "[memory] cur used memory (vmrss ): %12llu kB\n",
1914 "unknown", (uint64_t)t_info.virtual_size / 1024, "unknown", (uint64_t)t_info.resident_size / 1024);
1915#elif defined (_WIN32)
1916 //Based on: http://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process
1917 MEMORYSTATUSEX memInfo;
1918 memInfo.dwLength = sizeof(MEMORYSTATUSEX);
1919 GlobalMemoryStatusEx(&memInfo);
1920 // DWORDLONG totalVirtualMem = memInfo.ullTotalPageFile;
1921
1922 // Virtual Memory currently used by current process:
1923 PROCESS_MEMORY_COUNTERS_EX pmc;
1924 GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS *)&pmc, sizeof(pmc));
1925 size_t virtualMemUsedByMe = pmc.PagefileUsage;
1926 size_t virtualMemUsedByMeMax = pmc.PeakPagefileUsage;
1927
1928 // Max Physical Memory currently used by current process
1929 size_t physMemUsedByMeMax = pmc.PeakWorkingSetSize;
1930
1931 // Physical Memory currently used by current process
1932 size_t physMemUsedByMe = pmc.WorkingSetSize;
1933
1934
1935 fprintf(stderr, "[memory] max address space (vmpeak): %12llu kB\n"
1936 "[memory] cur address space (vmsize): %12llu kB\n"
1937 "[memory] max used memory (vmhwm ): %12llu kB\n"
1938 "[memory] cur used memory (vmrss ): %12llu Kb\n",
1939 virtualMemUsedByMeMax / 1024, virtualMemUsedByMe / 1024, physMemUsedByMeMax / 1024,
1940 physMemUsedByMe / 1024);
1941
1942#else
1943 fprintf(stderr, "dt_print_mem_usage() currently unsupported on this platform\n");
1944#endif
1945}
1946
1947void dt_concat_path_file(char destination[PATH_MAX], const char path[PATH_MAX], const char *const file)
1948{
1949 g_strlcpy(destination, path, sizeof(char) * PATH_MAX);
1950 g_strlcat(destination, G_DIR_SEPARATOR_S, sizeof(char) * PATH_MAX);
1951 g_strlcat(destination, file, sizeof(char) * PATH_MAX);
1952}
1953
1954// clang-format off
1955// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1956// vim: shiftwidth=2 expandtab tabstop=2 cindent
1957// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1958// 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)
void dt_accels_load_user_config(dt_accels_t *accels)
Loads keyboardrc.lang from config dir. This needs to run after we inited the accel map from widgets c...
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:151
void dt_bauhaus_cleanup(dt_bauhaus_t *bauhaus)
Definition bauhaus.c:1501
dt_bauhaus_t * dt_bauhaus_init()
Definition bauhaus.c:1383
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
void dt_culling_mode_to_selection()
dt_collection_t * dt_collection_new()
Definition collection.c:117
void dt_collection_free(const dt_collection_t *collection)
Definition collection.c:124
void dt_colorlabels_cleanup(void)
void dt_colorspaces_cleanup(dt_colorspaces_t *self)
dt_colorspaces_t * dt_colorspaces_init()
const dt_aligned_pixel_t f
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_history_cleanup(void)
int32_t dt_image_import(const int32_t film_id, const char *filename, gboolean raise_signals)
void dt_image_cleanup(void)
char * key
void dt_metadata_cleanup(void)
void dt_metadata_init()
#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_conf_cleanup(dt_conf_t *cf)
int dt_conf_get_bool(const char *name)
void dt_conf_init(dt_conf_t *cf, const char *filename, GSList *override_entries)
gchar * dt_conf_get_string(const char *name)
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
int64_t dt_conf_get_int64(const char *name)
void dt_conf_set_string(const char *name, const char *val)
void dt_ctl_switch_mode_to(const char *mode)
Definition control.c:673
void dt_control_init(dt_control_t *s)
Definition control.c:95
void dt_control_set_mouse_over_id(int32_t value)
Definition control.c:947
void dt_control_log(const char *msg,...)
Definition control.c:777
void dt_control_shutdown(dt_control_t *s)
Definition control.c:456
void dt_control_cleanup(dt_control_t *s)
Definition control.c:484
void dt_control_crawler_show_image_list(GList *images)
Definition crawler.c:680
GList * dt_control_crawler_run(void)
Definition crawler.c:121
void dt_printers_abort_discovery(void)
Definition cups_print.c:210
void dt_vprint(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1625
void dt_show_times(const dt_times_t *start, const char *prefix)
Definition darktable.c:1638
GType pango_fc_font_map_get_type(void)
int dt_load_from_string(const gchar *input, gboolean open_image_in_dr, gboolean *single_image)
Definition darktable.c:366
static GLogWriterOutput _gtk_log_writer_filter(GLogLevelFlags log_level, const GLogField *fields, gsize n_fields, gpointer user_data)
Definition darktable.c:197
void dt_cleanup()
Definition darktable.c:1366
int dt_worker_threads()
Definition darktable.c:1735
static void _dt_drain_main_context(const int max_iters)
Definition darktable.c:1358
const char * dt_install_id(void)
Definition darktable.c:328
void dt_concat_path_file(char destination[PATH_MAX], const char path[PATH_MAX], const char *const file)
Definition darktable.c:1947
darktable_t darktable
Definition darktable.c:183
void dt_print_mem_usage()
Definition darktable.c:1859
size_t get_usable_memory_bytes()
Definition darktable.c:1728
struct _PangoFcFontMap PangoFcFontMap
Definition darktable.c:186
void pango_fc_font_map_shutdown(PangoFcFontMap *fcfontmap)
void * dt_alloc_align(size_t size)
Definition darktable.c:484
void dt_capabilities_remove(char *capability)
Definition darktable.c:1842
int dt_init(int argc, char *argv[], const gboolean init_gui, const gboolean load_data)
Definition darktable.c:489
size_t dt_get_mipmap_mem()
Definition darktable.c:1745
const char * dt_session_id(void)
Definition darktable.c:314
static size_t _get_total_memory()
Definition darktable.c:435
char * dt_version_major_minor()
Definition darktable.c:283
void dt_print_nts(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1613
void dt_configure_runtime_performance(dt_sys_resources_t *resources, gboolean init_gui)
Definition darktable.c:1750
void dt_capabilities_add(char *capability)
Definition darktable.c:1831
gboolean dt_supported_image(const gchar *filename)
check if file is a supported image
Definition darktable.c:350
void dt_capabilities_cleanup()
Definition darktable.c:1852
void dt_show_times_f(const dt_times_t *start, const char *prefix, const char *suffix,...)
Definition darktable.c:1652
size_t dt_get_available_mem()
Definition darktable.c:1740
int dt_capabilities_check(char *capability)
Definition darktable.c:1818
static int usage(const char *argv0)
Definition darktable.c:231
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1600
#define CHKSIGDBG(sig)
dt_debug_thread_t
Definition darktable.h:734
@ DT_DEBUG_LIGHTTABLE
Definition darktable.h:747
@ DT_DEBUG_UNDO
Definition darktable.h:756
@ DT_DEBUG_INPUT
Definition darktable.h:751
@ DT_DEBUG_PRINT
Definition darktable.h:752
@ DT_DEBUG_OPENCL
Definition darktable.h:744
@ DT_DEBUG_GTK
Definition darktable.h:740
@ DT_DEBUG_PIPE
Definition darktable.h:763
@ DT_DEBUG_PIPECACHE
Definition darktable.h:742
@ DT_DEBUG_HISTORY
Definition darktable.h:762
@ DT_DEBUG_CAMERA_SUPPORT
Definition darktable.h:753
@ DT_DEBUG_NAN
Definition darktable.h:748
@ DT_DEBUG_DEMOSAIC
Definition darktable.h:759
@ DT_DEBUG_MEMORY
Definition darktable.h:746
@ DT_DEBUG_PERF
Definition darktable.h:741
@ DT_DEBUG_VERBOSE
Definition darktable.h:765
@ DT_DEBUG_PARAMS
Definition darktable.h:758
@ DT_DEBUG_CONTROL
Definition darktable.h:738
@ DT_DEBUG_COLORPROFILE
Definition darktable.h:766
@ DT_DEBUG_CACHE
Definition darktable.h:737
@ DT_DEBUG_ALWAYS
Definition darktable.h:735
@ DT_DEBUG_SIGNAL
Definition darktable.h:757
@ DT_DEBUG_PWSTORAGE
Definition darktable.h:743
@ DT_DEBUG_SHORTCUTS
Definition darktable.h:760
@ DT_DEBUG_IMAGEIO
Definition darktable.h:755
@ DT_DEBUG_DEV
Definition darktable.h:739
@ DT_DEBUG_NOCACHE_REUSE
Definition darktable.h:767
@ DT_DEBUG_IMPORT
Definition darktable.h:764
@ DT_DEBUG_IOPORDER
Definition darktable.h:754
@ DT_DEBUG_MASKS
Definition darktable.h:749
@ DT_DEBUG_TILING
Definition darktable.h:761
@ DT_DEBUG_SQL
Definition darktable.h:745
@ DT_DEBUG_LUA
Definition darktable.h:750
#define dt_gui_freeze_begin()
Definition darktable.h:900
#define dt_gui_freeze_end()
Definition darktable.h:901
#define omp_get_max_threads()
Definition darktable.h:266
static void * dt_alloc_align_internal(size_t size)
Definition darktable.h:421
static void dt_free_gpointer(gpointer ptr)
Definition darktable.h:485
#define dt_free(ptr)
Definition darktable.h:478
static void dt_get_times(dt_times_t *t)
Definition darktable.h:983
#define DT_DEBUG_SUPERVISOR
Definition darktable.h:774
static double dt_get_wtime(void)
Definition darktable.h:976
#define PATH_MAX
Definition darktable.h:1189
#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 darktable.h:293
void dt_database_cleanup_busy_statements(const struct dt_database_t *db)
Definition database.c:3716
void dt_database_optimize(const struct dt_database_t *db)
Definition database.c:3913
gboolean dt_database_snapshot(const struct dt_database_t *db)
Definition database.c:3979
void dt_database_perform_maintenance(const struct dt_database_t *db)
Definition database.c:3735
void dt_database_destroy(const dt_database_t *db)
Definition database.c:3633
gboolean dt_database_show_error(const dt_database_t *db)
Definition database.c:2651
char ** dt_database_snaps_to_remove(const struct dt_database_t *db)
Definition database.c:4237
gboolean dt_database_maybe_maintenance(const struct dt_database_t *db, const gboolean has_gui, const gboolean closing_time)
Definition database.c:3836
gboolean dt_database_get_lock_acquired(const dt_database_t *db)
Definition database.c:3711
dt_database_t * dt_database_init(const char *alternative, const gboolean load_data, const gboolean has_gui)
Definition database.c:3015
gboolean dt_database_maybe_snapshot(const struct dt_database_t *db)
Definition database.c:4029
void dt_datetime_init()
Definition datetime.c:30
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.
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:384
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Definition dtpthread.h:369
static int dt_pthread_rwlock_destroy(dt_pthread_rwlock_t *lock)
Definition dtpthread.h:447
static int dt_pthread_mutex_destroy(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:389
static int dt_pthread_rwlock_init(dt_pthread_rwlock_t *lock, const pthread_rwlockattr_t *attr)
Definition dtpthread.h:427
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:374
int supported(struct dt_imageio_module_storage_t *storage, struct dt_imageio_module_format_t *format)
Definition example.c:274
void dt_exif_set_exiv2_taglist()
Definition exif.cc:265
void dt_exif_init()
Definition exif.cc:4692
void dt_exif_cleanup()
Definition exif.cc:4732
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:161
int dt_film_open(const int32_t id)
Definition film.c:128
void dt_film_set_folder_status()
Definition film.c:514
int dt_film_import(const char *dirname)
Definition film.c:236
dt_job_t * dt_pathlist_import_create(int argc, char *argv[])
Definition film_jobs.c:115
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:39
ssize_t getline(char **lineptr, size_t *n, FILE *stream)
Definition getdelim.c:157
int dt_gui_gtk_init(dt_gui_gtk_t *gui)
Definition gtk.c:1183
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
void dt_gui_presets_init()
void dt_gui_presets_cleanup()
void dt_gui_throttle_init(void)
void dt_gui_throttle_cleanup(void)
GList * dt_guides_init()
Definition guides.c:580
void dt_guides_cleanup(GList *guides)
Definition guides.c:841
void dt_image_cache_cleanup(dt_image_cache_t *cache)
void dt_image_cache_init(dt_image_cache_t *cache)
void dt_image_cache_connect_info_changed_first(const struct dt_control_signal_t *ctlsig)
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:3052
void dt_iop_load_modules_so(void)
Definition imageop.c:1558
void dt_iop_unload_modules_so()
Definition imageop.c:1627
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:1096
GList * dt_ioppr_get_iop_order_rules()
Return the list of ordering rules (prev/next constraints).
Definition iop_order.c:793
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:1966
int dt_control_add_job(dt_control_t *control, dt_job_queue_t queue_id, _dt_job_t *job)
Definition jobs.c:405
@ DT_JOB_QUEUE_USER_BG
Definition jobs.h:55
dt_l10n_t * dt_l10n_init(gboolean init_list)
Definition l10n.c:311
void dt_lib_init(dt_lib_t *lib)
Definition lib.c:1324
void dt_lib_cleanup(dt_lib_t *lib)
Definition lib.c:1332
float *const restrict const size_t k
void dt_mipmap_cache_init(dt_mipmap_cache_t *cache)
void dt_mipmap_cache_cleanup(dt_mipmap_cache_t *cache)
size_t size
Definition mipmap_cache.c:3
#define dt_mipmap_cache_get(A, B, C, D, E, F)
@ DT_MIPMAP_BLOCKING
#define dt_mipmap_cache_release(A, B)
@ DT_MIPMAP_FULL
JsonParser * dt_noiseprofile_init(const char *alternative)
void dt_opencl_init(dt_opencl_t *cl, const gboolean exclude_opencl, const gboolean print_statistics)
Definition opencl.c:1019
void dt_opencl_cleanup(dt_opencl_t *cl)
Definition opencl.c:1310
gboolean dt_opencl_finish(const int devid)
Definition opencl.c:1375
void dt_dev_pixelpipe_cache_cleanup(dt_dev_pixelpipe_cache_t *cache)
dt_dev_pixelpipe_cache_t * dt_dev_pixelpipe_cache_init(size_t max_memory)
static void dt_points_cleanup(dt_points_t *p)
Definition points.h:65
static void dt_points_init(dt_points_t *p, const unsigned int num_threads)
Definition points.h:55
void dt_control_progress_init(struct dt_control_t *control)
Definition progress.c:224
const dt_pwstorage_t * dt_pwstorage_new()
Definition pwstorage.c:61
void dt_pwstorage_destroy(const dt_pwstorage_t *pwstorage)
Definition pwstorage.c:182
void dt_set_rlimits()
void dt_selection_free(dt_selection_t *selection)
Definition selection.c:252
dt_selection_t * dt_selection_new()
Definition selection.c:238
void dt_sentry_shutdown(void)
Definition sentry.c:624
void dt_sentry_init(const gboolean have_gui)
Definition sentry.c:620
void dt_control_signal_cleanup(dt_control_signal_t *ctlsig)
Definition signal.c:286
dt_control_signal_t * dt_control_signal_init()
Definition signal.c:253
@ DT_DEBUG_SIGNAL_ACT_DISCONNECT
Definition signal.h:341
@ DT_DEBUG_SIGNAL_ACT_CONNECT
Definition signal.h:340
@ DT_DEBUG_SIGNAL_ACT_RAISE
Definition signal.h:339
@ DT_DEBUG_SIGNAL_ACT_PRINT_TRACE
Definition signal.h:342
@ DT_SIGNAL_DEVELOP_INITIALIZE
This signal is raised when darktable.develop is initialized.
Definition signal.h:169
@ DT_SIGNAL_METADATA_CHANGED
This signal is raised when metadata status (shown/hidden) or value has changed.
Definition signal.h:139
@ DT_SIGNAL_VIEWMANAGER_THUMBTABLE_ACTIVATE
Definition signal.h:95
@ 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:64
@ DT_SIGNAL_CONTROL_REDRAW_ALL
This signal is raised when dt_control_queue_redraw() is called. no param, no returned value.
Definition signal.h:69
@ DT_SIGNAL_MASK_CHANGED
Definition signal.h:312
@ DT_SIGNAL_FOLDER_SURVEY_CHANGED
Raised when the folder survey starts or stops monitoring. no param, no returned value.
Definition signal.h:330
@ DT_SIGNAL_DEVELOP_HISTORY_CHANGE
This signal is raised when develop history is changed no param, no returned value.
Definition signal.h:204
@ DT_SIGNAL_DEVELOP_IMAGE_CHANGED
This signal is raised when image is changed in darkroom.
Definition signal.h:221
@ 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:242
@ 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:261
@ DT_SIGNAL_IMAGES_ORDER_CHANGE
This signal is raised to request image order change.
Definition signal.h:150
@ 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:174
@ DT_SIGNAL_STYLE_CHANGED
This signal is raised when a style is added/deleted/changed
Definition signal.h:147
@ DT_SIGNAL_DARKROOM_UI_CHANGED
Signal that the darkroom GUI color changed.
Definition signal.h:224
@ 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:179
@ DT_SIGNAL_FILMROLLS_CHANGED
This signal is raised when a filmroll is deleted/changed but not imported.
Definition signal.h:156
@ 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:59
@ DT_SIGNAL_CONTROL_TOAST_REDRAW
This signal is raised when dt_control_toast_redraw() is called. no param, no returned value.
Definition signal.h:288
@ DT_SIGNAL_DEVELOP_MODULE_MOVED
This signal is raised when order of modules in pipeline is changed.
Definition signal.h:218
@ DT_SIGNAL_IMAGE_INFO_CHANGED
This signal is raised when any of image info has changed
Definition signal.h:144
@ DT_SIGNAL_PREFERENCES_CHANGE
This signal is raised after preferences have been changed no parameters no return.
Definition signal.h:273
@ 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:74
@ DT_SIGNAL_DEVELOP_MODULEGROUPS_SET
This signal is raised to request a modulegroups update. 1 : dt_iop_module_t *module,...
Definition signal.h:191
@ DT_SIGNAL_FILMROLLS_REMOVED
This signal is raised only when a filmroll is removed.
Definition signal.h:159
@ DT_SIGNAL_TAG_CHANGED
This signal is raised when a tag is added/deleted/changed
Definition signal.h:130
@ DT_SIGNAL_IMAGEIO_STORAGE_CHANGE
This signal is raised when a new storage module is loaded noparameters no return.
Definition signal.h:267
@ 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:103
@ 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:215
@ DT_SIGNAL_IMAGE_LOADED
This signal is raised when an asynchronous darkroom image load finishes. 1 : uint32_t the load reques...
Definition signal.h:231
@ DT_SIGNAL_SELECTION_CHANGED
This signal is raised when the selection is changed no param, no returned value.
Definition signal.h:127
@ DT_SIGNAL_CONTROL_PICKERDATA_READY
This signal is raised when new color picker data are available in darkroom. no param,...
Definition signal.h:293
@ DT_SIGNAL_CONTROL_PROFILE_CHANGED
This signal is raised when the screen profile has changed no param, no returned value.
Definition signal.h:236
@ DT_SIGNAL_COUNT
Definition signal.h:333
@ 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:111
@ 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:248
@ DT_SIGNAL_COLLECTION_CHANGED
This signal is raised when collection changed. To avoid leaking the list, dt_collection_t is connecte...
Definition signal.h:122
@ DT_SIGNAL_CONTROL_LOG_REDRAW
This signal is raised when dt_control_log_redraw() is called. no param, no returned value.
Definition signal.h:283
@ DT_SIGNAL_CONTROL_NAVIGATION_REDRAW
This signal is raised when dt_control_navigation_redraw() is called. no param, no returned value.
Definition signal.h:278
@ DT_SIGNAL_METADATA_UPDATE
Definition signal.h:305
@ 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:199
@ 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:81
void dt_gui_splash_close(void)
Definition splash.c:695
struct _GtkWidget GtkWidget
Definition splash.h:29
void dt_styles_cleanup(void)
unsigned __int64 uint64_t
Definition strptime.c:75
struct dt_dbus_t * dbus
Definition darktable.h:814
struct dt_undo_t * undo
Definition darktable.h:815
dt_pthread_mutex_t readFile_mutex
Definition darktable.h:831
struct dt_lib_t * lib
Definition darktable.h:799
int32_t unmuted_signal_dbg_acts
Definition darktable.h:858
struct dt_imageio_t * imageio
Definition darktable.h:812
struct dt_dev_pixelpipe_cache_t * pixelpipe_cache
Definition darktable.h:818
int32_t num_openmp_threads
Definition darktable.h:786
struct dt_l10n_t * l10n
Definition darktable.h:817
struct dt_gui_gtk_t * gui
Definition darktable.h:803
dt_pthread_rwlock_t database_threadsafe
Definition darktable.h:844
struct dt_colorspaces_t * color_profiles
Definition darktable.h:816
GList * capabilities
Definition darktable.h:795
struct dt_collection_t * collection
Definition darktable.h:809
struct dt_mipmap_cache_t * mipmap_cache
Definition darktable.h:804
struct dt_selection_t * selection
Definition darktable.h:810
GList * iop
Definition darktable.h:789
dt_pthread_mutex_t exiv2_threadsafe
Definition darktable.h:828
struct dt_sys_resources_t dtresources
Definition darktable.h:862
dt_pthread_mutex_t plugin_threadsafe
Definition darktable.h:821
dt_pthread_mutex_t capabilities_threadsafe
Definition darktable.h:824
GList * iop_order_list
Definition darktable.h:790
const struct dt_database_t * db
Definition darktable.h:807
GList * iop_order_rules
Definition darktable.h:791
struct dt_control_signal_t * signals
Definition darktable.h:802
struct dt_bauhaus_t * bauhaus
Definition darktable.h:806
struct dt_opencl_t * opencl
Definition darktable.h:813
GList * themes
Definition darktable.h:857
int32_t unmuted
Definition darktable.h:788
struct dt_image_cache_t * image_cache
Definition darktable.h:805
struct dt_develop_t * develop
Definition darktable.h:798
struct dt_points_t * points
Definition darktable.h:811
dt_pthread_mutex_t pipeline_threadsafe
Definition darktable.h:836
struct dt_view_manager_t * view_manager
Definition darktable.h:800
JsonParser * noiseprofile_parser
Definition darktable.h:796
GList * guides
Definition darktable.h:855
gboolean unmuted_signal_dbg[DT_SIGNAL_COUNT]
Definition darktable.h:859
char * main_message
Definition darktable.h:865
char * progname
Definition darktable.h:846
struct dt_conf_t * conf
Definition darktable.h:797
const struct dt_pwstorage_t * pwstorage
Definition darktable.h:808
double start_wtime
Definition darktable.h:856
struct dt_control_t * control
Definition darktable.h:801
Definition conf.h:89
char * key
Definition conf.h:90
char * value
Definition conf.h:91
dt_pthread_mutex_t run_mutex
Definition control.h:260
int32_t running
Definition control.h:258
dt_pthread_mutex_t log_mutex
Definition control.h:244
GDBusConnection * dbus_connection
Definition dbus.h:38
cairo_surface_t * surface
Definition gtk.h:169
dt_accels_t * accels
Definition gtk.h:199
dt_ui_t * ui
Definition gtk.h:165
GtkWidget * scroll_to[2]
Definition gtk.h:227
gboolean culling_mode
Definition gtk.h:192
Definition lib.h:54
int num_devs
Definition opencl.h:263
int inited
Definition opencl.h:259
size_t pixelpipe_memory
Definition darktable.h:781
double clock
Definition darktable.h:870
double user
Definition darktable.h:871
void dt_supervisor_init(void)
Definition supervisor.c:283
void dt_supervisor_cleanup(void)
Definition supervisor.c:292
void dt_set_signal_handlers()
void dt_set_darktable_tags()
Definition tags.c:618
void dt_tags_cleanup(void)
Definition tags.c:1932
void dt_telemetry_shutdown(void)
Definition telemetry.c:451
void dt_telemetry_init(const gboolean have_gui)
Definition telemetry.c:447
#define MAX(a, b)
Definition thinplate.c:29
void dt_undo_cleanup(dt_undo_t *self)
Definition undo.c:76
dt_undo_t * dt_undo_init(void)
Definition undo.c:50
gchar * dt_util_normalize_path(const gchar *_input)
Definition utility.c:680
void dt_view_manager_cleanup(dt_view_manager_t *vm)
Definition view.c:132
void dt_view_manager_init(dt_view_manager_t *vm)
Definition view.c:115
void dt_view_manager_gui_init(dt_view_manager_t *vm)
Definition view.c:123
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)