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 Copyright (C) 2026 Guillaume Stutin.
37
38 darktable is free software: you can redistribute it and/or modify
39 it under the terms of the GNU General Public License as published by
40 the Free Software Foundation, either version 3 of the License, or
41 (at your option) any later version.
42
43 darktable is distributed in the hope that it will be useful,
44 but WITHOUT ANY WARRANTY; without even the implied warranty of
45 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46 GNU General Public License for more details.
47
48 You should have received a copy of the GNU General Public License
49 along with darktable. If not, see <http://www.gnu.org/licenses/>.
50*/
51
52#include "widgets/bauhaus.h"
53#include "common/paths.h" // DT_PATH_MAX
55#include "common/image.h"
56#include "common/selection.h"
59#include "common/utility.h"
60#include "common/variables.h"
61#include "common/conf.h"
62#include "control/signal.h"
64#include "widgets/button.h"
65#include "widgets/paint.h"
66#include "gui/application.h"
67#include "widgets/gtkentry.h"
69#ifdef GDK_WINDOWING_QUARTZ
70#endif
71#include <glib.h>
72#include <glib/gstdio.h>
73#include <stdio.h>
74#include <stdlib.h>
76
77DT_MODULE(3)
78
85
86// gui data
93
94// saved params
101
102
103const char *name(const struct dt_imageio_module_storage_t *self)
104{
105 return _("File on disk");
106}
107
108void *legacy_params(dt_imageio_module_storage_t *self, const void *const old_params,
109 const size_t old_params_size, const int old_version, const int new_version,
110 size_t *new_size)
111{
112 if(old_version == 1 && new_version == 3)
113 {
114 typedef struct dt_imageio_disk_v1_t
115 {
116 char filename[1024];
118 gboolean overwrite;
119 } dt_imageio_disk_v1_t;
120
122 dt_imageio_disk_v1_t *o = (dt_imageio_disk_v1_t *)old_params;
123
124 g_strlcpy(n->filename, o->filename, sizeof(n->filename));
126
127 *new_size = self->params_size(self);
128 return n;
129 }
130 if(old_version == 2 && new_version == 3)
131 {
132 typedef struct dt_imageio_disk_v2_t
133 {
134 char filename[DT_MAX_PATH_FOR_PARAMS];
135 gboolean overwrite;
137 } dt_imageio_disk_v2_t;
138
140 dt_imageio_disk_v2_t *o = (dt_imageio_disk_v2_t *)old_params;
141
142 g_strlcpy(n->filename, o->filename, sizeof(n->filename));
144
145 *new_size = self->params_size(self);
146 return n;
147 }
148 return NULL;
149}
150
151// Same separator handling as import.c's own path-building pipeline (see dt_cleanup_separators()
152// in common/utility.c, used through _path_cleanup() in control/jobs/import_jobs.c): normalize to
153// the current OS's separator instead of literally escaping '\' into '\\', which is what used to
154// make the entry display a doubled backslash on Windows. dt_variables_expand() never treats '\'
155// as special, so there is nothing here for that escaping to have protected against.
157{
158 disk_t *d = (disk_t *)self->gui_data;
160 GtkFileChooserNative *filechooser = gtk_file_chooser_native_new(
161 _("select directory"), GTK_WINDOW(win), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
162 _("_select as output destination"), _("_cancel"));
163
164 gchar *old = g_strdup(gtk_entry_get_text(d->entry));
165 char *c = g_strstr_len(old, -1, "$");
166 if(c) *c = '\0';
167 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechooser), old);
168 dt_free(old);
169 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT)
170 {
171 gchar *dir = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
172 char *composed = g_build_filename(dir, "$(FILE_NAME)", NULL);
173 gchar *cleaned = dt_cleanup_separators(composed);
174
175 gtk_entry_set_text(GTK_ENTRY(d->entry), cleaned); // the signal handler will write this to conf
176 gtk_editable_set_position(GTK_EDITABLE(d->entry), strlen(cleaned));
177 dt_free(dir);
178 dt_free(composed);
179 dt_free(cleaned);
180 }
181 g_object_unref(filechooser);
182}
183
184// Mirrors import.c's _set_test_path(): resolve the current path pattern against the first
185// selected image, so the user can see what the export will actually be named before running it.
187{
188 const int32_t imgid = dt_selection_get_first_id(dt_selection_get_global());
189 const gchar *pattern = gtk_entry_get_text(d->entry);
190
191 if(imgid <= UNKNOWN_IMAGE || !pattern[0])
192 {
193 gtk_label_set_text(GTK_LABEL(d->preview), _("select an image to preview the export path"));
194 return;
195 }
196
197 char input_dir[DT_PATH_MAX] = { 0 };
198 gboolean from_cache = FALSE;
199 dt_image_full_path(imgid, input_dir, sizeof(input_dir), &from_cache, __FUNCTION__);
200
203 vp->filename = input_dir;
204 vp->jobcode = "export";
205 vp->imgid = imgid;
206 vp->sequence = 1;
207
208 gchar *fixed_path = dt_util_fix_path(pattern);
209 gchar *expanded = dt_variables_expand(vp, fixed_path, TRUE);
210 dt_free(fixed_path);
211
213 dt_imageio_module_data_t *fdata = mformat ? mformat->get_params(mformat) : NULL;
214 gchar *full = g_strdup_printf("%s.%s", expanded, fdata ? mformat->extension(fdata) : "");
215 if(fdata) mformat->free_params(mformat, fdata);
216 dt_free(expanded);
217
218 gtk_label_set_text(GTK_LABEL(d->preview), full);
219 dt_free(full);
220
222}
223
224static void entry_changed_callback(GtkEntry *entry, gpointer user_data)
225{
227 disk_t *d = (disk_t *)self->gui_data;
228 dt_conf_set_string("plugins/imageio/storage/disk/file_directory", gtk_entry_get_text(entry));
230}
231
232static void _selection_changed_callback(gpointer instance, dt_imageio_module_storage_t *self)
233{
235}
236
237static void onsave_action_toggle_callback(GtkWidget *widget, gpointer user_data)
238{
239 dt_conf_set_int("plugins/imageio/storage/disk/overwrite", dt_bauhaus_combobox_get(widget));
240}
241
243{
244 disk_t *d = (disk_t *)malloc(sizeof(disk_t));
245 self->gui_data = (void *)d;
246 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
247 GtkWidget *widget;
248
249 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
250 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(hbox), TRUE, FALSE, 0);
251
252 widget = gtk_entry_new();
254 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
255 const char *dir = dt_conf_get_string_const("plugins/imageio/storage/disk/file_directory");
256 if(dir)
257 {
258 gtk_entry_set_text(GTK_ENTRY(widget), dir);
259 gtk_editable_set_position(GTK_EDITABLE(widget), strlen(dir));
260 }
261
263
264 d->entry = GTK_ENTRY(widget);
265 gtk_entry_set_width_chars(GTK_ENTRY(widget), 0);
266 gtk_widget_set_tooltip_text(widget,
267 _("enter the path where to put exported images\nvariables support bash like string manipulation\n"
268 "type '$(' to activate the completion and see the list of variables"));
269 g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(entry_changed_callback), self);
270
272 gtk_widget_set_tooltip_text(widget, _("select directory"));
273 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
274 g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(button_clicked), self);
275
277 dt_bauhaus_widget_set_label(d->onsave_action, N_("on conflict"));
278 gtk_widget_set_tooltip_text(d->onsave_action, _("Expected behaviour if the current naming pattern\n"
279 "produces a filename that already exists."));
280 dt_bauhaus_combobox_add(d->onsave_action, _("create unique filename"));
281 dt_bauhaus_combobox_add(d->onsave_action, _("overwrite"));
282 dt_bauhaus_combobox_add(d->onsave_action, _("skip"));
283 gtk_box_pack_start(GTK_BOX(self->widget), d->onsave_action, TRUE, TRUE, 0);
284 g_signal_connect(G_OBJECT(d->onsave_action), "value-changed", G_CALLBACK(onsave_action_toggle_callback), self);
285 dt_bauhaus_combobox_set(d->onsave_action, dt_conf_get_int("plugins/imageio/storage/disk/overwrite"));
286
287 d->preview = gtk_label_new("");
288 gtk_widget_set_halign(d->preview, GTK_ALIGN_START);
289 gtk_label_set_line_wrap(GTK_LABEL(d->preview), TRUE);
290 gtk_label_set_max_width_chars(GTK_LABEL(d->preview), 60);
291 gtk_box_pack_start(GTK_BOX(self->widget), d->preview, TRUE, TRUE, 0);
293
295 G_CALLBACK(_selection_changed_callback), self);
296}
297
303
305{
306 disk_t *d = (disk_t *)self->gui_data;
307 // global default can be annoying:
308 // gtk_entry_set_text(GTK_ENTRY(d->entry), "$(FILE_FOLDER)/darktable_exported/$(FILE_NAME)");
309 gtk_entry_set_text(d->entry, dt_confgen_get("plugins/imageio/storage/disk/file_directory", DT_DEFAULT));
310 dt_bauhaus_combobox_set(d->onsave_action, dt_confgen_get_int("plugins/imageio/storage/disk/overwrite", DT_DEFAULT));
311 dt_conf_set_string("plugins/imageio/storage/disk/file_directory", gtk_entry_get_text(d->entry));
312 dt_conf_set_int("plugins/imageio/storage/disk/overwrite", dt_bauhaus_combobox_get(d->onsave_action));
313}
314
315/* Guards the choice of an output filename, which spans images: two threads exporting
316 * different images can otherwise settle on the same free name and one silently overwrites
317 * the other. Module-owned, and initialised through pthread_once so it is recursive like
318 * every other lock created with dt_pthread_mutex_init(..., NULL). */
319static dt_pthread_mutex_t _filename_lock;
320static pthread_once_t _filename_lock_once = PTHREAD_ONCE_INIT;
321
322static void _filename_lock_init(void)
323{
325}
326
327int store(dt_imageio_module_storage_t *self, dt_imageio_module_data_t *sdata, const int32_t imgid,
328 dt_imageio_module_format_t *format, dt_imageio_module_data_t *fdata, const double scale_factor,
329 const int num, const int total,
330 const gboolean high_quality, const gboolean export_masks,
331 dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent,
332 dt_export_metadata_t *metadata)
333{
335
336 char filename[DT_PATH_MAX] = { 0 };
337 char input_dir[DT_PATH_MAX] = { 0 };
338 char pattern[DT_MAX_PATH_FOR_PARAMS];
339 g_strlcpy(pattern, d->filename, sizeof(pattern));
340 gboolean from_cache = FALSE;
341 dt_image_full_path(imgid, input_dir, sizeof(input_dir), &from_cache, __FUNCTION__);
342
343 /* Private expansion context, per call.
344 *
345 * This used to write into d->vp -- ONE dt_variables_params_t owned by the storage module
346 * and reused by every image in the export. store() runs in parallel, so two threads
347 * exporting different images both assigned ->imgid/->sequence there and then expanded,
348 * and the lock around the whole block was what kept that from producing a filename built
349 * from another image's variables. A per-call context removes the shared state instead of
350 * serializing access to it, which is the actual fix: nothing to race, nothing to lock. */
351 dt_variables_params_t *vp = NULL;
354
355 gboolean fail = FALSE;
356 /* Still serialized, but only for what genuinely spans images: choosing a filename nobody
357 * else has taken. That is a check-then-create across the whole export, which no per-image
358 * lock can cover. The lock is this module's own now, not a process-wide "plugin" mutex
359 * shared with the watermark renderer and rawspeed's metadata init.
360 *
361 * The mechanism is still not airtight -- another process can create the file between the
362 * g_file_test() below and the format writer opening it. The airtight version claims the
363 * name with O_CREAT|O_EXCL and retries on EEXIST, which needs the format writers to accept
364 * a descriptor instead of a path. Recorded in doc/lock-audit.md. */
367 {
368try_again:
369 // avoid braindead export which is bound to overwrite at random:
370 if(total > 1 && !g_strrstr(pattern, "$"))
371 {
372 snprintf(pattern + strlen(pattern), sizeof(pattern) - strlen(pattern), "_$(SEQUENCE)");
373 }
374
375 gchar *fixed_path = dt_util_fix_path(pattern);
376 g_strlcpy(pattern, fixed_path, sizeof(pattern));
377 dt_free(fixed_path);
378
379 vp->filename = input_dir;
380 vp->jobcode = "export";
381 vp->imgid = imgid;
382 vp->sequence = num;
383
384 gchar *result_filename = dt_variables_expand(vp, pattern, TRUE);
385 g_strlcpy(filename, result_filename, sizeof(filename));
386 dt_free(result_filename);
387
388 // if filenamepattern is a directory just add ${FILE_NAME} as default..
389 // this can happen if the filename component of the pattern is an empty variable
390 char last_char = *(filename + strlen(filename) - 1);
391 if(last_char == '/' || last_char == '\\')
392 {
393 // add to the end of the original pattern without caring about a
394 // potentially added "_$(SEQUENCE)"
395 if (snprintf(pattern, sizeof(pattern), "%s" G_DIR_SEPARATOR_S "$(FILE_NAME)", d->filename) < sizeof(pattern))
396 goto try_again;
397 }
398
399 char *output_dir = g_path_get_dirname(filename);
400
401 if(g_mkdir_with_parents(output_dir, 0755))
402 {
403 dt_control_alert(_("Export failed"), _("could not create directory!"), output_dir);
404 fail = TRUE;
405 goto failed;
406 }
407 if(g_access(output_dir, W_OK | X_OK) != 0)
408 {
409 dt_control_alert(_("Export failed"), _("could not write to directory!"), 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, scale_factor, TRUE, TRUE, export_masks, icc_type,
452 icc_filename, icc_intent, self, sdata, num, total, metadata) != 0)
453 {
454 dt_control_alert(_("Export failed"), _("could not export to file!"), filename);
455 return 1;
456 }
457
458 fprintf(stderr, "[export_job] exported to `%s'\n", filename);
459 dt_control_log(ngettext("%d/%d exported to `%s'", "%d/%d exported to `%s'", num),
460 num, total, filename);
461 return 0;
462}
463
465{
466 return sizeof(dt_imageio_disk_t) - sizeof(void *);
467}
468
470{
471}
472
474{
476
477 const char *text = dt_conf_get_string_const("plugins/imageio/storage/disk/file_directory");
478 g_strlcpy(d->filename, text, sizeof(d->filename));
479
480 d->onsave_action = dt_conf_get_int("plugins/imageio/storage/disk/overwrite");
481
482 d->vp = NULL;
484
485 return d;
486}
487
495
496int set_params(dt_imageio_module_storage_t *self, const void *params, const int size)
497{
499 disk_t *g = (disk_t *)self->gui_data;
500
501 if(size != self->params_size(self)) return 1;
502
503 gtk_entry_set_text(GTK_ENTRY(g->entry), d->filename);
504 gtk_editable_set_position(GTK_EDITABLE(g->entry), strlen(d->filename));
505 dt_bauhaus_combobox_set(g->onsave_action, d->onsave_action);
506 return 0;
507}
508
510{
511 disk_t *g = (disk_t *)self->gui_data;
512 if(dt_bauhaus_combobox_get(g->onsave_action) == DT_EXPORT_ONCONFLICT_OVERWRITE && dt_conf_get_bool("plugins/lighttable/export/ask_before_export_overwrite"))
513 {
514 return g_strdup(_("you are going to export on overwrite mode, this will overwrite any existing images\n\n"
515 "do you really want to continue?"));
516 }
517 else
518 {
519 return NULL;
520 }
521}
522
523// clang-format off
524// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
525// vim: shiftwidth=2 expandtab tabstop=2 cindent
526// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
527// 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:2139
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2093
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:1701
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:1827
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.
@ DT_DEFAULT
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.
void dt_control_alert(const char *title, const char *message, const char *item)
Tell the user something that must not go unseen: what it says stays true after a toast would have fad...
Definition control.c:883
void dt_control_log(const char *msg,...)
Definition control.c:839
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
Definition darktable.c:649
void * get_params(dt_imageio_module_storage_t *self)
Definition disk.c:473
static void _filename_lock_init(void)
Definition disk.c:322
char * ask_user_confirmation(dt_imageio_module_storage_t *self)
Definition disk.c:509
void gui_cleanup(dt_imageio_module_storage_t *self)
Definition disk.c:298
void free_params(dt_imageio_module_storage_t *self, dt_imageio_module_data_t *params)
Definition disk.c:488
static void onsave_action_toggle_callback(GtkWidget *widget, gpointer user_data)
Definition disk.c:237
size_t params_size(dt_imageio_module_storage_t *self)
Definition disk.c:464
void gui_init(dt_imageio_module_storage_t *self)
Definition disk.c:242
static void _update_preview(disk_t *d)
Definition disk.c:186
void init(dt_imageio_module_storage_t *self)
Definition disk.c:469
void gui_reset(dt_imageio_module_storage_t *self)
Definition disk.c:304
dt_disk_onconflict_actions_t
Definition disk.c:80
@ DT_EXPORT_ONCONFLICT_SKIP
Definition disk.c:83
@ DT_EXPORT_ONCONFLICT_UNIQUEFILENAME
Definition disk.c:81
@ DT_EXPORT_ONCONFLICT_OVERWRITE
Definition disk.c:82
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:108
static dt_pthread_mutex_t _filename_lock
Definition disk.c:319
static pthread_once_t _filename_lock_once
Definition disk.c:320
int set_params(dt_imageio_module_storage_t *self, const void *params, const int size)
Definition disk.c:496
static void button_clicked(GtkWidget *widget, dt_imageio_module_storage_t *self)
Definition disk.c:156
static void entry_changed_callback(GtkEntry *entry, gpointer user_data)
Definition disk.c:224
static void _selection_changed_callback(gpointer instance, dt_imageio_module_storage_t *self)
Definition disk.c:232
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 double scale_factor, 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()
static const dt_iop_drawlayer_params_t * params
Definition layers.h:80
#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 o
#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:411
struct dt_control_signal_t * dt_control_signal_get_global(void)
Definition darktable.c:619
@ DT_SIGNAL_SELECTION_CHANGED
This signal is raised when the selection is changed no param, no returned value.
Definition signal.h:131
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
Definition signal.h:400
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:88
GtkWidget * onsave_action
Definition disk.c:90
GtkEntry * entry
Definition disk.c:89
GtkWidget * preview
Definition disk.c:91
dt_variables_params_t * vp
Definition disk.c:99
dt_disk_onconflict_actions_t onsave_action
Definition disk.c:98
char filename[DT_MAX_PATH_FOR_PARAMS]
Definition disk.c:97
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:1091
gchar * dt_util_fix_path(const gchar *path)
Definition utility.c:249
#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