90 const int modversion,
const char *operation,
const void *module_params,
91 const int param_length,
const gboolean
enabled,
const void *blendop_params,
92 const int bl_length,
const int blendop_version,
const int multi_priority,
93 const char *multi_name,
const char *preset_name,
int *
legacy_params,
94 const gboolean presets);
127 const char *operation,
const void *module_params,
const int param_length,
128 const gboolean
enabled,
const void *blendop_params,
const int bl_length,
129 const int blendop_version,
const int multi_priority,
const char *multi_name,
130 const char *preset_name)
134 blendop_params, bl_length, blendop_version, multi_priority, multi_name, preset_name,
142 for(GList *history = g_list_first(history_list); history; history = g_list_next(history))
146 if(hist->module == module)
158 for(GList *history = g_list_nth(history_list, history_end -1); history; history = g_list_previous(history))
162 if(hist->module == module)
196 module->enabled = enabled;
198 hist->module =
module;
208 const void *src_params = params ? params :
module->params;
209 const int32_t src_size = params ?
params_size :
module->params_size;
227 hist->
hash =
module->hash;
234 int max_priority = 0;
235 for(
const GList *l = g_list_first(dev->
iop); l; l = g_list_next(l))
238 if(strcmp(
m->op, op))
continue;
239 max_priority =
MAX(max_priority,
m->multi_priority);
241 return max_priority + 1;
245 const int multi_priority)
247 const char *
name = (multi_name && *multi_name) ? multi_name : NULL;
248 dt_iop_module_t *
module = dt_iop_get_module_by_instance_name(dev->iop, op, name);
250 module = dt_iop_get_module_by_op_priority(dev->iop, op, multi_priority);
252 module = dt_iop_get_module_by_op_priority(dev->iop, op, 0);
257 const int multi_priority, gboolean use_next_priority)
266 dt_iop_module_t *
module = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
271 fprintf(stderr,
"[dt_dev_create_module_instance] can't load module %s\n", op);
276 module->instance = base->instance;
277 module->enabled = FALSE;
278 module->multi_priority = use_next_priority ? dt_dev_next_multi_priority_for_op(dev, op) : multi_priority;
279 g_strlcpy(module->multi_name, multi_name ? multi_name :
"",
sizeof(
module->multi_name));
281 dev->
iop = g_list_append(dev->
iop, module);
294 assert(sz_dest == sz_src);
295 if(sz_dest != sz_src)
return 1;
297 const int32_t sz =
MIN(sz_dest, sz_src);
298 if(sz > 0) memcpy(mod_dest->
params, mod_src->
params, sz);
313 "[dt_dev_history_item_from_source_history_item] invalid input: hist=%s hist_module=%s dest=%s out=%s\n",
314 hist_src ?
"yes" :
"no", hist_src && hist_src->module ?
"yes" :
"no",
315 mod_dest ?
"yes" :
"no", out_hist ?
"yes" :
"no");
323 "[dt_dev_history_item_from_source_history_item] allocation failed: src=%s multi='%s'\n",
324 hist_src->module->op, hist_src->module->
multi_name);
331 "[dt_dev_history_item_from_source_history_item] Forms copy failed: src=%s multi='%s'\n",
332 hist_src->module->op, hist_src->module->
multi_name);
337 gboolean raster_used =
FALSE;
338 gboolean drawn_used =
FALSE;
339 gboolean parametric_used =
FALSE;
340 GList *forms_snapshot = NULL;
349 "[dt_dev_history_item_from_source_history_item] %s '%s' uses drawn mask but there is no destination mask forms to snapshot\n",
350 hist_src->module->op, hist_src->module->
multi_name);
362 "[dt_dev_history_item_from_source_history_item] params update failed: src=%s multi='%s' "
363 "dest=%s multi='%s' src_params=%d dest_params=%d\n",
376 const gboolean paste_instances,
const char *source_label,
379 if(dest_imgid <= 0)
return 1;
405 const int ret_val =
dt_history_merge(&dev_dest, dev_src, dest_imgid, mod_list, merge_iop_order, mode,
406 paste_instances, source_label, batch);
428 for(GList *history = g_list_first(dev->history); history; history = g_list_next(history))
431 if(!hist || !hist->module)
continue;
433 if(strcmp(hist->module->op, module->op) == 0)
456 gboolean *reused_base) REQUIRES_SHARED(dev_dest->history_mutex)
459 *reused_base =
FALSE;
465 = dt_dev_get_module_instance(dev_dest, mod_src->op, mod_src->multi_name, mod_src->multi_priority);
466 if(module)
return module;
470 module = dt_iop_get_module_by_op_priority(dev_dest->iop, mod_src->op, -1);
478 module = dt_dev_create_module_instance(dev_dest, mod_src->op, mod_src->multi_name, mod_src->multi_priority, FALSE);
479 if(module) *created =
TRUE;
486 REQUIRES(dev_dest->history_mutex)
488 gboolean created =
FALSE;
489 gboolean reused_base =
FALSE;
490 dt_iop_module_t *
module = _history_merge_resolve_dest_instance(dev_dest, mod_src, &created, &reused_base);
495 dt_print(
DT_DEBUG_HISTORY,
"[dt_history_merge_module_into_history] %s (%s) will be overriden in target history by parameters from source history\n",
496 mod_src->name(), mod_src->multi_name);
500 dt_print(
DT_DEBUG_HISTORY,
"[dt_history_merge_module_into_history] %s (%s) will be inserted as a new instance in target history\n",
501 mod_src->name(), mod_src->multi_name);
505 dt_print(
DT_DEBUG_HISTORY,
"[dt_history_merge_module_into_history] %s (%s) will be enabled in target history with parameters from source history\n",
506 mod_src->name(), mod_src->multi_name);
509 g_strlcpy(module->multi_name, mod_src->multi_name,
sizeof(module->multi_name));
527 GList *result = NULL;
528 for(GList *h = g_list_first(hist); h; h = g_list_next(h))
536 dt_iop_module_t *
module = (old->module) ? old->module : dt_iop_get_module(old->op_name);
545 fprintf(stderr,
"[_duplicate_history] can't find base module for %s\n", old->
op_name);
557 new->forms = g_list_copy(old->
forms);
558 for(GList *form_node = new->forms; form_node; form_node = g_list_next(form_node))
562 result = g_list_prepend(result,
new);
565 return g_list_reverse(result);
664 GList *iop_order_list
729 if(dev->undo_history_depth == 0)
732 dev->undo_history_before_snapshot = NULL;
733 g_list_free_full(dev->undo_history_before_iop_order_list,
dt_free_gpointer);
734 dev->undo_history_before_iop_order_list = NULL;
735 dev->undo_history_before_end = 0;
742 dev->undo_history_depth++;
755 if(
IS_NULL_PTR(dev) || dev->undo_history_depth <= 0)
return;
757 dev->undo_history_depth--;
758 if(dev->undo_history_depth != 0)
return;
760 if(
IS_NULL_PTR(dev->undo_history_before_snapshot))
return;
764 hist->
before_end = dev->undo_history_before_end;
766 dev->undo_history_before_snapshot = NULL;
767 dev->undo_history_before_end = 0;
768 dev->undo_history_before_iop_order_list = NULL;
807 "[dt_dev_add_history_item_ext] archival history item %s at %i is past history limit (%i) and will be kept\n",
809 history = g_list_next(history);
820 gboolean earlier_entry =
FALSE;
821 if((hist->module->hide_enable_button || hist->module->default_enabled))
823 for(GList *prior_history = g_list_previous(history); prior_history;
824 prior_history = g_list_previous(prior_history))
827 if(!prior_hist || !prior_hist->module)
continue;
828 if(prior_hist->module->so == hist->module->so)
830 earlier_entry =
TRUE;
838 GList *link = history;
839 history = g_list_next(history);
842 if((!hist->module->hide_enable_button && !hist->module->default_enabled)
845 dt_print(
DT_DEBUG_HISTORY,
"[dt_dev_add_history_item_ext] removing obsoleted history item: %s at %i\n", hist->module->op, g_list_index(dev->history, hist));
849 g_list_index(dev->history, hist), dev->image_storage.id, hist->
enabled,
852 dev->history = g_list_delete_link(dev->history, link);
856 dt_print(
DT_DEBUG_HISTORY,
"[dt_dev_add_history_item_ext] obsoleted history item will be kept: %s at %i\n", hist->module->op, g_list_index(dev->history, hist));
862 gboolean force_new_item) REQUIRES(dev->history_mutex)
867 gboolean add_new_pipe_node =
FALSE;
873 module = dt_masks_get_mask_manager(dev);
877 force_new_item =
FALSE;
882 return add_new_pipe_node;
890 GList *last = g_list_last(dev->history);
891 gboolean new_is_old =
FALSE;
892 if(last && last->data && !force_new_item)
897 add_new_pipe_node =
FALSE;
912 const gboolean is_new_item = force_new_item || !new_is_old;
917 dev->history = g_list_append(dev->history, hist);
918 hist->
num = g_list_index(dev->history, hist);
920 module->name(), hist->
num);
930 module->name(), hist->
num);
934 if(
enable)
module->enabled = TRUE;
946 if(!include_masks && !
IS_NULL_PTR(module->blend_params) && module->blend_params->mask_id != 0)
952 GList *forms_snapshot = NULL;
955 dt_print(
DT_DEBUG_HISTORY,
"[dt_dev_add_history_item_ext] committing masks for module %s at history position %i\n", module->name(), hist->
num);
968 module->blend_params, forms_snapshot);
970 if(include_masks && hist->
forms)
971 dt_print(
DT_DEBUG_HISTORY,
"[dt_dev_add_history_item_ext] masks committed for module %s at history position %i\n", module->name(), hist->
num);
972 else if(include_masks)
973 dt_print(
DT_DEBUG_HISTORY,
"[dt_dev_add_history_item_ext] masks NOT committed for module %s at history position %i\n", module->name(), hist->
num);
985 module->multi_name, module->iop_order, hist->
num, dev->image_storage.id,
987 else if(old_param_hash != hist->
hash)
993 module->multi_name, module->iop_order, hist->
num, dev->image_storage.id,
998 module->multi_name, module->iop_order, hist->
num, dev->image_storage.id,
1002 return add_new_pipe_node;
1010 hist = g_list_previous(hist))
1026 gboolean add_new_pipe_node =
FALSE;
1037 const double _wrlock_wait_ms = (
dt_get_wtime() - _wrlock_wait_start) * 1000.0;
1038 if(_wrlock_wait_ms > 1.0)
1040 "[dt_dev_add_history_item_real] tid %lu (GUI thread) blocked %.2f ms acquiring history_mutex\n",
1041 (
unsigned long)pthread_self(), _wrlock_wait_ms);
1047 if(!
IS_NULL_PTR(module) && !
IS_NULL_PTR(module->post_history_commit))
module->post_history_commit(module);
1059 gboolean has_forms =
FALSE;
1086 const gboolean has_raster =
module && dt_iop_module_has_raster_mask(module);
1087 if(!
IS_NULL_PTR(module) && !(has_forms || has_raster) && !add_new_pipe_node)
1180 new_item->
forms = NULL;
1184 for(GList *form_node = new_item->
forms; form_node; form_node = g_list_next(form_node))
1201 GList *node = g_list_find(dev->
history, hist);
1225 for(
size_t i = 0;
i < G_N_ELEMENTS(pipes);
i++)
1243 REQUIRES_SHARED(dev->history_mutex)
1246 snapshot->items = NULL;
1247 snapshot->history_end = 0;
1254 snapshot->items = g_list_copy(dev->history);
1255 for(GList *node = snapshot->items; node; node = g_list_next(node))
1266 snapshot->items = NULL;
1267 snapshot->history_end = 0;
1277 for(GList *l = dev->history; l; l = g_list_next(l))
1286 dev->history = NULL;
1318 for(GList *modules = g_list_first(dev->
iop); modules; modules = g_list_next(modules))
1331 module->enabled = module->default_enabled;
1333 if(module->multi_priority == 0)
1334 module->iop_order = dt_ioppr_get_iop_order(dev->iop_order_list, module->op, module->multi_priority);
1336 module->iop_order = INT_MAX;
1340 if(module->force_enable)
1341 module->enabled = (module->force_enable(module, module->enabled) != 0);
1344 if(module->default_enabled == 1 && module->hide_enable_button == 1)
1345 module->enabled = TRUE;
1361 GList *current_forms)
1363 module->enabled = (hist->enabled != 0);
1366 module->iop_order = hist->iop_order;
1402 GList *history = g_list_first(dev->history);
1403 GList *forms = NULL;
1404 for(
int i = 0;
i < history_end && history;
i++)
1416 history = g_list_next(history);
1427 for(GList *modules = g_list_first(dev->iop); modules; modules = g_list_next(modules))
1430 if(module->commit_proxy)
module->commit_proxy(module);
1502 for(GList *history = g_list_first(dev_history); history; history = g_list_next(history))
1505 states += g_list_length(hist_item->
forms);
1527 "Consider compressing history and removing unused masks to keep reads/writes manageable."),
1544 dt_print(
DT_DEBUG_HISTORY,
"[dt_dev_write_history_item] writing history for module %s (%s) (enabled %i) at pipe position %i for image %i\n",
1547 const char *operation = h->module ? h->module->op : h->
op_name;
1549 const int module_version = h->module ? h->module->version() : h->
module_version;
1550 const int blendop_params_size
1552 const int blendop_version
1562 for(GList *forms = g_list_first(h->
forms); forms; forms = g_list_next(forms))
1590 REQUIRES_SHARED(dev->history_mutex)
1603 state->iop_order_list = NULL;
1621 for(GList *history = g_list_first(
state->snapshot.items); history; history = g_list_next(history))
1657 const int32_t imgid =
d->image_storage.id;
1677 const double _lock_ms = (
dt_get_wtime() - _lock_start) * 1000.0;
1680 "[_dt_dev_write_history_job_run] tid %lu held history_mutex for %.2f ms to snapshot image %i\n",
1681 (
unsigned long)pthread_self(), _lock_ms, imgid);
1685 const double _write_ms = (
dt_get_wtime() - _write_start) * 1000.0;
1688 "[_dt_dev_write_history_job_run] tid %lu full history+masks rewrite for image %i took %.2f ms, lock-free\n",
1689 (
unsigned long)pthread_self(), imgid, _write_ms);
1744 const char *workflow_preset = has_matrix ? _(
"scene-referred default") :
"\t\n";
1771 void *params = NULL;
1772 int32_t params_len = 0;
1838 && (module->default_enabled || (module->force_enable && module->force_enable(module,
FALSE))))
1840 module->enabled = TRUE;
1851 if(module->default_enabled || (module->force_enable && module->force_enable(module,
FALSE)))
1853 module->enabled = TRUE;
1857 if(!strcmp(module->op,
"temperature")
1859 && is_raw && is_inited && has_matrix)
1861 dt_print(
DT_DEBUG_HISTORY,
"[history] Image history seems older than Darktable 3.0, we will insert white balance.\n");
1878 else if(module->workflow_enabled && !is_inited)
1880 module->enabled = TRUE;
1885 dt_print(
DT_DEBUG_HISTORY,
"[history] %s was inserted into history by default (enabled %i)\n", module->op, module->enabled);
1891 REQUIRES(dev->history_mutex)
1899 for(GList *iop = g_list_first(dev->iop); iop; iop = g_list_next(iop))
1916 if(dest_imgid <= 0)
return 1;
1951 for(GList *modules = g_list_first(dev->
iop); modules; modules = g_list_next(modules))
1954 if(!strcmp(module->op, hist->
op_name))
1959 hist->module =
module;
1971 if(!hist->module && match)
1978 dev->
iop = g_list_append(dev->
iop, new_module);
1981 hist->module = new_module;
2011 if(!
IS_NULL_PTR(blendop_params) && is_valid_blendop_version && is_valid_blendop_size)
2015 else if(blendop_params
2042 const int modversion,
int *
legacy_params,
const char *preset_name)
2046 const gboolean is_valid_module_version = (modversion == hist->module->version());
2047 const gboolean is_valid_params_size = (param_length == hist->module->
params_size);
2050 if(is_valid_module_version && is_valid_params_size)
2056 if(!hist->module->legacy_params
2057 || hist->module->legacy_params(hist->module, module_params, labs(modversion),
2058 hist->
params, labs(hist->module->version())))
2060 gchar *
preset = (preset_name) ? g_strdup_printf(_(
"from preset %s"), preset_name)
2063 fprintf(stderr,
"[dev_read_history] module `%s' %s version mismatch: history is %d, dt %d.\n", hist->module->op,
2064 preset, modversion, hist->module->version());
2067 preset, hist->module->version(), modversion);
2078 if(!strcmp(hist->module->op,
"spots") && modversion == 1)
2095 if(!strcmp(hist->module->op,
"flip") && hist->
enabled == 0 && labs(modversion) == 1)
2130 const int modversion,
const char *operation,
const void *module_params,
2131 const int param_length,
const gboolean
enabled,
const void *blendop_params,
2132 const int bl_length,
const int blendop_version,
const int multi_priority,
2133 const char *multi_name,
const char *preset_name,
int *
legacy_params,
2134 const gboolean presets) REQUIRES(dev->history_mutex)
2137 const gboolean is_valid_id = (
id == imgid);
2138 const gboolean has_operation = (!
IS_NULL_PTR(operation));
2140 if(!(has_operation && is_valid_id))
2142 fprintf(stderr,
"[dev_read_history] database history for image `%s' seems to be corrupted!\n",
2143 dev->image_storage.filename);
2158 hist->module = NULL;
2176 if(!
IS_NULL_PTR(module_params) && param_length > 0)
2178 hist->
params = malloc(param_length);
2179 memcpy(hist->
params, module_params, param_length);
2189 "[dev_read_history] the module `%s' requested by image `%s' is not installed on this computer!\n",
2190 operation, dev->image_storage.filename);
2191 dev->history = g_list_append(dev->history, hist);
2214 GList *place = NULL;
2215 for(GList *l = dev->iop_order_list; l; l = g_list_next(l))
2218 if(!strcmp(e->
operation, operation)) place = l;
2220 dev->iop_order_list = g_list_insert_before(dev->iop_order_list,
2221 place ? g_list_next(place) : NULL, new_entry);
2251 if(hist->module->force_enable)
2252 hist->
enabled = (hist->module->force_enable(hist->module, hist->
enabled) != 0);
2255 if(hist->module->default_enabled ==
TRUE && hist->module->hide_enable_button ==
TRUE)
2262 && !
IS_NULL_PTR(hist->module->default_blendop_params))
2266 preset_blend.
mask_mode &= ~DEVELOP_MASK_ENABLED;
2267 default_blend.
mask_mode &= ~DEVELOP_MASK_ENABLED;
2272 dev->history = g_list_append(dev->history, hist);
2275 hist->
iop_order, hist->
enabled, (presets) ?
"preset" :
"database", (presets) ? preset_name :
"");
2320 const int32_t history_length = g_list_length(dev->history);
2322 if(history_length > db_items)
2328 history_end += history_length - db_items;
2341 for(GList *h = dev->history; h; h = g_list_next(h))
2358 read_lock_img = NULL;
2362 GList *accumulated_forms = NULL;
2363 for(GList *history = g_list_first(dev->history); history; history = g_list_next(history))
2368 fprintf(stderr,
"[dt_dev_read_history_ext] we have no history item. This is not normal.\n");
2371 else if(!hist->module)
2380 if(hist->
forms) accumulated_forms = hist->
forms;
2390 module->multi_name, module->iop_order, g_list_index(dev->history, hist),
2402 dev->forms_changed =
FALSE;
2414 for(; list; list = g_list_next(list))
2417 if (hitem->module == module)
2419 hitem->module = NULL;
2448 return module->default_enabled || (module->force_enable && module->force_enable(module, module->enabled));
2459 return module->has_defaults ? module->has_defaults(module) : TRUE;
2497 for(GList *item = g_list_first(dev->iop); item; item = g_list_next(item))
2510 return module->enabled && _module_is_default_or_forced_enabled(module);
2518 return module->enabled && !_module_is_default_or_forced_enabled(module)
2519 && _module_params_are_default(module);
2527 return module->enabled && !_module_is_default_or_forced_enabled(module)
2528 && !_module_params_are_default(module);
2536 return !
module->enabled
2537 && (module->default_enabled || module->workflow_enabled || _module_has_nondefault_internal_params(module));
2615 GList *next = g_list_next(link);
2658 GList **removed_gui_modules)
2660 GList *iop_list = *_iop_list;
2661 int deleted_module_found = 0;
2664 GList *modules = iop_list;
2670 int delete_module = 0;
2681 GList *modules_next = g_list_next(modules);
2692 if(mod_in_history && !mod_next_in_history)
2695 modules = modules_next;
2699 else if(!mod_in_history && mod_next_in_history)
2705 if(mod_in_history && mod_next_in_history)
2708 "[_check_deleted_instances] found duplicate module %s %s (%i) and %s %s (%i) both in history\n",
2714 "[_check_deleted_instances] found duplicate module %s %s (%i) and %s %s (%i) none in history\n",
2728 if(delete_module && mod)
2730 deleted_module_found = 1;
2732 iop_list = g_list_delete_link(iop_list, modules);
2745 if(removed_gui_modules)
2746 *removed_gui_modules = g_list_append(*removed_gui_modules, mod);
2753 modules = g_list_next(modules);
2757 *_iop_list = iop_list;
2759 return deleted_module_found;
2771 for(
const GList *history = history_list; history; history = g_list_next(history))
2795 for(; hist; hist = g_list_next(hist))
2801 hit->module =
module;
2832 GList *iop_list = *_iop_list;
2834 gboolean done =
FALSE;
2836 GList *l = history_list;
2839 GList *next = g_list_next(l);
2850 fprintf(stderr,
"[_create_deleted_modules] can't find base module for %s\n", hitem->
op_name);
2857 dt_iop_module_t *
module = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
2862 module->instance = base_module->instance;
2865 g_strlcpy(module->multi_name, hitem->
multi_name,
sizeof(module->multi_name));
2867 module->iop_order = hitem->iop_order;
2883 hitem->module =
module;
2888 *_iop_list = iop_list;
2897 GList **removed_gui_modules)
2899 GList *iop_list = *iop;
2902 int pipe_remove = 0;
2939 const void *blend_params,
const size_t blend_size)
3007 void *out_params,
const size_t out_params_size,
3008 void *out_blend,
const size_t out_blend_size, gboolean *out_has_blend)
3013 gboolean ok =
FALSE;
void reload_defaults(dt_iop_module_t *module)
void dt_atomic_set_int(dt_atomic_int *var, int value)
int dt_atomic_get_int(dt_atomic_int *var)
int dt_atomic_sub_int(dt_atomic_int *var, int decr)
int dt_atomic_add_int(dt_atomic_int *var, int incr)
int dt_atomic_exch_int(dt_atomic_int *var, int value)
static void * dt_atomic_exch_ptr(dt_atomic_ptr *var, void *value)
static void * dt_atomic_get_ptr(const dt_atomic_ptr *var)
size_t params_size(dt_imageio_module_format_t *self)
int dt_develop_blend_version(void)
int dt_develop_blend_legacy_params(dt_iop_module_t *module, const void *const old_params, const int old_version, void *new_params, const int new_version, const int length)
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_conf_set_string(const char *name, const char *val)
gboolean dt_image_is_matrix_correction_supported(const dt_image_t *img)
gboolean dt_image_is_raw(const dt_image_t *img)
int dt_image_monochrome_flags(const dt_image_t *img)
gboolean dt_image_is_hdr(const dt_image_t *img)
gboolean dt_image_needs_rawprepare(const dt_image_t *img)
void dt_image_history_changed(const int32_t imgid, const gboolean refresh_filmstrip)
struct dt_control_t * dt_control_get_global(void)
struct dt_develop_t * dt_dev_get_global(void)
struct dt_gui_gtk_t * dt_gui_get_global(void)
static void _remove_history_leaks(dt_develop_t *dev) REQUIRES(dev -> history_mutex)
Remove history items past history_end when allowed.
void dt_apply_dev_history_update(dt_develop_t *dev)
Reload the current darkroom history and refresh every dependent GUI.
static gboolean _module_blend_params_are_default(dt_iop_module_t *module)
Check if blend params match defaults.
void dt_dev_history_set_commit_gui_handler(dt_dev_history_commit_gui_handler_t handler)
static int _rebuild_multi_priority(GList *history_list)
Resync module multi_priority values from history.
int dt_dev_write_history_item(const int32_t imgid, dt_dev_history_item_t *h, int32_t num)
void dt_dev_history_compress_or_truncate(dt_develop_t *dev) REQUIRES_SHARED(dev -> history_mutex)
Compress history if history_end is at top, otherwise truncate.
static void _history_to_module(const dt_dev_history_item_t *const hist, dt_iop_module_t *module, GList *current_forms)
Apply a history item to a module instance.
int dt_dev_next_multi_priority_for_op(dt_develop_t *dev, const char *op)
Return the next available multi_priority for an operation.
static void _dt_dev_modules_reload_defaults(dt_develop_t *dev)
Reset every module to its (already-computed) default params before history is overlaid.
static int _check_deleted_instances(dt_develop_t *dev, GList **_iop_list, GList *history_list, GList **removed_gui_modules)
Detect and handle module instances that exist in iop list but not in history.
static void _dev_history_add_filtered(dt_develop_t *dev, dt_iop_module_filter_t filter) REQUIRES(dev -> history_mutex)
Append history items for modules that pass a filter.
gboolean dt_dev_transient_params_get(dt_develop_t *dev, const dt_iop_module_t *module, void *out_params, const size_t out_params_size, void *out_blend, const size_t out_blend_size, gboolean *out_has_blend)
static void _undo_items_cb(gpointer user_data, dt_undo_type_t type, dt_undo_data_t data)
Undo iterator callback to fix module pointers in snapshots.
void dt_dev_pop_history_items_ext(dt_develop_t *dev) REQUIRES_SHARED(dev -> history_mutex)
Apply history items to module params up to dev->history_end.
static void _history_invalidate_cb(gpointer user_data, dt_undo_type_t type, dt_undo_data_t item)
Undo iterator callback to invalidate module pointers in snapshots.
static gboolean _compress_enabled_user_nondefault_params(dt_iop_module_t *module)
Filter: enabled modules with non-default params (user edits).
void dt_dev_history_snapshot_release(dt_dev_history_snapshot_t *snapshot)
Release every reference a snapshot holds and reset it. Needs no lock.
static dt_dev_history_item_t * _search_history_by_op(dt_develop_t *dev, const dt_iop_module_t *module) REQUIRES_SHARED(dev -> history_mutex)
Find the first history item matching a module operation name.
void dt_dev_history_set_undo_restore_gui_handler(dt_dev_history_undo_restore_gui_handler_t handler)
static void _dev_history_db_row_cb(void *user_data, const int32_t id, const int num, const int modversion, const char *operation, const void *module_params, const int param_length, const gboolean enabled, const void *blendop_params, const int bl_length, const int blendop_version, const int multi_priority, const char *multi_name, const char *preset_name)
Adapter callback for history DB rows.
static void _find_so_for_history_entry(dt_develop_t *dev, dt_dev_history_item_t *hist)
Bind a history entry to a module instance (.so) in dev->iop.
static gboolean _module_params_are_default(dt_iop_module_t *module)
Check if module params match defaults.
gboolean dt_dev_read_history_ext(dt_develop_t *dev, const int32_t imgid) REQUIRES(dev -> history_mutex)
Read history and masks from DB and populate dev->history.
static gboolean _module_is_default_or_forced_enabled(dt_iop_module_t *module)
Check if a module is enabled by default or force-enabled.
static void _pop_undo(gpointer user_data, dt_undo_type_t type, dt_undo_data_t data, dt_undo_action_t action, GList **imgs) NO_THREAD_SAFETY_ANALYSIS
Apply an undo/redo history snapshot to a develop context.
static dt_iop_module_t * _history_merge_resolve_dest_instance(dt_develop_t *dev_dest, const dt_iop_module_t *mod_src, gboolean *created, gboolean *reused_base) REQUIRES_SHARED(dev_dest -> history_mutex)
Resolve or create the destination module instance for history merge.
static void _process_history_db_entry(dt_develop_t *dev, const int32_t imgid, const int id, const int num, const int modversion, const char *operation, const void *module_params, const int param_length, const gboolean enabled, const void *blendop_params, const int bl_length, const int blendop_version, const int multi_priority, const char *multi_name, const char *preset_name, int *legacy_params, const gboolean presets)
Build a history item from DB row data and append it to dev->history.
static int _sync_params(dt_dev_history_item_t *hist, const void *module_params, const int param_length, const int modversion, int *legacy_params, const char *preset_name)
Load or convert module params into a history item.
gboolean _module_leaves_no_history(dt_iop_module_t *module)
Return whether a module never writes history entries.
void dt_dev_history_undo_end_record_locked(dt_develop_t *dev) REQUIRES(dev -> history_mutex)
Finish an undo record with history_mutex already locked.
dt_dev_history_item_t * dt_dev_history_item_create(void)
Allocate a fresh, blank history item with refcount 1.
int dt_dev_replace_history_on_image(dt_develop_t *dev_src, const int32_t dest_imgid, const gboolean reload_defaults, const char *msg)
Replace an image history with the content of dev_src.
static int _create_deleted_modules(GList **_iop_list, GList *history_list)
Recreate missing module instances referenced by history.
static void _history_write_state_release(_history_write_state_t *state)
void dt_dev_transient_params_clear(dt_iop_module_t *module)
Drop the transient slot if it belongs to module.
void dt_dev_history_cleanup(void)
Cleanup cached statements or state used by history I/O.
dt_iop_module_t * dt_dev_get_module_instance(dt_develop_t *dev, const char *op, const char *multi_name, const int multi_priority)
Find a module instance by op name and instance metadata.
void dt_dev_transient_params_set(dt_iop_module_t *module, const void *params, const size_t params_size, const void *blend_params, const size_t blend_size)
Out-of-history transient param channel.
int dt_history_merge_module_into_history(dt_develop_t *dev_dest, dt_develop_t *dev_src, dt_iop_module_t *mod_src) REQUIRES(dev_dest -> history_mutex)
Merge a single module instance into a destination history.
void dt_dev_free_history_item(gpointer data)
Release a reference to a history item (used as GList free callback).
gboolean dt_dev_history_item_update_from_params(dt_develop_t *dev, dt_dev_history_item_t *hist, dt_iop_module_t *module, const gboolean enabled, const void *params, const int32_t params_size, const dt_develop_blend_params_t *blend_params, GList *forms)
dt_iop_module_t * dt_dev_create_module_instance(dt_develop_t *dev, const char *op, const char *multi_name, const int multi_priority, gboolean use_next_priority)
Create a new module instance from an existing base .so.
GList * dt_history_duplicate(GList *hist)
Deep-copy a history list.
static dt_dev_history_item_t * _dt_dev_history_item_duplicate_one(const dt_dev_history_item_t *old)
int dt_dev_copy_module_contents(dt_develop_t *dev_dest, dt_develop_t *dev_src, dt_iop_module_t *mod_dest, const dt_iop_module_t *mod_src)
int dt_dev_history_refresh_nodes_ext(dt_develop_t *dev, GList **iop, GList *history, GList **removed_gui_modules)
Refresh GUI module nodes to match history state.
void dt_dev_history_free_history(dt_develop_t *dev) REQUIRES(dev -> history_mutex)
Free the whole history list attached to dev->history.
static void _history_undo_data_free(gpointer data)
Free an undo history snapshot structure.
void dt_dev_history_compress_ext(dt_develop_t *dev, gboolean write_history)
Variant of history compression that optionally skips DB writeback.
gboolean dt_dev_add_history_item_ext(dt_develop_t *dev, struct dt_iop_module_t *module, gboolean enable, gboolean force_new_item) REQUIRES(dev -> history_mutex)
Append or update a history item for a module.
gboolean(* dt_iop_module_filter_t)(dt_iop_module_t *module)
void dt_dev_history_undo_invalidate_module(dt_iop_module_t *module)
Invalidate a module pointer inside undo snapshots.
void dt_dev_history_compress(dt_develop_t *dev)
Compress an history from a loaded pipeline, aka simply take a snapshot of all modules parameters....
uint64_t dt_dev_history_compute_hash(dt_develop_t *dev) REQUIRES_SHARED(dev -> history_mutex)
Get the integrity checksum of the whole history stack. This should be done ONLY when history is chang...
dt_dev_history_item_t * dt_dev_history_item_ref(dt_dev_history_item_t *item)
Take a reference on a history item. Pair with dt_dev_free_history_item().
gboolean dt_dev_history_is_image_in_dev(GList *imgs)
Check whether any image of the list is the one currently loaded in the darkroom.
static void _insert_default_modules(dt_develop_t *dev, dt_iop_module_t *module, gboolean is_inited) REQUIRES(dev -> history_mutex)
Insert default modules into history when needed.
void dt_dev_history_snapshot_take(dt_develop_t *dev, dt_dev_history_snapshot_t *snapshot) REQUIRES_SHARED(dev -> history_mutex)
Take a snapshot of dev->history. Caller holds history_mutex (reader suffices).
int dt_dev_history_item_from_source_history_item(dt_develop_t *dev_dest, dt_develop_t *dev_src, const dt_dev_history_item_t *hist_src, dt_iop_module_t *mod_dest, dt_dev_history_item_t **out_hist)
int dt_dev_merge_history_into_image(dt_develop_t *dev_src, int32_t dest_imgid, const GList *mod_list, gboolean merge_iop_order, const dt_history_merge_strategy_t mode, const gboolean paste_instances, const char *source_label, dt_hm_batch_state_t *batch)
Merge a list of modules into a destination image history via dt_history_merge().
void dt_dev_pop_history_items(dt_develop_t *dev)
Thread-safe wrapper around dt_dev_pop_history_items_ext(), then update GUI.
void dt_dev_write_history(dt_develop_t *dev, gboolean async)
Thread-safe wrapper around dt_dev_write_history_ext() for dev->image_storage.id.
void dt_dev_history_truncate(dt_develop_t *dev, const int32_t imgid)
static gboolean _compress_enabled_default_or_forced(dt_iop_module_t *module)
Filter: enabled modules that are default/forced enabled.
static void _reset_module_instance(GList *hist, dt_iop_module_t *module, int multi_priority)
Rebind history items to a module instance after recreation.
static dt_dev_history_undo_restore_gui_handler_t _undo_restore_gui_handler
dt_dev_history_item_t * dt_dev_history_get_last_item_by_module(GList *history_list, dt_iop_module_t *module, int history_end)
Find the last history item referencing a module up to history_end.
gboolean dt_dev_transient_params_active(dt_develop_t *dev, const dt_iop_module_t *module)
static void _dt_dev_history_compress_internal(dt_develop_t *dev, const gboolean write_history)
Rebuild history from current pipeline state.
static void _cleanup_history(const int32_t imgid)
Delete all history entries for an image from the DB.
void dt_dev_history_undo_end_record(dt_develop_t *dev)
Finish an undo record for history changes.
gboolean dt_dev_init_default_history(dt_develop_t *dev, const int32_t imgid, gboolean apply_auto_presets)
Initialize module defaults and insert required default modules.
gboolean dt_history_module_skip_copy(const int flags)
Determine whether a module should be skipped during history copy.
guint dt_dev_mask_history_overload(GList *dev_history, guint threshold)
static int _dt_dev_write_history_job_run(dt_job_t *job)
void dt_dev_history_pixelpipe_update(dt_develop_t *dev, gboolean rebuild)
Rebuild or resync pixelpipes after backend history changes.
void dt_dev_history_undo_start_record(dt_develop_t *dev)
Start an undo record for history changes.
static dt_dev_history_commit_gui_handler_t _commit_gui_handler
void dt_dev_history_commit_item_now(dt_develop_t *dev, dt_iop_module_t *module, gboolean enable)
Commit one history item immediately – record undo, take history_mutex as writer, write through,...
static void _sync_blendop_params(dt_dev_history_item_t *hist, const void *blendop_params, const int bl_length, const int blendop_version, int *legacy_params)
Load or convert blendop params into a history item.
void dt_dev_history_undo_start_record_locked(dt_develop_t *dev) REQUIRES(dev -> history_mutex)
Start an undo record with history_mutex already locked.
static void _write_history_from_state(const _history_write_state_t *state, const int32_t imgid)
void dt_dev_invalidate_history_module(GList *list, dt_iop_module_t *module)
Remove a module pointer from a history list.
void dt_dev_history_notify_change(dt_develop_t *dev, const int32_t imgid)
Notify the rest of the app that history changes were written.
gboolean dt_dev_reload_history_items(dt_develop_t *dev, const int32_t imgid)
Reload history from DB and rebuild pipelines/GUI state.
static gboolean _compress_disabled_with_history(dt_iop_module_t *module)
Filter: disabled modules that still need history entries.
static void _history_write_state_take(dt_develop_t *dev, _history_write_state_t *state) REQUIRES_SHARED(dev -> history_mutex)
static gboolean _compress_enabled_user_default_params(dt_iop_module_t *module)
Filter: enabled modules with default params (user enabled).
static gboolean _dev_auto_apply_presets(dt_develop_t *dev, int32_t imgid)
Apply auto-presets and default iop order for a fresh history.
static gboolean _module_has_nondefault_internal_params(dt_iop_module_t *module)
Check if any module params (including blend params) are non-default.
dt_dev_history_item_t * dt_dev_history_get_first_item_by_module(GList *history_list, dt_iop_module_t *module)
Find the first history item referencing a module.
dt_dev_history_item_t * dt_dev_history_cow_touch(dt_develop_t *dev, dt_dev_history_item_t *hist)
Copy-on-write gate for mutating a history item in place.
void dt_dev_write_history_ext(dt_develop_t *dev, const int32_t imgid) REQUIRES_SHARED(dev -> history_mutex)
Write dev->history to DB and XMP for a given image id.
void(* dt_dev_history_commit_gui_handler_t)(struct dt_develop_t *dev, struct dt_iop_module_t *module)
Post-commit presentation work: viewport-size refresh for geometry-changing modules,...
void dt_dev_set_history_end_ext(struct dt_develop_t *dev, const uint32_t index)
Set the history end index (GUI perspective).
void dt_dev_history_gui_update(struct dt_develop_t *dev)
Apply history-loaded params to module GUIs.
int32_t dt_dev_get_history_end_ext(struct dt_develop_t *dev)
Get the current history end index (GUI perspective).
void(* dt_dev_history_undo_restore_gui_handler_t)(struct dt_develop_t *dev, int mask_edit_mode, int request_mask_display)
Restores the presentation half of an undo record: the blending panel's mask toggles for the focused m...
#define dt_dev_pixelpipe_resync_history_all(dev)
#define dt_dev_pixelpipe_rebuild_all(dev)
#define dt_dev_pixelpipe_update_history_all(dev)
void dt_dev_signal_modules_moved(dt_develop_t *dev)
void dt_dev_masks_list_change(dt_develop_t *dev)
int dt_dev_get_thumbnail_size(dt_develop_t *dev)
void dt_dev_cleanup(dt_develop_t *dev)
void dt_dev_init(dt_develop_t *dev, int32_t gui_attached)
void dt_dev_undo_start_record(dt_develop_t *dev)
GList * dt_dev_load_modules(dt_develop_t *dev)
void dt_dev_masks_update_hash(dt_develop_t *dev)
void dt_dev_undo_end_record(dt_develop_t *dev)
dt_dev_image_storage_t dt_dev_ensure_image_storage(dt_develop_t *dev, const int32_t imgid)
void dt_dev_masks_list_update(dt_develop_t *dev)
static uint64_t dt_dev_get_history_hash(const dt_develop_t *dev)
dt_dev_pixelpipe_display_mask_t
@ DT_DEV_PIXELPIPE_DISPLAY_NONE
static void dt_dev_set_history_hash(dt_develop_t *dev, const uint64_t history_hash)
gboolean enabled
–doc was passed on the command line
static int rwlock NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_rwlock_wrlock(dt_pthread_rwlock_t *rwlock) ACQUIRE(rwlock) NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_rwlock_unlock(dt_pthread_rwlock_t *rwlock) RELEASE_GENERIC(rwlock) NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_rwlock_rdlock(dt_pthread_rwlock_t *rwlock) ACQUIRE_SHARED(rwlock) NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
void * legacy_params(dt_imageio_module_format_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)
static uint64_t dt_hash(uint64_t hash, const char *str, size_t size)
static gboolean enable(const dt_image_t *image)
void dt_history_toast(const char *format,...)
void dt_history_message(const char *format,...)
void dt_history_changed(const dt_history_change_t what)
Raise it. Internal to this code.
Everything the history, styles and presets code says to the outside world: messages for the user,...
@ DT_HISTORY_CHANGE_DEVELOP
int dt_history_merge(dt_develop_t *dev_dest, dt_develop_t *dev_src, const int32_t dest_imgid, const GList *mod_list, const gboolean merge_iop_order, const dt_history_merge_strategy_t strategy, const gboolean force_new_modules, const char *source_label, dt_hm_batch_state_t *batch)
Merge a list of modules into a destination image, solving pipeline topologies for proper insertion of...
dt_history_merge_strategy_t
void dt_history_repository_foreach_auto_preset_row(const int32_t imgid, const dt_image_t *image, const char *workflow_preset, const int iformat, const int excluded, dt_history_repository_row_cb cb, void *user_data)
gboolean dt_history_repository_delete_dev_history(const int32_t imgid)
gboolean dt_history_repository_write_item(const int32_t imgid, const int num, const char *operation, const void *op_params, const int op_params_size, const int module_version, const gboolean enabled, const void *blendop_params, const int blendop_params_size, const int blendop_version, const int multi_priority, const char *multi_name)
gboolean dt_history_repository_module_exists(const int32_t imgid, const char *operation)
gboolean dt_history_repository_get_autoapply_ioporder_params(const int32_t imgid, const dt_image_t *image, const int iformat, const int excluded, void **params, int32_t *params_len)
gboolean dt_history_repository_set_end(const int32_t imgid, const int32_t history_end)
int32_t dt_history_repository_get_end(const int32_t imgid)
int32_t dt_history_repository_get_next_num(const int32_t imgid)
void dt_history_repository_foreach_row(const int32_t imgid, dt_history_repository_row_cb cb, void *user_data)
@ DT_IMAGE_NO_LEGACY_PRESETS
@ DT_IMAGE_AUTO_PRESETS_APPLIED
void dt_image_cache_write_release(dt_image_t *img, dt_image_cache_write_mode_t mode)
dt_image_t * dt_image_cache_get(const int32_t imgid, char mode)
void dt_image_cache_read_release(const dt_image_t *img)
dt_iop_module_t * dt_iop_get_module_from_list(GList *iop_list, const char *op)
gboolean dt_iop_module_needs_mask_history_ext(const dt_iop_module_t *module, gboolean *raster, gboolean *drawn, gboolean *parametric)
void dt_iop_load_default_params(dt_iop_module_t *module)
void dt_iop_compute_module_hash(dt_iop_module_t *module, GList *masks)
void dt_iop_reload_defaults(dt_iop_module_t *module)
void dt_iop_commit_blend_params(dt_iop_module_t *module, const dt_develop_blend_params_t *blendop_params)
int dt_iop_load_module(dt_iop_module_t *module, dt_iop_module_so_t *module_so, dt_develop_t *dev)
gboolean dt_iop_module_needs_mask_history(const dt_iop_module_t *module)
gboolean dt_iop_check_modules_equal(dt_iop_module_t *mod_1, dt_iop_module_t *mod_2)
dt_iop_module_t * dt_iop_get_module_by_op_priority(GList *modules, const char *operation, const int multi_priority)
void dt_iop_update_multi_priority(dt_iop_module_t *module, int new_priority)
@ IOP_FLAGS_NO_HISTORY_STACK
struct dt_iop_tonecurve_params_t preset
gboolean dt_ioppr_has_iop_order_list(int32_t imgid)
Check whether the image has an explicit order list stored in DB.
GList * dt_ioppr_get_iop_order_list_version(dt_iop_order_t version)
Return the built-in order list for a given version.
gint dt_sort_iop_by_order(gconstpointer a, gconstpointer b)
Compare two module instances by iop_order for sorting.
GList * dt_ioppr_iop_order_copy_deep(GList *iop_order_list)
Deep-copy an order list.
gboolean dt_ioppr_write_iop_order_list(GList *iop_order_list, const int32_t imgid)
Persist an order list to the DB for a given image.
int dt_ioppr_get_iop_order(GList *iop_order_list, const char *op_name, const int multi_priority)
Return the iop_order for a given operation/instance pair.
void dt_ioppr_set_default_iop_order(dt_develop_t *dev, const int32_t imgid)
Set dev->iop_order_list to the default order for a given image.
void dt_ioppr_resync_pipeline(dt_develop_t *dev, const int32_t imgid, const char *msg, gboolean check_duplicates)
Resynchronize pipeline order and related structures.
GList * dt_ioppr_deserialize_iop_order_list(const char *buf, size_t size)
Deserialize an order list from a binary blob.
dt_job_t * dt_control_job_create(dt_job_execute_callback execute, const char *msg,...)
int dt_control_add_job(dt_control_t *control, dt_job_queue_t queue_id, _dt_job_t *job)
void * dt_control_job_get_params(const _dt_job_t *job)
void dt_control_job_set_params(_dt_job_t *job, void *params, dt_job_destroy_callback callback)
void dt_control_job_dispose(_dt_job_t *job)
_lib_location_type_t type
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
void dt_masks_read_masks_history(dt_develop_t *dev, const int32_t imgid)
void dt_masks_write_masks_history_item(const int32_t imgid, const int num, dt_masks_form_t *form)
dt_masks_form_t * dt_masks_get_from_id(dt_develop_t *dev, int id)
dt_masks_edit_mode_t dt_masks_get_edit_mode(struct dt_iop_module_t *module)
void dt_masks_set_edit_mode(struct dt_iop_module_t *module, dt_masks_edit_mode_t value)
int dt_masks_copy_used_forms_for_module(dt_develop_t *dev_dest, dt_develop_t *dev_src, const struct dt_iop_module_t *mod_src)
GList * dt_masks_snapshot_current_forms(dt_develop_t *dev, gboolean reset_changed)
void dt_masks_replace_current_forms(dt_develop_t *dev, GList *forms)
dt_masks_form_t * dt_masks_form_ref(dt_masks_form_t *form)
void dt_masks_form_unref(dt_masks_form_t *form)
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
dt_mipmap_buffer_dsc_flags flags
#define DT_PIXELPIPE_CACHE_HASH_INVALID
const float uint32_t state[4]
unsigned __int64 uint64_t
dt_iop_module_t *int multi_priority
dt_dev_history_snapshot_t snapshot
struct dt_develop_blend_params_t * blend_params
struct dt_iop_module_t *gboolean enabled
A reference-sharing snapshot of dev->history, for readers that outlive a lock.
struct dt_develop_t::@12 transient_params
struct dt_iop_module_t * gui_module
dt_pthread_rwlock_t history_mutex
struct dt_dev_pixelpipe_t * preview_pipe
struct dt_iop_module_t *void * params
dt_atomic_int history_write_pending
dt_pthread_mutex_t transient_params_mutex
struct dt_dev_pixelpipe_t * pipe
GTimeSpan change_timestamp
struct dt_develop_blend_params_t * blend_params
struct dt_develop_t * dev
struct dt_develop_blend_params_t * default_blendop_params
union dt_iop_order_entry_t::@26 o
dt_dev_pixelpipe_display_mask_t request_mask_display
GList * before_iop_order_list
GList * after_iop_order_list
dt_masks_edit_mode_t mask_edit_mode
void dt_supervisor_rekey(const uint64_t old_hash, const uint64_t new_hash)
void dt_supervisor_history(const dt_sv_op_t op, const uint64_t param_hash, const char *op_name, const int multi_priority, const char *multi_name, const int iop_order, const int history_index, const int32_t imgid, const gboolean enabled, const dt_iop_module_t *module, const void *params, const dt_develop_blend_params_t *blend_params, GList *forms)
static gboolean dt_supervisor_active(void)
static double dt_get_wtime(void)
void dt_undo_iterate_internal(dt_undo_t *self, uint32_t filter, gpointer user_data, void(*apply)(gpointer user_data, dt_undo_type_t type, dt_undo_data_t item))
void dt_undo_record(dt_undo_t *self, gpointer user_data, dt_undo_type_t type, dt_undo_data_t data, void(*undo)(gpointer user_data, dt_undo_type_t type, dt_undo_data_t item, dt_undo_action_t action, GList **imgs), void(*free_data)(gpointer data))
dt_undo_t * dt_undo_get_global(void)