Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
disk.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010 Andrea Purracchio.
4 Copyright (C) 2010-2011, 2013 Henrik Andersson.
5 Copyright (C) 2010-2013 johannes hanika.
6 Copyright (C) 2010 Stuart Henderson.
7 Copyright (C) 2011 Antony Dovgal.
8 Copyright (C) 2011 Moritz Lipp.
9 Copyright (C) 2011 Olivier Tribout.
10 Copyright (C) 2011 Robert Bieber.
11 Copyright (C) 2011-2018, 2020 Tobias Ellinghaus.
12 Copyright (C) 2012 Christian Tellefsen.
13 Copyright (C) 2012 Richard Wonka.
14 Copyright (C) 2013 Jake Probst.
15 Copyright (C) 2013-2015 Jérémy Rosen.
16 Copyright (C) 2013-2015, 2018-2021 Pascal Obry.
17 Copyright (C) 2013-2016 Roman Lebedev.
18 Copyright (C) 2014 Pascal de Bruijn.
19 Copyright (C) 2015 Pedro Côrte-Real.
20 Copyright (C) 2017 parafin.
21 Copyright (C) 2018 Dan Torop.
22 Copyright (C) 2019, 2023, 2025 Aurélien PIERRE.
23 Copyright (C) 2019 Denis Dyakov.
24 Copyright (C) 2019 Edgardo Hoszowski.
25 Copyright (C) 2019, 2022 Philippe Weyland.
26 Copyright (C) 2020-2021 Chris Elston.
27 Copyright (C) 2020-2021 Diederik Ter Rahe.
28 Copyright (C) 2020 Marco.
29 Copyright (C) 2021 Hanno Schwalm.
30 Copyright (C) 2021 Hubert Kowalski.
31 Copyright (C) 2021 Marco Carrarini.
32 Copyright (C) 2021 Mark-64.
33 Copyright (C) 2021 Ralf Brown.
34 Copyright (C) 2022 Martin Bařinka.
35 Copyright (C) 2023 Ricky Moon.
36
37 darktable is free software: you can redistribute it and/or modify
38 it under the terms of the GNU General Public License as published by
39 the Free Software Foundation, either version 3 of the License, or
40 (at your option) any later version.
41
42 darktable is distributed in the hope that it will be useful,
43 but WITHOUT ANY WARRANTY; without even the implied warranty of
44 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45 GNU General Public License for more details.
46
47 You should have received a copy of the GNU General Public License
48 along with darktable. If not, see <http://www.gnu.org/licenses/>.
49*/
50
51#include "widgets/bauhaus.h"
52#include "common/paths.h" // DT_PATH_MAX
54#include "common/image.h"
55#include "common/selection.h"
58#include "common/utility.h"
59#include "common/variables.h"
60#include "common/conf.h"
61#include "control/signal.h"
63#include "widgets/button.h"
64#include "widgets/paint.h"
65#include "gui/application.h"
66#include "widgets/gtkentry.h"
68#ifdef GDK_WINDOWING_QUARTZ
69#endif
70#include <glib.h>
71#include <glib/gstdio.h>
72#include <stdio.h>
73#include <stdlib.h>
75
76DT_MODULE(3)
77
84
85// gui data
92
93// saved params
100
101
102const char *name(const struct dt_imageio_module_storage_t *self)
103{
104 return _("File on disk");
105}
106
107void *legacy_params(dt_imageio_module_storage_t *self, const void *const old_params,
108 const size_t old_params_size, const int old_version, const int new_version,
109 size_t *new_size)
110{
111 if(old_version == 1 && new_version == 3)
112 {
113 typedef struct dt_imageio_disk_v1_t
114 {
115 char filename[1024];
117 gboolean overwrite;
118 } dt_imageio_disk_v1_t;
119
121 dt_imageio_disk_v1_t *o = (dt_imageio_disk_v1_t *)old_params;
122
123 g_strlcpy(n->filename, o->filename, sizeof(n->filename));
125
126 *new_size = self->params_size(self);
127 return n;
128 }
129 if(old_version == 2 && new_version == 3)
130 {
131 typedef struct dt_imageio_disk_v2_t
132 {
133 char filename[DT_MAX_PATH_FOR_PARAMS];
134 gboolean overwrite;
136 } dt_imageio_disk_v2_t;
137
139 dt_imageio_disk_v2_t *o = (dt_imageio_disk_v2_t *)old_params;
140
141 g_strlcpy(n->filename, o->filename, sizeof(n->filename));
143
144 *new_size = self->params_size(self);
145 return n;
146 }
147 return NULL;
148}
149
150// Same separator handling as import.c's own path-building pipeline (see dt_cleanup_separators()
151// in common/utility.c, used through _path_cleanup() in control/jobs/import_jobs.c): normalize to
152// the current OS's separator instead of literally escaping '\' into '\\', which is what used to
153// make the entry display a doubled backslash on Windows. dt_variables_expand() never treats '\'
154// as special, so there is nothing here for that escaping to have protected against.
156{
157 disk_t *d = (disk_t *)self->gui_data;
159 GtkFileChooserNative *filechooser = gtk_file_chooser_native_new(
160 _("select directory"), GTK_WINDOW(win), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
161 _("_select as output destination"), _("_cancel"));
162
163 gchar *old = g_strdup(gtk_entry_get_text(d->entry));
164 char *c = g_strstr_len(old, -1, "$");
165 if(c) *c = '\0';
166 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechooser), old);
167 dt_free(old);
168 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT)
169 {
170 gchar *dir = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
171 char *composed = g_build_filename(dir, "$(FILE_NAME)", NULL);
172 gchar *cleaned = dt_cleanup_separators(composed);
173
174 gtk_entry_set_text(GTK_ENTRY(d->entry), cleaned); // the signal handler will write this to conf
175 gtk_editable_set_position(GTK_EDITABLE(d->entry), strlen(cleaned));
176 dt_free(dir);
177 dt_free(composed);
178 dt_free(cleaned);
179 }
180 g_object_unref(filechooser);
181}
182
183// Mirrors import.c's _set_test_path(): resolve the current path pattern against the first
184// selected image, so the user can see what the export will actually be named before running it.
186{
187 const int32_t imgid = dt_selection_get_first_id(dt_selection_get_global());
188 const gchar *pattern = gtk_entry_get_text(d->entry);
189
190 if(imgid <= UNKNOWN_IMAGE || !pattern[0])
191 {
192 gtk_label_set_text(GTK_LABEL(d->preview), _("select an image to preview the export path"));
193 return;
194 }
195
196 char input_dir[DT_PATH_MAX] = { 0 };
197 gboolean from_cache = FALSE;
198 dt_image_full_path(imgid, input_dir, sizeof(input_dir), &from_cache, __FUNCTION__);
199
202 vp->filename = input_dir;
203 vp->jobcode = "export";
204 vp->imgid = imgid;
205 vp->sequence = 1;
206
207 gchar *fixed_path = dt_util_fix_path(pattern);
208 gchar *expanded = dt_variables_expand(vp, fixed_path, TRUE);
209 dt_free(fixed_path);
210
212 dt_imageio_module_data_t *fdata = mformat ? mformat->get_params(mformat) : NULL;
213 gchar *full = g_strdup_printf("%s.%s", expanded, fdata ? mformat->extension(fdata) : "");
214 if(fdata) mformat->free_params(mformat, fdata);
215 dt_free(expanded);
216
217 gtk_label_set_text(GTK_LABEL(d->preview), full);
218 dt_free(full);
219
221}
222
223static void entry_changed_callback(GtkEntry *entry, gpointer user_data)
224{
226 disk_t *d = (disk_t *)self->gui_data;
227 dt_conf_set_string("plugins/imageio/storage/disk/file_directory", gtk_entry_get_text(entry));
229}
230
231static void _selection_changed_callback(gpointer instance, dt_imageio_module_storage_t *self)
232{
234}
235
236static void onsave_action_toggle_callback(GtkWidget *widget, gpointer user_data)
237{
238 dt_conf_set_int("plugins/imageio/storage/disk/overwrite", dt_bauhaus_combobox_get(widget));
239}
240
242{
243 disk_t *d = (disk_t *)malloc(sizeof(disk_t));
244 self->gui_data = (void *)d;
245 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
246 GtkWidget *widget;
247
248 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
249 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(hbox), TRUE, FALSE, 0);
250
251 widget = gtk_entry_new();
253 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
254 const char *dir = dt_conf_get_string_const("plugins/imageio/storage/disk/file_directory");
255 if(dir)
256 {
257 gtk_entry_set_text(GTK_ENTRY(widget), dir);
258 gtk_editable_set_position(GTK_EDITABLE(widget), strlen(dir));
259 }
260
262
263 d->entry = GTK_ENTRY(widget);
264 gtk_entry_set_width_chars(GTK_ENTRY(widget), 0);
265 gtk_widget_set_tooltip_text(widget,
266 _("enter the path where to put exported images\nvariables support bash like string manipulation\n"
267 "type '$(' to activate the completion and see the list of variables"));
268 g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(entry_changed_callback), self);
269
271 gtk_widget_set_tooltip_text(widget, _("select directory"));
272 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
273 g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(button_clicked), self);
274
276 dt_bauhaus_widget_set_label(d->onsave_action, N_("on conflict"));
277 gtk_widget_set_tooltip_text(d->onsave_action, _("Expected behaviour if the current naming pattern\n"
278 "produces a filename that already exists."));
279 dt_bauhaus_combobox_add(d->onsave_action, _("create unique filename"));
280 dt_bauhaus_combobox_add(d->onsave_action, _("overwrite"));
281 dt_bauhaus_combobox_add(d->onsave_action, _("skip"));
282 gtk_box_pack_start(GTK_BOX(self->widget), d->onsave_action, TRUE, TRUE, 0);
283 g_signal_connect(G_OBJECT(d->onsave_action), "value-changed", G_CALLBACK(onsave_action_toggle_callback), self);
284 dt_bauhaus_combobox_set(d->onsave_action, dt_conf_get_int("plugins/imageio/storage/disk/overwrite"));
285
286 d->preview = gtk_label_new("");
287 gtk_widget_set_halign(d->preview, GTK_ALIGN_START);
288 gtk_label_set_line_wrap(GTK_LABEL(d->preview), TRUE);
289 gtk_label_set_max_width_chars(GTK_LABEL(d->preview), 60);
290 gtk_box_pack_start(GTK_BOX(self->widget), d->preview, TRUE, TRUE, 0);
292
294 G_CALLBACK(_selection_changed_callback), self);
295}
296
302
304{
305 disk_t *d = (disk_t *)self->gui_data;
306 // global default can be annoying:
307 // gtk_entry_set_text(GTK_ENTRY(d->entry), "$(FILE_FOLDER)/darktable_exported/$(FILE_NAME)");
308 gtk_entry_set_text(d->entry, dt_confgen_get("plugins/imageio/storage/disk/file_directory", DT_DEFAULT));
309 dt_bauhaus_combobox_set(d->onsave_action, dt_confgen_get_int("plugins/imageio/storage/disk/overwrite", DT_DEFAULT));
310 dt_conf_set_string("plugins/imageio/storage/disk/file_directory", gtk_entry_get_text(d->entry));
311 dt_conf_set_int("plugins/imageio/storage/disk/overwrite", dt_bauhaus_combobox_get(d->onsave_action));
312}
313
314/* Guards the choice of an output filename, which spans images: two threads exporting
315 * different images can otherwise settle on the same free name and one silently overwrites
316 * the other. Module-owned, and initialised through pthread_once so it is recursive like
317 * every other lock created with dt_pthread_mutex_init(..., NULL). */
318static dt_pthread_mutex_t _filename_lock;
319static pthread_once_t _filename_lock_once = PTHREAD_ONCE_INIT;
320
321static void _filename_lock_init(void)
322{
324}
325
326int store(dt_imageio_module_storage_t *self, dt_imageio_module_data_t *sdata, const int32_t imgid,
327 dt_imageio_module_format_t *format, dt_imageio_module_data_t *fdata, const int num, const int total,
328 const gboolean high_quality, const gboolean export_masks,
329 dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent,
330 dt_export_metadata_t *metadata)
331{
333
334 char filename[DT_PATH_MAX] = { 0 };
335 char input_dir[DT_PATH_MAX] = { 0 };
336 char pattern[DT_MAX_PATH_FOR_PARAMS];
337 g_strlcpy(pattern, d->filename, sizeof(pattern));
338 gboolean from_cache = FALSE;
339 dt_image_full_path(imgid, input_dir, sizeof(input_dir), &from_cache, __FUNCTION__);
340
341 /* Private expansion context, per call.
342 *
343 * This used to write into d->vp -- ONE dt_variables_params_t owned by the storage module
344 * and reused by every image in the export. store() runs in parallel, so two threads
345 * exporting different images both assigned ->imgid/->sequence there and then expanded,
346 * and the lock around the whole block was what kept that from producing a filename built
347 * from another image's variables. A per-call context removes the shared state instead of
348 * serializing access to it, which is the actual fix: nothing to race, nothing to lock. */
349 dt_variables_params_t *vp = NULL;
352
353 gboolean fail = FALSE;
354 /* Still serialized, but only for what genuinely spans images: choosing a filename nobody
355 * else has taken. That is a check-then-create across the whole export, which no per-image
356 * lock can cover. The lock is this module's own now, not a process-wide "plugin" mutex
357 * shared with the watermark renderer and rawspeed's metadata init.
358 *
359 * The mechanism is still not airtight -- another process can create the file between the
360 * g_file_test() below and the format writer opening it. The airtight version claims the
361 * name with O_CREAT|O_EXCL and retries on EEXIST, which needs the format writers to accept
362 * a descriptor instead of a path. Recorded in doc/lock-audit.md. */
365 {
366try_again:
367 // avoid braindead export which is bound to overwrite at random:
368 if(total > 1 && !g_strrstr(pattern, "$"))
369 {
370 snprintf(pattern + strlen(pattern), sizeof(pattern) - strlen(pattern), "_$(SEQUENCE)");
371 }
372
373 gchar *fixed_path = dt_util_fix_path(pattern);
374 g_strlcpy(pattern, fixed_path, sizeof(pattern));
375 dt_free(fixed_path);
376
377 vp->filename = input_dir;
378 vp->jobcode = "export";
379 vp->imgid = imgid;
380 vp->sequence = num;
381
382 gchar *result_filename = dt_variables_expand(vp, pattern, TRUE);
383 g_strlcpy(filename, result_filename, sizeof(filename));
384 dt_free(result_filename);
385
386 // if filenamepattern is a directory just add ${FILE_NAME} as default..
387 // this can happen if the filename component of the pattern is an empty variable
388 char last_char = *(filename + strlen(filename) - 1);
389 if(last_char == '/' || last_char == '\\')
390 {
391 // add to the end of the original pattern without caring about a
392 // potentially added "_$(SEQUENCE)"
393 if (snprintf(pattern, sizeof(pattern), "%s" G_DIR_SEPARATOR_S "$(FILE_NAME)", d->filename) < sizeof(pattern))
394 goto try_again;
395 }
396
397 char *output_dir = g_path_get_dirname(filename);
398
399 if(g_mkdir_with_parents(output_dir, 0755))
400 {
401 fprintf(stderr, "[imageio_storage_disk] could not create directory: `%s'!\n", output_dir);
402 dt_control_log(_("could not create directory `%s'!"), output_dir);
403 fail = TRUE;
404 goto failed;
405 }
406 if(g_access(output_dir, W_OK | X_OK) != 0)
407 {
408 fprintf(stderr, "[imageio_storage_disk] could not write to directory: `%s'!\n", output_dir);
409 dt_control_log(_("could not write to directory `%s'!"), output_dir);
410 fail = TRUE;
411 goto failed;
412 }
413
414 const char *ext = format->extension(fdata);
415 char *c = filename + strlen(filename);
416 size_t filename_free_space = sizeof(filename) - (c - filename);
417 snprintf(c, filename_free_space, ".%s", ext);
418
419 /* prevent overwrite of files */
420 failed:
421 dt_free(output_dir);
422
423 if(!fail && d->onsave_action == DT_EXPORT_ONCONFLICT_UNIQUEFILENAME)
424 {
425 int seq = 1;
426 while(g_file_test(filename, G_FILE_TEST_EXISTS))
427 {
428 snprintf(c, filename_free_space, "_%.2d.%s", seq, ext);
429 seq++;
430 }
431 }
432
433 if(!fail && d->onsave_action == DT_EXPORT_ONCONFLICT_SKIP)
434 {
435 if(g_file_test(filename, G_FILE_TEST_EXISTS))
436 {
439 fprintf(stderr, "[export_job] skipping `%s'\n", filename);
440 dt_control_log(ngettext("%d/%d skipping `%s'", "%d/%d skipping `%s'", num),
441 num, total, filename);
442 return 0;
443 }
444 }
445 } // end of critical block
448 if(fail) return 1;
449
450 /* export image to file */
451 if(dt_imageio_export(imgid, filename, format, fdata, TRUE, TRUE, export_masks, icc_type,
452 icc_filename, icc_intent, self, sdata, num, total, metadata) != 0)
453 {
454 fprintf(stderr, "[imageio_storage_disk] could not export to file: `%s'!\n", filename);
455 dt_control_log(_("could not export to file `%s'!"), filename);
456 return 1;
457 }
458
459 fprintf(stderr, "[export_job] exported to `%s'\n", filename);
460 dt_control_log(ngettext("%d/%d exported to `%s'", "%d/%d exported to `%s'", num),
461 num, total, filename);
462 return 0;
463}
464
466{
467 return sizeof(dt_imageio_disk_t) - sizeof(void *);
468}
469
471{
472}
473
475{
477
478 const char *text = dt_conf_get_string_const("plugins/imageio/storage/disk/file_directory");
479 g_strlcpy(d->filename, text, sizeof(d->filename));
480
481 d->onsave_action = dt_conf_get_int("plugins/imageio/storage/disk/overwrite");
482
483 d->vp = NULL;
485
486 return d;
487}
488
490{
491 if(IS_NULL_PTR(params)) return;
494 dt_free(params);
495}
496
497int set_params(dt_imageio_module_storage_t *self, const void *params, const int size)
498{
500 disk_t *g = (disk_t *)self->gui_data;
501
502 if(size != self->params_size(self)) return 1;
503
504 gtk_entry_set_text(GTK_ENTRY(g->entry), d->filename);
505 gtk_editable_set_position(GTK_EDITABLE(g->entry), strlen(d->filename));
506 dt_bauhaus_combobox_set(g->onsave_action, d->onsave_action);
507 return 0;
508}
509
511{
512 disk_t *g = (disk_t *)self->gui_data;
513 if(dt_bauhaus_combobox_get(g->onsave_action) == DT_EXPORT_ONCONFLICT_OVERWRITE && dt_conf_get_bool("plugins/lighttable/export/ask_before_export_overwrite"))
514 {
515 return g_strdup(_("you are going to export on overwrite mode, this will overwrite any existing images\n\n"
516 "do you really want to continue?"));
517 }
518 else
519 {
520 return NULL;
521 }
522}
523
524// clang-format off
525// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
526// vim: shiftwidth=2 expandtab tabstop=2 cindent
527// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
528// clang-format on
void dt_accels_disconnect_on_text_input(GtkWidget *widget)
Disconnect accels while a text or search entry has the focus, and reconnect them when it loses it....
GtkWidget * dt_gui_main_window(void)
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2136
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2090
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
Definition bauhaus.c:1504
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
Definition bauhaus.c:1698
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:1824
GtkWidget * dtgtk_button_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
Definition button.c:135
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
int dt_conf_get_bool(const char *name)
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.
int dt_confgen_get_int(const char *name, dt_confgen_value_kind_t kind)
void dt_conf_set_string(const char *name, const char *val)
const char * dt_conf_get_string_const(const char *name)
Borrow the stored string for name without copying it.
const char * dt_confgen_get(const char *name, dt_confgen_value_kind_t kind)
One declared attribute of name from the generated XML, as text.
void dt_image_full_path(const int32_t imgid, char *pathname, size_t pathname_len, gboolean *from_cache, const char *calling_func)
Get the full path of an image out of the database.
@ DT_DEFAULT
Definition conf.h:135
void dt_control_log(const char *msg,...)
Definition control.c:824
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
Definition darktable.c:646
void * get_params(dt_imageio_module_storage_t *self)
Definition disk.c:474
static void _filename_lock_init(void)
Definition disk.c:321
char * ask_user_confirmation(dt_imageio_module_storage_t *self)
Definition disk.c:510
void gui_cleanup(dt_imageio_module_storage_t *self)
Definition disk.c:297
void free_params(dt_imageio_module_storage_t *self, dt_imageio_module_data_t *params)
Definition disk.c:489
static void onsave_action_toggle_callback(GtkWidget *widget, gpointer user_data)
Definition disk.c:236
size_t params_size(dt_imageio_module_storage_t *self)
Definition disk.c:465
void gui_init(dt_imageio_module_storage_t *self)
Definition disk.c:241
static void _update_preview(disk_t *d)
Definition disk.c:185
void init(dt_imageio_module_storage_t *self)
Definition disk.c:470
void gui_reset(dt_imageio_module_storage_t *self)
Definition disk.c:303
dt_disk_onconflict_actions_t
Definition disk.c:79
@ DT_EXPORT_ONCONFLICT_SKIP
Definition disk.c:82
@ DT_EXPORT_ONCONFLICT_UNIQUEFILENAME
Definition disk.c:80
@ DT_EXPORT_ONCONFLICT_OVERWRITE
Definition disk.c:81
void * legacy_params(dt_imageio_module_storage_t *self, const void *const old_params, const size_t old_params_size, const int old_version, const int new_version, size_t *new_size)
Definition disk.c:107
static dt_pthread_mutex_t _filename_lock
Definition disk.c:318
static pthread_once_t _filename_lock_once
Definition disk.c:319
int set_params(dt_imageio_module_storage_t *self, const void *params, const int size)
Definition disk.c:497
static void button_clicked(GtkWidget *widget, dt_imageio_module_storage_t *self)
Definition disk.c:155
static void entry_changed_callback(GtkEntry *entry, gpointer user_data)
Definition disk.c:223
static void _selection_changed_callback(gpointer instance, dt_imageio_module_storage_t *self)
Definition disk.c:231
GtkTreeStore * store
its model, owned by the view
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_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:117
void dt_gtkentry_setup_completion(GtkEntry *entry, const dt_gtkentry_completion_spec *compl_list, const char *trigger_char)
Definition gtkentry.c:176
const dt_gtkentry_completion_spec * dt_gtkentry_get_default_path_compl_list()
Definition gtkentry.c:200
#define DT_GUI_MODULE(x)
#define UNKNOWN_IMAGE
Definition image.h:78
int dt_imageio_export(const int32_t imgid, const char *filename, dt_imageio_module_format_t *format, dt_imageio_module_data_t *format_params, const gboolean high_quality, const gboolean copy_metadata, const gboolean export_masks, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent, dt_imageio_module_storage_t *storage, dt_imageio_module_data_t *storage_params, int num, int total, dt_export_metadata_t *metadata)
dt_imageio_module_format_t * dt_imageio_get_format()
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition macros.h:96
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
size_t size
Definition mipmap_cache.c:3
#define DT_MODULE(MODVER)
Instantiate the version handshake every module must export. Use once, at file scope,...
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
Definition paths.h:57
#define DT_MAX_PATH_FOR_PARAMS
Definition paths.h:65
const char * name
Definition pdf.h:90
dt_iop_color_intent_t
ICC rendering intent, as stored in iop params and in conf.
dt_colorspaces_color_profile_type_t
int32_t dt_selection_get_first_id(struct dt_selection_t *selection)
Definition selection.c:103
struct dt_selection_t * dt_selection_get_global(void)
Definition selection.c:80
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
Definition signal.h:407
struct dt_control_signal_t * dt_control_signal_get_global(void)
Definition darktable.c:616
@ DT_SIGNAL_SELECTION_CHANGED
This signal is raised when the selection is changed no param, no returned value.
Definition signal.h:130
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
Definition signal.h:396
char * dt_variables_expand(dt_variables_params_t *params, gchar *source, gboolean iterate)
void dt_variables_params_destroy(dt_variables_params_t *params)
void dt_variables_set_max_width_height(dt_variables_params_t *params, int max_width, int max_height)
void dt_variables_params_init(dt_variables_params_t **params)
Definition disk.c:87
GtkWidget * onsave_action
Definition disk.c:89
GtkEntry * entry
Definition disk.c:88
GtkWidget * preview
Definition disk.c:90
dt_variables_params_t * vp
Definition disk.c:98
dt_disk_onconflict_actions_t onsave_action
Definition disk.c:97
char filename[DT_MAX_PATH_FOR_PARAMS]
Definition disk.c:96
GModule *GtkWidget * widget
const gchar * filename
Definition variables.h:48
const gchar * jobcode
Definition variables.h:51
Telling the user something happened.
gchar * dt_cleanup_separators(gchar *string)
Definition utility.c:1059
gchar * dt_util_fix_path(const gchar *path)
Definition utility.c:226
#define DT_GUI_BOX_SPACING
void dtgtk_cairo_paint_directory(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
@ CPF_NONE