1 /*
2     This file is part of darktable,
3     Copyright (C) 2009-2021 darktable developers.
4 
5     darktable is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9 
10     darktable is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with darktable.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include <assert.h>
19 #include <glib/gprintf.h>
20 #include <math.h>
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <strings.h>
25 #include <unistd.h>
26 
27 #include "common/atomic.h"
28 #include "common/debug.h"
29 #include "common/history.h"
30 #include "common/image_cache.h"
31 #include "common/imageio.h"
32 #include "common/mipmap_cache.h"
33 #include "common/opencl.h"
34 #include "common/tags.h"
35 #include "control/conf.h"
36 #include "control/control.h"
37 #include "control/jobs.h"
38 #include "develop/blend.h"
39 #include "develop/develop.h"
40 #include "develop/imageop.h"
41 #include "develop/lightroom.h"
42 #include "develop/masks.h"
43 #include "gui/gtk.h"
44 #include "gui/presets.h"
45 
46 #define DT_DEV_AVERAGE_DELAY_START 250
47 #define DT_DEV_PREVIEW_AVERAGE_DELAY_START 50
48 #define DT_DEV_AVERAGE_DELAY_COUNT 5
49 #define DT_IOP_ORDER_INFO (darktable.unmuted & DT_DEBUG_IOPORDER)
50 
dt_dev_init(dt_develop_t * dev,int32_t gui_attached)51 void dt_dev_init(dt_develop_t *dev, int32_t gui_attached)
52 {
53   memset(dev, 0, sizeof(dt_develop_t));
54   dev->full_preview = FALSE;
55   dev->gui_module = NULL;
56   dev->timestamp = 0;
57   dev->average_delay = DT_DEV_AVERAGE_DELAY_START;
58   dev->preview_average_delay = DT_DEV_PREVIEW_AVERAGE_DELAY_START;
59   dev->preview2_average_delay = DT_DEV_PREVIEW_AVERAGE_DELAY_START;
60   dev->gui_leaving = 0;
61   dev->gui_synch = 0;
62   dt_pthread_mutex_init(&dev->history_mutex, NULL);
63   dev->history_end = 0;
64   dev->history = NULL; // empty list
65 
66   dev->gui_attached = gui_attached;
67   dev->width = -1;
68   dev->height = -1;
69 
70   dt_image_init(&dev->image_storage);
71   dev->image_status = dev->preview_status = dev->preview2_status = DT_DEV_PIXELPIPE_DIRTY;
72   dev->history_updating = dev->image_force_reload = dev->image_loading = dev->preview_loading = FALSE;
73   dev->preview2_loading = dev->preview_input_changed = dev->preview2_input_changed = FALSE;
74   dev->image_invalid_cnt = 0;
75   dev->pipe = dev->preview_pipe = dev->preview2_pipe = NULL;
76   dt_pthread_mutex_init(&dev->pipe_mutex, NULL);
77   dt_pthread_mutex_init(&dev->preview_pipe_mutex, NULL);
78   dt_pthread_mutex_init(&dev->preview2_pipe_mutex, NULL);
79   dev->histogram_pre_tonecurve = NULL;
80   dev->histogram_pre_levels = NULL;
81   dev->preview_downsampling = dt_dev_get_preview_downsampling();
82   dev->forms = NULL;
83   dev->form_visible = NULL;
84   dev->form_gui = NULL;
85   dev->allforms = NULL;
86 
87   if(dev->gui_attached)
88   {
89     dev->pipe = (dt_dev_pixelpipe_t *)malloc(sizeof(dt_dev_pixelpipe_t));
90     dev->preview_pipe = (dt_dev_pixelpipe_t *)malloc(sizeof(dt_dev_pixelpipe_t));
91     dev->preview2_pipe = (dt_dev_pixelpipe_t *)malloc(sizeof(dt_dev_pixelpipe_t));
92     dt_dev_pixelpipe_init(dev->pipe);
93     dt_dev_pixelpipe_init_preview(dev->preview_pipe);
94     dt_dev_pixelpipe_init_preview2(dev->preview2_pipe);
95     dev->histogram_pre_tonecurve = (uint32_t *)calloc(4 * 256, sizeof(uint32_t));
96     dev->histogram_pre_levels = (uint32_t *)calloc(4 * 256, sizeof(uint32_t));
97 
98     // FIXME: these are uint32_t, setting to -1 is confusing
99     dev->histogram_pre_tonecurve_max = -1;
100     dev->histogram_pre_levels_max = -1;
101   }
102 
103   dev->iop_instance = 0;
104   dev->iop = NULL;
105   dev->alliop = NULL;
106 
107   dev->allprofile_info = NULL;
108 
109   dev->iop_order_version = 0;
110   dev->iop_order_list = NULL;
111 
112   dev->proxy.exposure.module = NULL;
113   dev->proxy.chroma_adaptation = NULL;
114   dev->proxy.wb_is_D65 = TRUE; // don't display error messages until we know for sure it's FALSE
115   dev->proxy.wb_coeffs[0] = 0.f;
116 
117   dev->rawoverexposed.enabled = FALSE;
118   dev->rawoverexposed.mode = dt_conf_get_int("darkroom/ui/rawoverexposed/mode");
119   dev->rawoverexposed.colorscheme = dt_conf_get_int("darkroom/ui/rawoverexposed/colorscheme");
120   dev->rawoverexposed.threshold = dt_conf_get_float("darkroom/ui/rawoverexposed/threshold");
121 
122   dev->overexposed.enabled = FALSE;
123   dev->overexposed.mode = dt_conf_get_int("darkroom/ui/overexposed/mode");
124   dev->overexposed.colorscheme = dt_conf_get_int("darkroom/ui/overexposed/colorscheme");
125   dev->overexposed.lower = dt_conf_get_float("darkroom/ui/overexposed/lower");
126   dev->overexposed.upper = dt_conf_get_float("darkroom/ui/overexposed/upper");
127 
128   dev->overlay_color.enabled = FALSE;
129   dev->overlay_color.color = dt_conf_get_int("darkroom/ui/overlay_color");
130 
131   dev->iso_12646.enabled = FALSE;
132 
133   dev->second_window.zoom = DT_ZOOM_FIT;
134   dev->second_window.closeup = 0;
135   dev->second_window.zoom_x = dev->second_window.zoom_y = 0;
136   dev->second_window.zoom_scale = 1.0f;
137 }
138 
dt_dev_cleanup(dt_develop_t * dev)139 void dt_dev_cleanup(dt_develop_t *dev)
140 {
141   if(!dev) return;
142   // image_cache does not have to be unref'd, this is done outside develop module.
143   dt_pthread_mutex_destroy(&dev->pipe_mutex);
144   dt_pthread_mutex_destroy(&dev->preview_pipe_mutex);
145   dt_pthread_mutex_destroy(&dev->preview2_pipe_mutex);
146   dev->proxy.chroma_adaptation = NULL;
147   dev->proxy.wb_coeffs[0] = 0.f;
148   if(dev->pipe)
149   {
150     dt_dev_pixelpipe_cleanup(dev->pipe);
151     free(dev->pipe);
152   }
153   if(dev->preview_pipe)
154   {
155     dt_dev_pixelpipe_cleanup(dev->preview_pipe);
156     free(dev->preview_pipe);
157   }
158   if(dev->preview2_pipe)
159   {
160     dt_dev_pixelpipe_cleanup(dev->preview2_pipe);
161     free(dev->preview2_pipe);
162   }
163   while(dev->history)
164   {
165     dt_dev_free_history_item(((dt_dev_history_item_t *)dev->history->data));
166     dev->history = g_list_delete_link(dev->history, dev->history);
167   }
168   while(dev->iop)
169   {
170     dt_iop_cleanup_module((dt_iop_module_t *)dev->iop->data);
171     free(dev->iop->data);
172     dev->iop = g_list_delete_link(dev->iop, dev->iop);
173   }
174   while(dev->alliop)
175   {
176     dt_iop_cleanup_module((dt_iop_module_t *)dev->alliop->data);
177     free(dev->alliop->data);
178     dev->alliop = g_list_delete_link(dev->alliop, dev->alliop);
179   }
180   g_list_free_full(dev->iop_order_list, free);
181   while(dev->allprofile_info)
182   {
183     dt_ioppr_cleanup_profile_info((dt_iop_order_iccprofile_info_t *)dev->allprofile_info->data);
184     free(dev->allprofile_info->data);
185     dev->allprofile_info = g_list_delete_link(dev->allprofile_info, dev->allprofile_info);
186   }
187   dt_pthread_mutex_destroy(&dev->history_mutex);
188   free(dev->histogram_pre_tonecurve);
189   free(dev->histogram_pre_levels);
190 
191   g_list_free_full(dev->forms, (void (*)(void *))dt_masks_free_form);
192   g_list_free_full(dev->allforms, (void (*)(void *))dt_masks_free_form);
193 
194   dt_conf_set_int("darkroom/ui/rawoverexposed/mode", dev->rawoverexposed.mode);
195   dt_conf_set_int("darkroom/ui/rawoverexposed/colorscheme", dev->rawoverexposed.colorscheme);
196   dt_conf_set_float("darkroom/ui/rawoverexposed/threshold", dev->rawoverexposed.threshold);
197 
198   dt_conf_set_int("darkroom/ui/overexposed/mode", dev->overexposed.mode);
199   dt_conf_set_int("darkroom/ui/overexposed/colorscheme", dev->overexposed.colorscheme);
200   dt_conf_set_float("darkroom/ui/overexposed/lower", dev->overexposed.lower);
201   dt_conf_set_float("darkroom/ui/overexposed/upper", dev->overexposed.upper);
202 
203   dt_conf_set_int("darkroom/ui/overlay_color", dev->overlay_color.color);
204 }
205 
dt_dev_get_preview_downsampling()206 float dt_dev_get_preview_downsampling()
207 {
208   gchar *preview_downsample = dt_conf_get_string("preview_downsampling");
209   const float downsample = (g_strcmp0(preview_downsample, "original") == 0) ? 1.0f
210         : (g_strcmp0(preview_downsample, "to 1/2")==0) ? 0.5f
211         : (g_strcmp0(preview_downsample, "to 1/3")==0) ? 1/3.0f
212         : 0.25f;
213   g_free(preview_downsample);
214   return downsample;
215 }
216 
dt_dev_process_image(dt_develop_t * dev)217 void dt_dev_process_image(dt_develop_t *dev)
218 {
219   if(!dev->gui_attached || dev->pipe->processing) return;
220   int err
221       = dt_control_add_job_res(darktable.control, dt_dev_process_image_job_create(dev), DT_CTL_WORKER_ZOOM_1);
222   if(err) fprintf(stderr, "[dev_process_image] job queue exceeded!\n");
223 }
224 
dt_dev_process_preview(dt_develop_t * dev)225 void dt_dev_process_preview(dt_develop_t *dev)
226 {
227   if(!dev->gui_attached) return;
228   int err = dt_control_add_job_res(darktable.control, dt_dev_process_preview_job_create(dev),
229                                    DT_CTL_WORKER_ZOOM_FILL);
230   if(err) fprintf(stderr, "[dev_process_preview] job queue exceeded!\n");
231 }
232 
dt_dev_process_preview2(dt_develop_t * dev)233 void dt_dev_process_preview2(dt_develop_t *dev)
234 {
235   if(!dev->gui_attached) return;
236   if(!(dev->second_window.widget && GTK_IS_WIDGET(dev->second_window.widget))) return;
237   int err = dt_control_add_job_res(darktable.control, dt_dev_process_preview2_job_create(dev),
238                                    DT_CTL_WORKER_ZOOM_2);
239   if(err) fprintf(stderr, "[dev_process_preview2] job queue exceeded!\n");
240 }
241 
dt_dev_invalidate(dt_develop_t * dev)242 void dt_dev_invalidate(dt_develop_t *dev)
243 {
244   dev->image_status = DT_DEV_PIXELPIPE_DIRTY;
245   dev->timestamp++;
246   if(dev->preview_pipe) dev->preview_pipe->input_timestamp = dev->timestamp;
247   if(dev->preview2_pipe) dev->preview2_pipe->input_timestamp = dev->timestamp;
248 }
249 
dt_dev_invalidate_all(dt_develop_t * dev)250 void dt_dev_invalidate_all(dt_develop_t *dev)
251 {
252   dev->image_status = dev->preview_status = dev->preview2_status = DT_DEV_PIXELPIPE_DIRTY;
253   dev->timestamp++;
254 }
255 
dt_dev_invalidate_preview(dt_develop_t * dev)256 void dt_dev_invalidate_preview(dt_develop_t *dev)
257 {
258   dev->preview_status = DT_DEV_PIXELPIPE_DIRTY;
259   dev->timestamp++;
260   if(dev->pipe) dev->pipe->input_timestamp = dev->timestamp;
261   if(dev->preview2_pipe) dev->preview2_pipe->input_timestamp = dev->timestamp;
262 }
263 
dt_dev_process_preview_job(dt_develop_t * dev)264 void dt_dev_process_preview_job(dt_develop_t *dev)
265 {
266   if(dev->image_loading)
267   {
268     // raw is already loading, no use starting another file access, we wait.
269     return;
270   }
271 
272   dt_pthread_mutex_lock(&dev->preview_pipe_mutex);
273 
274   if(dev->gui_leaving)
275   {
276     dt_pthread_mutex_unlock(&dev->preview_pipe_mutex);
277     return;
278   }
279 
280   dt_control_log_busy_enter();
281   dt_control_toast_busy_enter();
282   dev->preview_pipe->input_timestamp = dev->timestamp;
283   dev->preview_status = DT_DEV_PIXELPIPE_RUNNING;
284 
285   // lock if there, issue a background load, if not (best-effort for mip f).
286   dt_mipmap_buffer_t buf;
287   dt_mipmap_cache_get(darktable.mipmap_cache, &buf, dev->image_storage.id, DT_MIPMAP_F, DT_MIPMAP_BEST_EFFORT,
288                       'r');
289   if(!buf.buf)
290   {
291     dt_control_log_busy_leave();
292     dt_control_toast_busy_leave();
293     dev->preview_status = DT_DEV_PIXELPIPE_DIRTY;
294     dt_pthread_mutex_unlock(&dev->preview_pipe_mutex);
295     return; // not loaded yet. load will issue a gtk redraw on completion, which in turn will trigger us again
296             // later.
297   }
298   // init pixel pipeline for preview.
299   dt_dev_pixelpipe_set_input(dev->preview_pipe, dev, (float *)buf.buf, buf.width, buf.height, buf.iscale);
300 
301   if(dev->preview_loading)
302   {
303     dt_dev_pixelpipe_cleanup_nodes(dev->preview_pipe);
304     dt_dev_pixelpipe_create_nodes(dev->preview_pipe, dev);
305     dt_dev_pixelpipe_flush_caches(dev->preview_pipe);
306     dev->preview_loading = FALSE;
307   }
308 
309   // if raw loaded, get new mipf
310   if(dev->preview_input_changed)
311   {
312     dt_dev_pixelpipe_flush_caches(dev->preview_pipe);
313     dev->preview_input_changed = FALSE;
314   }
315 
316 // always process the whole downsampled mipf buffer, to allow for fast scrolling and mip4 write-through.
317 restart:
318   if(dev->gui_leaving)
319   {
320     dt_control_log_busy_leave();
321     dt_control_toast_busy_leave();
322     dev->preview_status = DT_DEV_PIXELPIPE_INVALID;
323     dt_pthread_mutex_unlock(&dev->preview_pipe_mutex);
324     dt_mipmap_cache_release(darktable.mipmap_cache, &buf);
325     return;
326   }
327   // adjust pipeline according to changed flag set by {add,pop}_history_item.
328   // this locks dev->history_mutex.
329   dt_times_t start;
330   dt_get_times(&start);
331   dt_dev_pixelpipe_change(dev->preview_pipe, dev);
332   if(dt_dev_pixelpipe_process(
333          dev->preview_pipe, dev, 0, 0, dev->preview_pipe->processed_width * dev->preview_downsampling,
334          dev->preview_pipe->processed_height * dev->preview_downsampling, dev->preview_downsampling))
335   {
336     if(dev->preview_loading || dev->preview_input_changed)
337     {
338       dt_control_log_busy_leave();
339       dt_control_toast_busy_leave();
340       dev->preview_status = DT_DEV_PIXELPIPE_INVALID;
341       dt_pthread_mutex_unlock(&dev->preview_pipe_mutex);
342       dt_mipmap_cache_release(darktable.mipmap_cache, &buf);
343       return;
344     }
345     else
346       goto restart;
347   }
348 
349   dev->preview_status = DT_DEV_PIXELPIPE_VALID;
350 
351   dt_show_times(&start, "[dev_process_preview] pixel pipeline processing");
352   dt_dev_average_delay_update(&start, &dev->preview_average_delay);
353 
354   // if a widget needs to be redraw there's the DT_SIGNAL_*_PIPE_FINISHED signals
355   dt_control_log_busy_leave();
356   dt_control_toast_busy_leave();
357   dt_pthread_mutex_unlock(&dev->preview_pipe_mutex);
358   dt_mipmap_cache_release(darktable.mipmap_cache, &buf);
359 
360   DT_DEBUG_CONTROL_SIGNAL_RAISE(darktable.signals, DT_SIGNAL_DEVELOP_PREVIEW_PIPE_FINISHED);
361 }
362 
dt_dev_process_preview2_job(dt_develop_t * dev)363 void dt_dev_process_preview2_job(dt_develop_t *dev)
364 {
365   if(dev->image_loading)
366   {
367     // raw is already loading, no use starting another file access, we wait.
368     return;
369   }
370 
371   if(!(dev->second_window.widget && GTK_IS_WIDGET(dev->second_window.widget)))
372   {
373     return;
374   }
375 
376   dt_pthread_mutex_lock(&dev->preview2_pipe_mutex);
377 
378   if(dev->gui_leaving)
379   {
380     dt_pthread_mutex_unlock(&dev->preview2_pipe_mutex);
381     return;
382   }
383 
384   dt_control_log_busy_enter();
385   dt_control_toast_busy_enter();
386   dev->preview2_pipe->input_timestamp = dev->timestamp;
387   dev->preview2_status = DT_DEV_PIXELPIPE_RUNNING;
388 
389   // lock if there, issue a background load, if not (best-effort for mip f).
390   dt_mipmap_buffer_t buf;
391   dt_mipmap_cache_get(darktable.mipmap_cache, &buf, dev->image_storage.id, DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING, 'r');
392 
393   if(!buf.buf)
394   {
395     dt_control_log_busy_leave();
396     dt_control_toast_busy_leave();
397     dev->preview2_status = DT_DEV_PIXELPIPE_DIRTY;
398     dt_pthread_mutex_unlock(&dev->preview2_pipe_mutex);
399     return; // not loaded yet. load will issue a gtk redraw on completion, which in turn will trigger us again
400             // later.
401   }
402   // init pixel pipeline for preview2.
403   dt_dev_pixelpipe_set_input(dev->preview2_pipe, dev, (float *)buf.buf, buf.width, buf.height, 1.0 /*buf.iscale*/);
404 
405   if(dev->preview2_loading)
406   {
407     dt_dev_pixelpipe_cleanup_nodes(dev->preview2_pipe);
408     dt_dev_pixelpipe_create_nodes(dev->preview2_pipe, dev);
409     dt_dev_pixelpipe_flush_caches(dev->preview2_pipe);
410     dev->preview2_loading = FALSE;
411   }
412 
413   // if raw loaded, get new mipf
414   if(dev->preview2_input_changed)
415   {
416     dt_dev_pixelpipe_flush_caches(dev->preview2_pipe);
417     dev->preview2_input_changed = 0;
418   }
419 
420 // always process the whole downsampled mipf buffer, to allow for fast scrolling and mip4 write-through.
421 restart:
422   if(dev->gui_leaving)
423   {
424     dt_control_log_busy_leave();
425     dt_control_toast_busy_leave();
426     dev->preview2_status = DT_DEV_PIXELPIPE_INVALID;
427     dt_pthread_mutex_unlock(&dev->preview2_pipe_mutex);
428     dt_mipmap_cache_release(darktable.mipmap_cache, &buf);
429     return;
430   }
431 
432   const dt_dev_pixelpipe_change_t pipe_changed = dev->pipe->changed;
433 
434   // adjust pipeline according to changed flag set by {add,pop}_history_item.
435   // this locks dev->history_mutex.
436   dt_times_t start;
437   dt_get_times(&start);
438   dt_dev_pixelpipe_change(dev->preview2_pipe, dev);
439 
440   const dt_dev_zoom_t zoom = dt_second_window_get_dev_zoom(dev);
441   const int closeup = dt_second_window_get_dev_closeup(dev);
442   float zoom_x = dt_second_window_get_dev_zoom_x(dev);
443   float zoom_y = dt_second_window_get_dev_zoom_y(dev);
444   // if just changed to an image with a different aspect ratio or
445   // altered image orientation, the prior zoom xy could now be beyond
446   // the image boundary
447   if(dev->preview2_loading || (pipe_changed != DT_DEV_PIPE_UNCHANGED))
448   {
449     dt_second_window_check_zoom_bounds(dev, &zoom_x, &zoom_y, zoom, closeup, NULL, NULL);
450     dt_second_window_set_dev_zoom_x(dev, zoom_x);
451     dt_second_window_set_dev_zoom_y(dev, zoom_y);
452   }
453   const float scale = dt_second_window_get_zoom_scale(dev, zoom, 1.0f, 0) * dev->second_window.ppd;
454   int window_width = dev->second_window.width * dev->second_window.ppd;
455   int window_height = dev->second_window.height * dev->second_window.ppd;
456   if(closeup)
457   {
458     window_width /= 1 << closeup;
459     window_height /= 1 << closeup;
460   }
461 
462   const int wd = MIN(window_width, dev->preview2_pipe->processed_width * scale);
463   const int ht = MIN(window_height, dev->preview2_pipe->processed_height * scale);
464   int x = MAX(0, scale * dev->preview2_pipe->processed_width * (.5 + zoom_x) - wd / 2);
465   int y = MAX(0, scale * dev->preview2_pipe->processed_height * (.5 + zoom_y) - ht / 2);
466 
467   if(dt_dev_pixelpipe_process(dev->preview2_pipe, dev, x, y, wd, ht, scale))
468   {
469     if(dev->preview2_loading || dev->preview2_input_changed)
470     {
471       dt_control_log_busy_leave();
472       dt_control_toast_busy_leave();
473       dev->preview2_status = DT_DEV_PIXELPIPE_INVALID;
474       dt_pthread_mutex_unlock(&dev->preview2_pipe_mutex);
475       dt_mipmap_cache_release(darktable.mipmap_cache, &buf);
476       return;
477     }
478     else
479       goto restart;
480   }
481 
482   dev->preview2_pipe->backbuf_scale = scale;
483   dev->preview2_pipe->backbuf_zoom_x = zoom_x;
484   dev->preview2_pipe->backbuf_zoom_y = zoom_y;
485 
486   dev->preview2_status = DT_DEV_PIXELPIPE_VALID;
487 
488   dt_show_times(&start, "[dev_process_preview2] pixel pipeline processing");
489   dt_dev_average_delay_update(&start, &dev->preview2_average_delay);
490 
491   dt_control_log_busy_leave();
492   dt_control_toast_busy_leave();
493   dt_pthread_mutex_unlock(&dev->preview2_pipe_mutex);
494   dt_mipmap_cache_release(darktable.mipmap_cache, &buf);
495 
496   DT_DEBUG_CONTROL_SIGNAL_RAISE(darktable.signals, DT_SIGNAL_DEVELOP_PREVIEW2_PIPE_FINISHED);
497 }
498 
dt_dev_process_image_job(dt_develop_t * dev)499 void dt_dev_process_image_job(dt_develop_t *dev)
500 {
501   dt_pthread_mutex_lock(&dev->pipe_mutex);
502 
503   if(dev->gui_leaving)
504   {
505     dt_pthread_mutex_unlock(&dev->pipe_mutex);
506     return;
507   }
508 
509   dt_control_log_busy_enter();
510   dt_control_toast_busy_enter();
511   // let gui know to draw preview instead of us, if it's there:
512   dev->image_status = DT_DEV_PIXELPIPE_RUNNING;
513 
514   dt_mipmap_buffer_t buf;
515   dt_times_t start;
516   dt_get_times(&start);
517   dt_mipmap_cache_get(darktable.mipmap_cache, &buf, dev->image_storage.id, DT_MIPMAP_FULL,
518                            DT_MIPMAP_BLOCKING, 'r');
519   dt_show_times_f(&start, "[dev]", "to load the image.");
520 
521   // failed to load raw?
522   if(!buf.buf)
523   {
524     dt_control_log_busy_leave();
525     dt_control_toast_busy_leave();
526     dev->image_status = DT_DEV_PIXELPIPE_DIRTY;
527     dt_pthread_mutex_unlock(&dev->pipe_mutex);
528     dev->image_invalid_cnt++;
529     return;
530   }
531 
532   dt_dev_pixelpipe_set_input(dev->pipe, dev, (float *)buf.buf, buf.width, buf.height, 1.0);
533 
534   if(dev->image_loading)
535   {
536     // init pixel pipeline
537     dt_dev_pixelpipe_cleanup_nodes(dev->pipe);
538     dt_dev_pixelpipe_create_nodes(dev->pipe, dev);
539     if(dev->image_force_reload) dt_dev_pixelpipe_flush_caches(dev->pipe);
540     dev->image_force_reload = FALSE;
541     if(dev->gui_attached)
542     {
543       // during load, a mipf update could have been issued.
544       dev->preview_input_changed = TRUE;
545       dev->preview_status = DT_DEV_PIXELPIPE_DIRTY;
546       dev->preview2_input_changed = TRUE;
547       dev->preview2_status = DT_DEV_PIXELPIPE_DIRTY;
548       dev->gui_synch = 1; // notify gui thread we want to synch (call gui_update in the modules)
549       dev->preview_pipe->changed |= DT_DEV_PIPE_SYNCH;
550       dev->preview2_pipe->changed |= DT_DEV_PIPE_SYNCH;
551     }
552     dev->pipe->changed |= DT_DEV_PIPE_SYNCH;
553   }
554 
555   dt_dev_zoom_t zoom;
556   float zoom_x = 0.0f, zoom_y = 0.0f, scale = 0.0f;
557   int window_width, window_height, x, y, closeup;
558   dt_dev_pixelpipe_change_t pipe_changed;
559 
560 // adjust pipeline according to changed flag set by {add,pop}_history_item.
561 restart:
562   if(dev->gui_leaving)
563   {
564     dt_mipmap_cache_release(darktable.mipmap_cache, &buf);
565     dt_control_log_busy_leave();
566     dt_control_toast_busy_leave();
567     dev->image_status = DT_DEV_PIXELPIPE_INVALID;
568     dt_pthread_mutex_unlock(&dev->pipe_mutex);
569     return;
570   }
571   dev->pipe->input_timestamp = dev->timestamp;
572   // dt_dev_pixelpipe_change() will clear the changed value
573   pipe_changed = dev->pipe->changed;
574   // this locks dev->history_mutex.
575   dt_dev_pixelpipe_change(dev->pipe, dev);
576   // determine scale according to new dimensions
577   zoom = dt_control_get_dev_zoom();
578   closeup = dt_control_get_dev_closeup();
579   zoom_x = dt_control_get_dev_zoom_x();
580   zoom_y = dt_control_get_dev_zoom_y();
581   // if just changed to an image with a different aspect ratio or
582   // altered image orientation, the prior zoom xy could now be beyond
583   // the image boundary
584   if(dev->image_loading || (pipe_changed != DT_DEV_PIPE_UNCHANGED))
585   {
586     dt_dev_check_zoom_bounds(dev, &zoom_x, &zoom_y, zoom, closeup, NULL, NULL);
587     dt_control_set_dev_zoom_x(zoom_x);
588     dt_control_set_dev_zoom_y(zoom_y);
589   }
590 
591   scale = dt_dev_get_zoom_scale(dev, zoom, 1.0f, 0) * darktable.gui->ppd;
592   window_width = dev->width * darktable.gui->ppd;
593   window_height = dev->height * darktable.gui->ppd;
594   if(closeup)
595   {
596     window_width /= 1<<closeup;
597     window_height /= 1<<closeup;
598   }
599   const int wd = MIN(window_width, dev->pipe->processed_width * scale);
600   const int ht = MIN(window_height, dev->pipe->processed_height * scale);
601   x = MAX(0, scale * dev->pipe->processed_width  * (.5 + zoom_x) - wd / 2);
602   y = MAX(0, scale * dev->pipe->processed_height * (.5 + zoom_y) - ht / 2);
603 
604   dt_get_times(&start);
605   if(dt_dev_pixelpipe_process(dev->pipe, dev, x, y, wd, ht, scale))
606   {
607     // interrupted because image changed?
608     if(dev->image_force_reload)
609     {
610       dt_mipmap_cache_release(darktable.mipmap_cache, &buf);
611       dt_control_log_busy_leave();
612       dt_control_toast_busy_leave();
613       dev->image_status = DT_DEV_PIXELPIPE_INVALID;
614       dt_pthread_mutex_unlock(&dev->pipe_mutex);
615       return;
616     }
617     // or because the pipeline changed?
618     else
619       goto restart;
620   }
621   dt_show_times(&start, "[dev_process_image] pixel pipeline processing");
622   dt_dev_average_delay_update(&start, &dev->average_delay);
623 
624   // maybe we got zoomed/panned in the meantime?
625   if(dev->pipe->changed != DT_DEV_PIPE_UNCHANGED) goto restart;
626 
627   // cool, we got a new image!
628   dev->pipe->backbuf_scale = scale;
629   dev->pipe->backbuf_zoom_x = zoom_x;
630   dev->pipe->backbuf_zoom_y = zoom_y;
631 
632   dev->image_status = DT_DEV_PIXELPIPE_VALID;
633   dev->image_loading = FALSE;
634   dev->image_invalid_cnt = 0;
635   dt_mipmap_cache_release(darktable.mipmap_cache, &buf);
636   // if a widget needs to be redraw there's the DT_SIGNAL_*_PIPE_FINISHED signals
637   dt_control_log_busy_leave();
638   dt_control_toast_busy_leave();
639   dt_pthread_mutex_unlock(&dev->pipe_mutex);
640 
641   if(dev->gui_attached && !dev->gui_leaving)
642     DT_DEBUG_CONTROL_SIGNAL_RAISE(darktable.signals, DT_SIGNAL_DEVELOP_UI_PIPE_FINISHED);
643 }
644 
645 
_dt_dev_load_pipeline_defaults(dt_develop_t * dev)646 static inline void _dt_dev_load_pipeline_defaults(dt_develop_t *dev)
647 {
648   for(const GList *modules = g_list_last(dev->iop); modules; modules = g_list_previous(modules))
649   {
650     dt_iop_module_t *module = (dt_iop_module_t *)(modules->data);
651     dt_iop_reload_defaults(module);
652   }
653 }
654 
655 // load the raw and get the new image struct, blocking in gui thread
_dt_dev_load_raw(dt_develop_t * dev,const uint32_t imgid)656 static inline void _dt_dev_load_raw(dt_develop_t *dev, const uint32_t imgid)
657 {
658   // first load the raw, to make sure dt_image_t will contain all and correct data.
659   dt_mipmap_buffer_t buf;
660   dt_times_t start;
661   dt_get_times(&start);
662   dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING, 'r');
663   dt_mipmap_cache_release(darktable.mipmap_cache, &buf);
664   dt_show_times_f(&start, "[dev]", "to load the image.");
665 
666   const dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'r');
667   dev->image_storage = *image;
668   dt_image_cache_read_release(darktable.image_cache, image);
669 }
670 
dt_dev_reload_image(dt_develop_t * dev,const uint32_t imgid)671 void dt_dev_reload_image(dt_develop_t *dev, const uint32_t imgid)
672 {
673   _dt_dev_load_raw(dev, imgid);
674   dev->image_force_reload = dev->image_loading = dev->preview_loading = dev->preview2_loading = TRUE;
675 
676   dev->pipe->changed |= DT_DEV_PIPE_SYNCH;
677   dt_dev_invalidate(dev); // only invalidate image, preview will follow once it's loaded.
678 }
679 
dt_dev_get_zoom_scale(dt_develop_t * dev,dt_dev_zoom_t zoom,int closeup_factor,int preview)680 float dt_dev_get_zoom_scale(dt_develop_t *dev, dt_dev_zoom_t zoom, int closeup_factor, int preview)
681 {
682   float zoom_scale;
683 
684   const float w = preview ? dev->preview_pipe->processed_width : dev->pipe->processed_width;
685   const float h = preview ? dev->preview_pipe->processed_height : dev->pipe->processed_height;
686   const float ps = dev->pipe->backbuf_width
687                        ? dev->pipe->processed_width / (float)dev->preview_pipe->processed_width
688                        : dev->preview_pipe->iscale;
689 
690   switch(zoom)
691   {
692     case DT_ZOOM_FIT:
693       zoom_scale = fminf(dev->width / w, dev->height / h);
694       break;
695     case DT_ZOOM_FILL:
696       zoom_scale = fmaxf(dev->width / w, dev->height / h);
697       break;
698     case DT_ZOOM_1:
699       zoom_scale = closeup_factor;
700       if(preview) zoom_scale *= ps;
701       break;
702     default: // DT_ZOOM_FREE
703       zoom_scale = dt_control_get_dev_zoom_scale();
704       if(preview) zoom_scale *= ps;
705       break;
706   }
707   if (preview) zoom_scale /= dev->preview_downsampling;
708 
709   return zoom_scale;
710 }
711 
dt_dev_load_image(dt_develop_t * dev,const uint32_t imgid)712 void dt_dev_load_image(dt_develop_t *dev, const uint32_t imgid)
713 {
714   dt_lock_image(imgid);
715 
716   _dt_dev_load_raw(dev, imgid);
717 
718   if(dev->pipe)
719   {
720     dev->pipe->processed_width = 0;
721     dev->pipe->processed_height = 0;
722   }
723   dev->image_loading = dev->first_load = dev->preview_loading = dev->preview2_loading = TRUE;
724 
725   dev->image_status = dev->preview_status = dev->preview2_status = DT_DEV_PIXELPIPE_DIRTY;
726 
727   // we need a global lock as the dev->iop set must not be changed until read history is terminated
728   dt_pthread_mutex_lock(&darktable.dev_threadsafe);
729   dev->iop = dt_iop_load_modules(dev);
730 
731   dt_dev_read_history(dev);
732   dt_pthread_mutex_unlock(&darktable.dev_threadsafe);
733 
734   dev->first_load = FALSE;
735 
736   // Loading an image means we do some developing and so remove the darktable|problem|history-compress tag
737   dt_history_set_compress_problem(imgid, FALSE);
738 
739   dt_unlock_image(imgid);
740 }
741 
dt_dev_configure(dt_develop_t * dev,int wd,int ht)742 void dt_dev_configure(dt_develop_t *dev, int wd, int ht)
743 {
744   // fixed border on every side
745   const int32_t tb = dev->border_size;
746   wd -= 2*tb;
747   ht -= 2*tb;
748   if(dev->width != wd || dev->height != ht)
749   {
750     dev->width = wd;
751     dev->height = ht;
752     dev->preview_pipe->changed |= DT_DEV_PIPE_ZOOMED;
753     dev->preview2_pipe->changed |= DT_DEV_PIPE_ZOOMED;
754     dev->pipe->changed |= DT_DEV_PIPE_ZOOMED;
755     dt_dev_invalidate(dev);
756   }
757 }
758 
759 // helper used to synch a single history item with db
dt_dev_write_history_item(const int imgid,dt_dev_history_item_t * h,int32_t num)760 int dt_dev_write_history_item(const int imgid, dt_dev_history_item_t *h, int32_t num)
761 {
762   sqlite3_stmt *stmt;
763   DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
764                               "SELECT num FROM main.history WHERE imgid = ?1 AND num = ?2", -1, &stmt, NULL);
765   DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
766   DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, num);
767   if(sqlite3_step(stmt) != SQLITE_ROW)
768   {
769     sqlite3_finalize(stmt);
770     DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
771                                 "INSERT INTO main.history (imgid, num) VALUES (?1, ?2)", -1, &stmt, NULL);
772     DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
773     DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, num);
774     sqlite3_step(stmt);
775   }
776   // printf("[dev write history item] writing %d - %s params %f %f\n", h->module->instance, h->module->op,
777   // *(float *)h->params, *(((float *)h->params)+1));
778   sqlite3_finalize(stmt);
779   DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
780                               "UPDATE main.history"
781                               " SET operation = ?1, op_params = ?2, module = ?3, enabled = ?4, "
782                               "     blendop_params = ?7, blendop_version = ?8, multi_priority = ?9, multi_name = ?10"
783                               " WHERE imgid = ?5 AND num = ?6",
784                               -1, &stmt, NULL);
785   DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, h->module->op, -1, SQLITE_TRANSIENT);
786   DT_DEBUG_SQLITE3_BIND_BLOB(stmt, 2, h->params, h->module->params_size, SQLITE_TRANSIENT);
787   DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, h->module->version());
788   DT_DEBUG_SQLITE3_BIND_INT(stmt, 4, h->enabled);
789   DT_DEBUG_SQLITE3_BIND_INT(stmt, 5, imgid);
790   DT_DEBUG_SQLITE3_BIND_INT(stmt, 6, num);
791   DT_DEBUG_SQLITE3_BIND_BLOB(stmt, 7, h->blend_params, sizeof(dt_develop_blend_params_t), SQLITE_TRANSIENT);
792   DT_DEBUG_SQLITE3_BIND_INT(stmt, 8, dt_develop_blend_version());
793   DT_DEBUG_SQLITE3_BIND_INT(stmt, 9, h->multi_priority);
794   DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 10, h->multi_name, -1, SQLITE_TRANSIENT);
795 
796   sqlite3_step(stmt);
797   sqlite3_finalize(stmt);
798 
799   // write masks (if any)
800   for(GList *forms = h->forms; forms; forms = g_list_next(forms))
801   {
802     dt_masks_form_t *form = (dt_masks_form_t *)forms->data;
803     if (form)
804       dt_masks_write_masks_history_item(imgid, num, form);
805   }
806 
807   return 0;
808 }
809 
_dev_add_history_item_ext(dt_develop_t * dev,dt_iop_module_t * module,gboolean enable,gboolean new_item,gboolean no_image,gboolean include_masks)810 static void _dev_add_history_item_ext(dt_develop_t *dev, dt_iop_module_t *module, gboolean enable,
811                                       gboolean new_item, gboolean no_image, gboolean include_masks)
812 {
813   int kept_module = 0;
814   GList *history = g_list_nth(dev->history, dev->history_end);
815   // look for leaks on top of history in two steps
816   // first remove obsolete items above history_end
817   // but keep the always-on modules
818   while(history)
819   {
820     GList *next = g_list_next(history);
821     dt_dev_history_item_t *hist = (dt_dev_history_item_t *)(history->data);
822     // printf("removing obsoleted history item: %s\n", hist->module->op);
823     if(!hist->module->hide_enable_button && !hist->module->default_enabled)
824     {
825       dt_dev_free_history_item(hist);
826       dev->history = g_list_delete_link(dev->history, history);
827     }
828     else
829       kept_module++;
830     history = next;
831   }
832   // then remove NIL items there
833   while ((dev->history_end>0) && (! g_list_nth(dev->history, dev->history_end - 1)))
834     dev->history_end--;
835 
836   dev->history_end += kept_module;
837 
838   history = g_list_nth(dev->history, dev->history_end - 1);
839   dt_dev_history_item_t *hist = history ? (dt_dev_history_item_t *)(history->data) : 0;
840   if(!history                                                  // no history yet, push new item
841      || new_item                                               // a new item is requested
842      || module != hist->module
843      || module->instance != hist->module->instance             // add new item for different op
844      || module->multi_priority != hist->module->multi_priority // or instance
845      || ((dev->focus_hash != hist->focus_hash)                 // or if focused out and in
846          // but only add item if there is a difference at all for the same module
847          && ((module->params_size != hist->module->params_size)
848              || include_masks
849              || (module->params_size == hist->module->params_size
850                  && memcmp(hist->params, module->params, module->params_size)))))
851   {
852     // new operation, push new item
853     // printf("adding new history item %d - %s\n", dev->history_end, module->op);
854     // if(history) printf("because item %d - %s is different operation.\n", dev->history_end-1,
855     // ((dt_dev_history_item_t *)history->data)->module->op);
856     dev->history_end++;
857 
858     hist = (dt_dev_history_item_t *)calloc(1, sizeof(dt_dev_history_item_t));
859     if(enable)
860     {
861       module->enabled = TRUE;
862       if(!no_image)
863       {
864         if(module->off)
865         {
866           ++darktable.gui->reset;
867           dt_iop_gui_set_enable_button(module);
868           --darktable.gui->reset;
869         }
870       }
871     }
872     g_strlcpy(hist->op_name, module->op, sizeof(hist->op_name));
873     hist->focus_hash = dev->focus_hash;
874     hist->enabled = module->enabled;
875     hist->module = module;
876     hist->params = malloc(module->params_size);
877     hist->iop_order = module->iop_order;
878     hist->multi_priority = module->multi_priority;
879     g_strlcpy(hist->multi_name, module->multi_name, sizeof(hist->multi_name));
880     /* allocate and set hist blend_params */
881     hist->blend_params = malloc(sizeof(dt_develop_blend_params_t));
882     memcpy(hist->params, module->params, module->params_size);
883     memcpy(hist->blend_params, module->blend_params, sizeof(dt_develop_blend_params_t));
884     if(include_masks)
885       hist->forms = dt_masks_dup_forms_deep(dev->forms, NULL);
886     else
887       hist->forms = NULL;
888 
889     dev->history = g_list_append(dev->history, hist);
890     if(!no_image)
891     {
892       dev->pipe->changed |= DT_DEV_PIPE_SYNCH;
893       dev->preview_pipe->changed |= DT_DEV_PIPE_SYNCH; // topology remains, as modules are fixed for now.
894       dev->preview2_pipe->changed |= DT_DEV_PIPE_SYNCH; // topology remains, as modules are fixed for now.
895     }
896   }
897   else
898   {
899     // same operation, change params
900     // printf("changing same history item %d - %s\n", dev->history_end-1, module->op);
901     hist = (dt_dev_history_item_t *)history->data;
902     memcpy(hist->params, module->params, module->params_size);
903 
904     if(module->flags() & IOP_FLAGS_SUPPORTS_BLENDING)
905       memcpy(hist->blend_params, module->blend_params, sizeof(dt_develop_blend_params_t));
906 
907     // if the user changed stuff and the module is still not enabled, do it:
908     if(!hist->enabled && !module->enabled)
909     {
910       module->enabled = 1;
911       if(!no_image)
912       {
913         if(module->off)
914         {
915           ++darktable.gui->reset;
916           dt_iop_gui_set_enable_button(module);
917           --darktable.gui->reset;
918         }
919       }
920     }
921     hist->iop_order = module->iop_order;
922     hist->multi_priority = module->multi_priority;
923     memcpy(hist->multi_name, module->multi_name, sizeof(module->multi_name));
924     hist->enabled = module->enabled;
925 
926     if(include_masks)
927     {
928       g_list_free_full(hist->forms, (void (*)(void *))dt_masks_free_form);
929       hist->forms = dt_masks_dup_forms_deep(dev->forms, NULL);
930     }
931     if(!no_image)
932     {
933       dev->pipe->changed |= DT_DEV_PIPE_TOP_CHANGED;
934       dev->preview_pipe->changed |= DT_DEV_PIPE_TOP_CHANGED;
935       dev->preview2_pipe->changed |= DT_DEV_PIPE_TOP_CHANGED;
936     }
937   }
938 }
939 
dt_dev_add_history_item_ext(dt_develop_t * dev,dt_iop_module_t * module,gboolean enable,const int no_image)940 void dt_dev_add_history_item_ext(dt_develop_t *dev, dt_iop_module_t *module, gboolean enable, const int no_image)
941 {
942   _dev_add_history_item_ext(dev, module, enable, FALSE, no_image, FALSE);
943 }
944 
_dev_add_history_item(dt_develop_t * dev,dt_iop_module_t * module,gboolean enable,gboolean new_item)945 void _dev_add_history_item(dt_develop_t *dev, dt_iop_module_t *module, gboolean enable, gboolean new_item)
946 {
947   if(!darktable.gui || darktable.gui->reset) return;
948 
949   dt_dev_undo_start_record(dev);
950 
951   dt_pthread_mutex_lock(&dev->history_mutex);
952 
953   if(dev->gui_attached)
954   {
955     _dev_add_history_item_ext(dev, module, enable, new_item, FALSE, FALSE);
956   }
957 #if 0
958   {
959     // debug:
960     printf("remaining %d history items:\n", dev->history_end);
961     int i = 0;
962     for(GList *history = dev->history; history; history = g_list_next(history))
963     {
964       dt_dev_history_item_t *hist = (dt_dev_history_item_t *)(history->data);
965       printf("%d %s\n", i, hist->module->op);
966       i++;
967     }
968   }
969 #endif
970 
971   /* attach changed tag reflecting actual change */
972   const int imgid = dev->image_storage.id;
973   guint tagid = 0;
974   dt_tag_new("darktable|changed", &tagid);
975   const gboolean tag_change = dt_tag_attach(tagid, imgid, FALSE, FALSE);
976 
977   /* register export timestamp in cache */
978   dt_image_cache_set_change_timestamp(darktable.image_cache, imgid);
979 
980   // invalidate buffers and force redraw of darkroom
981   dt_dev_invalidate_all(dev);
982   dt_pthread_mutex_unlock(&dev->history_mutex);
983 
984   if(dev->gui_attached)
985   {
986     /* signal that history has changed */
987     dt_dev_undo_end_record(dev);
988 
989     if(tag_change) DT_DEBUG_CONTROL_SIGNAL_RAISE(darktable.signals, DT_SIGNAL_TAG_CHANGED);
990 
991     /* redraw */
992     dt_control_queue_redraw_center();
993   }
994 }
995 
dt_dev_add_history_item(dt_develop_t * dev,dt_iop_module_t * module,gboolean enable)996 void dt_dev_add_history_item(dt_develop_t *dev, dt_iop_module_t *module, gboolean enable)
997 {
998   _dev_add_history_item(dev, module, enable, FALSE);
999 }
1000 
dt_dev_add_new_history_item(dt_develop_t * dev,dt_iop_module_t * module,gboolean enable)1001 void dt_dev_add_new_history_item(dt_develop_t *dev, dt_iop_module_t *module, gboolean enable)
1002 {
1003   _dev_add_history_item(dev, module, enable, TRUE);
1004 }
1005 
dt_dev_add_masks_history_item_ext(dt_develop_t * dev,dt_iop_module_t * _module,gboolean _enable,gboolean no_image)1006 void dt_dev_add_masks_history_item_ext(dt_develop_t *dev, dt_iop_module_t *_module, gboolean _enable, gboolean no_image)
1007 {
1008   dt_iop_module_t *module = _module;
1009   gboolean enable = _enable;
1010 
1011   // no module means that is called from the mask manager, so find the iop
1012   if(module == NULL)
1013   {
1014     for(GList *modules = dev->iop; modules; modules = g_list_next(modules))
1015     {
1016       dt_iop_module_t *mod = (dt_iop_module_t *)(modules->data);
1017       if(strcmp(mod->op, "mask_manager") == 0)
1018       {
1019         module = mod;
1020         break;
1021       }
1022     }
1023     enable = FALSE;
1024   }
1025   if(module)
1026   {
1027     _dev_add_history_item_ext(dev, module, enable, FALSE, no_image, TRUE);
1028   }
1029   else
1030     fprintf(stderr, "[dt_dev_add_masks_history_item_ext] can't find mask manager module\n");
1031 }
1032 
dt_dev_add_masks_history_item(dt_develop_t * dev,dt_iop_module_t * module,gboolean enable)1033 void dt_dev_add_masks_history_item(dt_develop_t *dev, dt_iop_module_t *module, gboolean enable)
1034 {
1035   if(!darktable.gui || darktable.gui->reset) return;
1036 
1037   dt_dev_undo_start_record(dev);
1038 
1039   dt_pthread_mutex_lock(&dev->history_mutex);
1040 
1041   if(dev->gui_attached)
1042   {
1043     dt_dev_add_masks_history_item_ext(dev, module, enable, FALSE);
1044   }
1045 
1046   // invalidate buffers and force redraw of darkroom
1047   dt_dev_invalidate_all(dev);
1048   dt_pthread_mutex_unlock(&dev->history_mutex);
1049 
1050   if(dev->gui_attached)
1051   {
1052     /* signal that history has changed */
1053     dt_dev_undo_end_record(dev);
1054 
1055     /* recreate mask list */
1056     dt_dev_masks_list_change(dev);
1057 
1058     /* redraw */
1059     dt_control_queue_redraw_center();
1060   }
1061 }
1062 
dt_dev_free_history_item(gpointer data)1063 void dt_dev_free_history_item(gpointer data)
1064 {
1065   dt_dev_history_item_t *item = (dt_dev_history_item_t *)data;
1066   free(item->params);
1067   free(item->blend_params);
1068   g_list_free_full(item->forms, (void (*)(void *))dt_masks_free_form);
1069   free(item);
1070 }
1071 
dt_dev_reload_history_items(dt_develop_t * dev)1072 void dt_dev_reload_history_items(dt_develop_t *dev)
1073 {
1074   dev->focus_hash = 0;
1075 
1076   dt_lock_image(dev->image_storage.id);
1077 
1078   dt_ioppr_set_default_iop_order(dev, dev->image_storage.id);
1079   dt_dev_pop_history_items(dev, 0);
1080 
1081   // remove unused history items:
1082   GList *history = g_list_nth(dev->history, dev->history_end);
1083   while(history)
1084   {
1085     GList *next = g_list_next(history);
1086     dt_dev_history_item_t *hist = (dt_dev_history_item_t *)(history->data);
1087     dt_dev_free_history_item(hist);
1088     dev->history = g_list_delete_link(dev->history, history);
1089     history = next;
1090   }
1091   dt_dev_read_history(dev);
1092 
1093   // we have to add new module instances first
1094   for(GList *modules = dev->iop; modules; modules = g_list_next(modules))
1095   {
1096     dt_iop_module_t *module = (dt_iop_module_t *)(modules->data);
1097     if(module->multi_priority > 0)
1098     {
1099       if(!dt_iop_is_hidden(module) && !module->expander)
1100       {
1101         dt_iop_gui_init(module);
1102 
1103         /* add module to right panel */
1104         dt_iop_gui_set_expander(module);
1105         dt_iop_gui_set_expanded(module, TRUE, FALSE);
1106 
1107         dt_iop_reload_defaults(module);
1108         dt_iop_gui_update_blending(module);
1109 
1110         // the pipe need to be reconstruct
1111         dev->pipe->changed |= DT_DEV_PIPE_REMOVE;
1112         dev->preview_pipe->changed |= DT_DEV_PIPE_REMOVE;
1113         dev->preview2_pipe->changed |= DT_DEV_PIPE_REMOVE;
1114       }
1115     }
1116     else if(!dt_iop_is_hidden(module) && module->expander)
1117     {
1118       // we have to ensure that the name of the widget is correct
1119       GtkWidget *child = dt_gui_container_first_child(GTK_CONTAINER(module->expander));
1120       GtkWidget *header = gtk_bin_get_child(GTK_BIN(child));
1121 
1122       GtkWidget *wlabel = dt_gui_container_nth_child(GTK_CONTAINER(header), IOP_MODULE_LABEL);
1123       gchar *label = dt_history_item_get_name_html(module);
1124       gtk_label_set_markup(GTK_LABEL(wlabel), label);
1125       g_free(label);
1126     }
1127   }
1128 
1129   dt_dev_pop_history_items(dev, dev->history_end);
1130 
1131   dt_ioppr_resync_iop_list(dev);
1132 
1133   // set the module list order
1134   dt_dev_reorder_gui_module_list(dev);
1135 
1136   // we update show params for multi-instances for each other instances
1137   dt_dev_modules_update_multishow(dev);
1138 
1139   dt_unlock_image(dev->image_storage.id);
1140 }
1141 
dt_dev_pop_history_items_ext(dt_develop_t * dev,int32_t cnt)1142 void dt_dev_pop_history_items_ext(dt_develop_t *dev, int32_t cnt)
1143 {
1144   dt_ioppr_check_iop_order(dev, 0, "dt_dev_pop_history_items_ext begin");
1145   const int end_prev = dev->history_end;
1146   dev->history_end = cnt;
1147 
1148   // reset gui params for all modules
1149   for(GList *modules = dev->iop; modules; modules = g_list_next(modules))
1150   {
1151     dt_iop_module_t *module = (dt_iop_module_t *)(modules->data);
1152     memcpy(module->params, module->default_params, module->params_size);
1153     dt_iop_commit_blend_params(module, module->default_blendop_params);
1154     module->enabled = module->default_enabled;
1155 
1156     if(module->multi_priority == 0)
1157       module->iop_order = dt_ioppr_get_iop_order(dev->iop_order_list, module->op, module->multi_priority);
1158     else
1159     {
1160       module->iop_order = INT_MAX;
1161     }
1162   }
1163 
1164   // go through history and set gui params
1165   GList *forms = NULL;
1166   GList *history = dev->history;
1167   for(int i = 0; i < cnt && history; i++)
1168   {
1169     dt_dev_history_item_t *hist = (dt_dev_history_item_t *)(history->data);
1170     memcpy(hist->module->params, hist->params, hist->module->params_size);
1171     dt_iop_commit_blend_params(hist->module, hist->blend_params);
1172 
1173     hist->module->iop_order = hist->iop_order;
1174     hist->module->enabled = hist->enabled;
1175     g_strlcpy(hist->module->multi_name, hist->multi_name, sizeof(hist->module->multi_name));
1176     if(hist->forms) forms = hist->forms;
1177 
1178     history = g_list_next(history);
1179   }
1180 
1181   dt_ioppr_resync_modules_order(dev);
1182 
1183   dt_ioppr_check_duplicate_iop_order(&dev->iop, dev->history);
1184 
1185   dt_ioppr_check_iop_order(dev, 0, "dt_dev_pop_history_items_ext end");
1186 
1187   // check if masks have changed
1188   int masks_changed = 0;
1189   if(cnt < end_prev)
1190     history = g_list_nth(dev->history, cnt);
1191   else if(cnt > end_prev)
1192     history = g_list_nth(dev->history, end_prev);
1193   else
1194     history = NULL;
1195   for(int i = MIN(cnt, end_prev); i < MAX(cnt, end_prev) && history && !masks_changed; i++)
1196   {
1197     dt_dev_history_item_t *hist = (dt_dev_history_item_t *)(history->data);
1198 
1199     if(hist->forms != NULL)
1200       masks_changed = 1;
1201 
1202     history = g_list_next(history);
1203   }
1204   if(masks_changed)
1205     dt_masks_replace_current_forms(dev, forms);
1206 }
1207 
dt_dev_pop_history_items(dt_develop_t * dev,int32_t cnt)1208 void dt_dev_pop_history_items(dt_develop_t *dev, int32_t cnt)
1209 {
1210   dt_pthread_mutex_lock(&dev->history_mutex);
1211   ++darktable.gui->reset;
1212   GList *dev_iop = g_list_copy(dev->iop);
1213 
1214   dt_dev_pop_history_items_ext(dev, cnt);
1215 
1216   darktable.develop->history_updating = TRUE;
1217 
1218   // update all gui modules
1219   GList *modules = dev->iop;
1220   while(modules)
1221   {
1222     dt_iop_module_t *module = (dt_iop_module_t *)(modules->data);
1223     dt_iop_gui_update(module);
1224     modules = g_list_next(modules);
1225   }
1226 
1227   darktable.develop->history_updating = FALSE;
1228 
1229   // check if the order of modules has changed
1230   int dev_iop_changed = (g_list_length(dev_iop) != g_list_length(dev->iop));
1231   if(!dev_iop_changed)
1232   {
1233     modules = dev->iop;
1234     GList *modules_old = dev_iop;
1235     while(modules && modules_old)
1236     {
1237       dt_iop_module_t *module = (dt_iop_module_t *)(modules->data);
1238       dt_iop_module_t *module_old = (dt_iop_module_t *)(modules_old->data);
1239 
1240       if(module->iop_order != module_old->iop_order)
1241       {
1242         dev_iop_changed = 1;
1243         break;
1244       }
1245 
1246       modules = g_list_next(modules);
1247       modules_old = g_list_next(modules_old);
1248     }
1249   }
1250   g_list_free(dev_iop);
1251 
1252   if(!dev_iop_changed)
1253   {
1254     dev->pipe->changed |= DT_DEV_PIPE_SYNCH;
1255     dev->preview_pipe->changed |= DT_DEV_PIPE_SYNCH; // again, fixed topology for now.
1256     dev->preview2_pipe->changed |= DT_DEV_PIPE_SYNCH; // again, fixed topology for now.
1257   }
1258   else
1259   {
1260     dev->pipe->changed |= DT_DEV_PIPE_REMOVE;
1261     dev->preview_pipe->changed |= DT_DEV_PIPE_REMOVE;
1262     dev->preview2_pipe->changed |= DT_DEV_PIPE_REMOVE;
1263     dev->pipe->cache_obsolete = 1;
1264     dev->preview_pipe->cache_obsolete = 1;
1265     dev->preview2_pipe->cache_obsolete = 1;
1266   }
1267 
1268   --darktable.gui->reset;
1269   dt_dev_invalidate_all(dev);
1270   dt_pthread_mutex_unlock(&dev->history_mutex);
1271 
1272   dt_dev_masks_list_change(dev);
1273 
1274   dt_control_queue_redraw_center();
1275 }
1276 
_cleanup_history(const int imgid)1277 static void _cleanup_history(const int imgid)
1278 {
1279   sqlite3_stmt *stmt;
1280   DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.history WHERE imgid = ?1", -1,
1281                               &stmt, NULL);
1282   DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
1283   sqlite3_step(stmt);
1284   sqlite3_finalize(stmt);
1285 
1286   DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.masks_history WHERE imgid = ?1", -1,
1287                               &stmt, NULL);
1288   DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
1289   sqlite3_step(stmt);
1290   sqlite3_finalize(stmt);
1291 }
1292 
dt_dev_write_history_ext(dt_develop_t * dev,const int imgid)1293 void dt_dev_write_history_ext(dt_develop_t *dev, const int imgid)
1294 {
1295   sqlite3_stmt *stmt;
1296   dt_lock_image(imgid);
1297 
1298   _cleanup_history(imgid);
1299 
1300   // write history entries
1301 
1302   GList *history = dev->history;
1303   if (DT_IOP_ORDER_INFO)
1304     fprintf(stderr,"\n^^^^ Writing history image: %i, iop version: %i",imgid,dev->iop_order_version);
1305   for(int i = 0; history; i++)
1306   {
1307     dt_dev_history_item_t *hist = (dt_dev_history_item_t *)(history->data);
1308     (void)dt_dev_write_history_item(imgid, hist, i);
1309     if (DT_IOP_ORDER_INFO)
1310     {
1311       fprintf(stderr,"\n%20s, num %i, order %d, v(%i), multiprio %i",
1312               hist->module->op,i,hist->iop_order,hist->module->version(),hist->multi_priority);
1313       if (hist->enabled) fprintf(stderr,", enabled");
1314     }
1315     history = g_list_next(history);
1316   }
1317   if (DT_IOP_ORDER_INFO)
1318     fprintf(stderr,"\nvvvv\n");
1319 
1320   // update history end
1321   DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
1322                               "UPDATE main.images SET history_end = ?1 WHERE id = ?2", -1,
1323                               &stmt, NULL);
1324   DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dev->history_end);
1325   DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);
1326   sqlite3_step(stmt);
1327   sqlite3_finalize(stmt);
1328 
1329   // write the current iop-order-list for this image
1330 
1331   dt_ioppr_write_iop_order_list(dev->iop_order_list, imgid);
1332   dt_history_hash_write_from_history(imgid, DT_HISTORY_HASH_CURRENT);
1333 
1334   dt_unlock_image(imgid);
1335 }
1336 
dt_dev_write_history(dt_develop_t * dev)1337 void dt_dev_write_history(dt_develop_t *dev)
1338 {
1339   dt_dev_write_history_ext(dev, dev->image_storage.id);
1340 }
1341 
_dev_get_module_nb_records()1342 static int _dev_get_module_nb_records()
1343 {
1344   sqlite3_stmt *stmt;
1345   DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
1346                               "SELECT count (*) FROM  memory.history",
1347                               -1, &stmt, NULL);
1348   sqlite3_step(stmt);
1349   const int cnt = sqlite3_column_int(stmt, 0);
1350   sqlite3_finalize(stmt);
1351   return cnt;
1352 }
1353 
_dev_insert_module(dt_develop_t * dev,dt_iop_module_t * module,const int imgid)1354 void _dev_insert_module(dt_develop_t *dev, dt_iop_module_t *module, const int imgid)
1355 {
1356   sqlite3_stmt *stmt;
1357 
1358   DT_DEBUG_SQLITE3_PREPARE_V2(
1359     dt_database_get(darktable.db),
1360     "INSERT INTO memory.history VALUES (?1, 0, ?2, ?3, ?4, 1, NULL, 0, 0, '')",
1361     -1, &stmt, NULL);
1362   DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
1363   DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, module->version());
1364   DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 3, module->op, -1, SQLITE_TRANSIENT);
1365   DT_DEBUG_SQLITE3_BIND_BLOB(stmt, 4, module->default_params, module->params_size, SQLITE_TRANSIENT);
1366   sqlite3_step(stmt);
1367   sqlite3_finalize(stmt);
1368 
1369   dt_print(DT_DEBUG_PARAMS, "[history] module %s inserted to history\n", module->op);
1370 }
1371 
_dev_auto_apply_presets(dt_develop_t * dev)1372 static gboolean _dev_auto_apply_presets(dt_develop_t *dev)
1373 {
1374   // NOTE: the presets/default iops will be *prepended* into the history.
1375 
1376   const int imgid = dev->image_storage.id;
1377 
1378   if(imgid <= 0) return FALSE;
1379 
1380   gboolean run = FALSE;
1381   dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'w');
1382   if(!(image->flags & DT_IMAGE_AUTO_PRESETS_APPLIED)) run = TRUE;
1383 
1384   const gboolean is_raw = dt_image_is_raw(image);
1385   const gboolean is_modern_chroma =
1386     dt_conf_is_equal("plugins/darkroom/chromatic-adaptation", "modern");
1387 
1388   // flag was already set? only apply presets once in the lifetime of a history stack.
1389   // (the flag will be cleared when removing it).
1390   if(!run || image->id <= 0)
1391   {
1392     // Next section is to recover old edits where all modules with default parameters were not
1393     // recorded in the db nor in the .XMP.
1394     //
1395     // One crutial point is the white-balance which has automatic default based on the camera
1396     // and depends on the chroma-adaptation. In modern mode the default won't be the same used
1397     // in legacy mode and if the white-balance is not found on the history one will be added by
1398     // default using current defaults. But if we are in modern chromatic adaptation the default
1399     // will not be equivalent to the one used to develop this old edit.
1400 
1401     // So if the current mode is the modern chromatic-adaptation, do check the history.
1402 
1403     if(is_modern_chroma && is_raw)
1404     {
1405       // loop over all modules and display a message for default-enabled modules that
1406       // are not found on the history.
1407 
1408       for(GList *modules = dev->iop; modules; modules = g_list_next(modules))
1409       {
1410         dt_iop_module_t *module = (dt_iop_module_t *)modules->data;
1411 
1412         if(module->default_enabled
1413            && !(module->flags() & IOP_FLAGS_NO_HISTORY_STACK)
1414            && !dt_history_check_module_exists(imgid, module->op))
1415         {
1416           fprintf(stderr,
1417                   "[_dev_auto_apply_presets] missing mandatory module %s for image %d\n",
1418                   module->op, imgid);
1419 
1420           // If the module is white-balance and we are dealing with a raw file we need to add
1421           // one now with the default legacy parameters. And we want to do this only for
1422           // old edits.
1423           //
1424           // For new edits the temperature will be added back depending on the chromatic
1425           // adaptation the standard way.
1426 
1427           if(!strcmp(module->op, "temperature")
1428              && (image->change_timestamp == -1))
1429           {
1430             // it is important to recover temperature in this case (modern chroma and
1431             // not module present as we need to have the pre 3.0 default parameters used.
1432 
1433             dt_conf_set_string("plugins/darkroom/chromatic-adaptation", "legacy");
1434             dt_iop_reload_defaults(module);
1435             _dev_insert_module(dev, module, imgid);
1436             dt_conf_set_string("plugins/darkroom/chromatic-adaptation", "modern");
1437             dt_iop_reload_defaults(module);
1438           }
1439         }
1440       }
1441     }
1442 
1443     dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_RELAXED);
1444     return FALSE;
1445   }
1446 
1447   gchar *workflow = dt_conf_get_string("plugins/darkroom/workflow");
1448   const gboolean is_scene_referred = strcmp(workflow, "scene-referred") == 0;
1449   const gboolean is_display_referred = strcmp(workflow, "display-referred") == 0;
1450   const gboolean is_workflow_none = strcmp(workflow, "none") == 0;
1451   g_free(workflow);
1452 
1453   //  Add scene-referred workflow
1454   //  Note that we cannot use a preset for FilmicRGB as the default values are
1455   //  dynamically computed depending on the actual exposure compensation
1456   //  (see reload_default routine in filmicrgb.c)
1457 
1458   const gboolean has_matrix = dt_image_is_matrix_correction_supported(image);
1459 
1460   const gboolean auto_apply_filmic = is_raw && is_scene_referred;
1461   const gboolean auto_apply_cat = has_matrix && is_modern_chroma;
1462   const gboolean auto_apply_sharpen = dt_conf_get_bool("plugins/darkroom/sharpen/auto_apply");
1463 
1464   if(auto_apply_filmic || auto_apply_sharpen || auto_apply_cat)
1465   {
1466     for(GList *modules = dev->iop; modules; modules = g_list_next(modules))
1467     {
1468       dt_iop_module_t *module = (dt_iop_module_t *)modules->data;
1469 
1470       if(((auto_apply_filmic && strcmp(module->op, "filmicrgb") == 0)
1471           || (auto_apply_sharpen && strcmp(module->op, "sharpen") == 0)
1472           || (auto_apply_cat && strcmp(module->op, "channelmixerrgb") == 0))
1473          && !dt_history_check_module_exists(imgid, module->op)
1474          && !(module->flags() & IOP_FLAGS_NO_HISTORY_STACK))
1475       {
1476         _dev_insert_module(dev, module, imgid);
1477       }
1478     }
1479   }
1480 
1481   // select all presets from one of the following table and add them into memory.history. Note that
1482   // this is appended to possibly already present default modules.
1483   const char *preset_table[2] = { "data.presets", "main.legacy_presets" };
1484   const int legacy = (image->flags & DT_IMAGE_NO_LEGACY_PRESETS) ? 0 : 1;
1485   char query[1024];
1486   snprintf(query, sizeof(query),
1487            "INSERT INTO memory.history"
1488            " SELECT ?1, 0, op_version, operation, op_params,"
1489            "       enabled, blendop_params, blendop_version, multi_priority, multi_name"
1490            " FROM %s"
1491            " WHERE ( (autoapply=1"
1492            "          AND ((?2 LIKE model AND ?3 LIKE maker) OR (?4 LIKE model AND ?5 LIKE maker))"
1493            "          AND ?6 LIKE lens AND ?7 BETWEEN iso_min AND iso_max"
1494            "          AND ?8 BETWEEN exposure_min AND exposure_max"
1495            "          AND ?9 BETWEEN aperture_min AND aperture_max"
1496            "          AND ?10 BETWEEN focal_length_min AND focal_length_max"
1497            "          AND (format = 0 OR (format&?11 != 0 AND ~format&?12 != 0)))"
1498            "        OR (name = ?13))"
1499            "   AND operation NOT IN"
1500            "        ('ioporder', 'metadata', 'modulegroups', 'export', 'tagging', 'collect', '%s')"
1501            " ORDER BY writeprotect DESC, LENGTH(model), LENGTH(maker), LENGTH(lens)",
1502            preset_table[legacy],
1503            is_display_referred?"":"basecurve");
1504   // query for all modules at once:
1505   sqlite3_stmt *stmt;
1506   const char *workflow_preset = has_matrix && is_display_referred
1507                                 ? _("display-referred default")
1508                                 : (has_matrix && is_scene_referred
1509                                    ?_("scene-referred default")
1510                                    :"\t\n");
1511   int iformat = 0;
1512   if(dt_image_is_rawprepare_supported(image)) iformat |= FOR_RAW;
1513   else iformat |= FOR_LDR;
1514   if(dt_image_is_hdr(image)) iformat |= FOR_HDR;
1515 
1516   int excluded = 0;
1517   if(dt_image_monochrome_flags(image)) excluded |= FOR_NOT_MONO;
1518   else excluded |= FOR_NOT_COLOR;
1519 
1520   DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), query, -1, &stmt, NULL);
1521   DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
1522   DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, image->exif_model, -1, SQLITE_TRANSIENT);
1523   DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 3, image->exif_maker, -1, SQLITE_TRANSIENT);
1524   DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 4, image->camera_alias, -1, SQLITE_TRANSIENT);
1525   DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 5, image->camera_maker, -1, SQLITE_TRANSIENT);
1526   DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 6, image->exif_lens, -1, SQLITE_TRANSIENT);
1527   DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 7, fmaxf(0.0f, fminf(FLT_MAX, image->exif_iso)));
1528   DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 8, fmaxf(0.0f, fminf(1000000, image->exif_exposure)));
1529   DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 9, fmaxf(0.0f, fminf(1000000, image->exif_aperture)));
1530   DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 10, fmaxf(0.0f, fminf(1000000, image->exif_focal_length)));
1531   // 0: dontcare, 1: ldr, 2: raw plus monochrome & color
1532   DT_DEBUG_SQLITE3_BIND_INT(stmt, 11, iformat);
1533   DT_DEBUG_SQLITE3_BIND_INT(stmt, 12, excluded);
1534   DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 13, workflow_preset, -1, SQLITE_TRANSIENT);
1535   sqlite3_step(stmt);
1536   sqlite3_finalize(stmt);
1537 
1538   // now we want to auto-apply the iop-order list if one corresponds and none are
1539   // still applied. Note that we can already have an iop-order list set when
1540   // copying an history or applying a style to a not yet developed image.
1541 
1542   if(!dt_ioppr_has_iop_order_list(imgid))
1543   {
1544     DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
1545                                 "SELECT op_params"
1546                                 " FROM data.presets"
1547                                 " WHERE autoapply=1"
1548                                 "       AND ((?2 LIKE model AND ?3 LIKE maker) OR (?4 LIKE model AND ?5 LIKE maker))"
1549                                 "       AND ?6 LIKE lens AND ?7 BETWEEN iso_min AND iso_max"
1550                                 "       AND ?8 BETWEEN exposure_min AND exposure_max"
1551                                 "       AND ?9 BETWEEN aperture_min AND aperture_max"
1552                                 "       AND ?10 BETWEEN focal_length_min AND focal_length_max"
1553                                 "       AND (format = 0 OR (format&?11 != 0 AND ~format&?12 != 0))"
1554                                 "       AND operation = 'ioporder'"
1555                                 " ORDER BY writeprotect DESC, LENGTH(model), LENGTH(maker), LENGTH(lens)",
1556                                 -1, &stmt, NULL);
1557     DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
1558     DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, image->exif_model, -1, SQLITE_TRANSIENT);
1559     DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 3, image->exif_maker, -1, SQLITE_TRANSIENT);
1560     DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 4, image->camera_alias, -1, SQLITE_TRANSIENT);
1561     DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 5, image->camera_maker, -1, SQLITE_TRANSIENT);
1562     DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 6, image->exif_lens, -1, SQLITE_TRANSIENT);
1563     DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 7, fmaxf(0.0f, fminf(FLT_MAX, image->exif_iso)));
1564     DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 8, fmaxf(0.0f, fminf(1000000, image->exif_exposure)));
1565     DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 9, fmaxf(0.0f, fminf(1000000, image->exif_aperture)));
1566     DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 10, fmaxf(0.0f, fminf(1000000, image->exif_focal_length)));
1567     // 0: dontcare, 1: ldr, 2: raw plus monochrome & color
1568     DT_DEBUG_SQLITE3_BIND_INT(stmt, 11, iformat);
1569     DT_DEBUG_SQLITE3_BIND_INT(stmt, 12, excluded);
1570     if(sqlite3_step(stmt) == SQLITE_ROW)
1571     {
1572       const char *params = (char *)sqlite3_column_blob(stmt, 0);
1573       const int32_t params_len = sqlite3_column_bytes(stmt, 0);
1574       GList *iop_list = dt_ioppr_deserialize_iop_order_list(params, params_len);
1575       dt_ioppr_write_iop_order_list(iop_list, imgid);
1576       g_list_free_full(iop_list, free);
1577       dt_ioppr_set_default_iop_order(dev, imgid);
1578     }
1579     else
1580     {
1581       // we have no auto-apply order, so apply iop order, depending of the workflow
1582       GList *iop_list;
1583       if(is_scene_referred || is_workflow_none)
1584         iop_list = dt_ioppr_get_iop_order_list_version(DT_IOP_ORDER_V30);
1585       else
1586         iop_list = dt_ioppr_get_iop_order_list_version(DT_IOP_ORDER_LEGACY);
1587       dt_ioppr_write_iop_order_list(iop_list, imgid);
1588       g_list_free_full(iop_list, free);
1589       dt_ioppr_set_default_iop_order(dev, imgid);
1590     }
1591     sqlite3_finalize(stmt);
1592   }
1593 
1594   image->flags |= DT_IMAGE_AUTO_PRESETS_APPLIED | DT_IMAGE_NO_LEGACY_PRESETS;
1595 
1596   // make sure these end up in the image_cache; as the history is not correct right now
1597   // we don't write the sidecar here but later in dt_dev_read_history_ext
1598   dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_RELAXED);
1599 
1600   return TRUE;
1601 }
1602 
_dev_add_default_modules(dt_develop_t * dev,const int imgid)1603 static void _dev_add_default_modules(dt_develop_t *dev, const int imgid)
1604 {
1605   //start with those modules that cannot be disabled
1606   for(GList *modules = dev->iop; modules; modules = g_list_next(modules))
1607   {
1608     dt_iop_module_t *module = (dt_iop_module_t *)modules->data;
1609 
1610     if(!dt_history_check_module_exists(imgid, module->op)
1611        && module->default_enabled
1612        && module->hide_enable_button
1613        && !(module->flags() & IOP_FLAGS_NO_HISTORY_STACK))
1614     {
1615       _dev_insert_module(dev, module, imgid);
1616     }
1617   }
1618   //now modules that can be disabled but are auto-on
1619   for(GList *modules = dev->iop; modules; modules = g_list_next(modules))
1620   {
1621     dt_iop_module_t *module = (dt_iop_module_t *)modules->data;
1622 
1623     if(!dt_history_check_module_exists(imgid, module->op)
1624        && module->default_enabled
1625        && !module->hide_enable_button
1626        && !(module->flags() & IOP_FLAGS_NO_HISTORY_STACK))
1627     {
1628       _dev_insert_module(dev, module, imgid);
1629     }
1630   }
1631 }
1632 
_dev_merge_history(dt_develop_t * dev,const int imgid)1633 static void _dev_merge_history(dt_develop_t *dev, const int imgid)
1634 {
1635   sqlite3_stmt *stmt;
1636 
1637   // count what we found:
1638   DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
1639                               "SELECT COUNT(*) FROM memory.history", -1,
1640                               &stmt, NULL);
1641   if(sqlite3_step(stmt) == SQLITE_ROW)
1642   {
1643     // if there is anything..
1644     const int cnt = sqlite3_column_int(stmt, 0);
1645     sqlite3_finalize(stmt);
1646 
1647     // workaround a sqlite3 "feature". The above statement to insert
1648     // items into memory.history is complex and in this case sqlite
1649     // does not give rowid a linear increment. But the following code
1650     // really expect that the rowid in this table starts from 0 and
1651     // increment one by one. So in the following code we rewrite the
1652     // "num" values from 0 to cnt-1.
1653 
1654     if(cnt > 0)
1655     {
1656       // get all rowids
1657       GList *rowids = NULL;
1658 
1659       // get the rowids in descending order since building the list will reverse the order
1660       DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
1661                                   "SELECT rowid FROM memory.history ORDER BY rowid DESC",
1662                                   -1, &stmt, NULL);
1663       while(sqlite3_step(stmt) == SQLITE_ROW)
1664         rowids = g_list_prepend(rowids, GINT_TO_POINTER(sqlite3_column_int(stmt, 0)));
1665       sqlite3_finalize(stmt);
1666 
1667       // update num accordingly
1668       int v = 0;
1669 
1670       DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
1671                                   "UPDATE memory.history SET num=?1 WHERE rowid=?2",
1672                                   -1, &stmt, NULL);
1673 
1674       // let's wrap this into a transaction, it might make it a little faster.
1675       sqlite3_exec(dt_database_get(darktable.db), "BEGIN TRANSACTION", NULL, NULL, NULL);
1676       for(GList *r = rowids; r; r = g_list_next(r))
1677       {
1678         DT_DEBUG_SQLITE3_CLEAR_BINDINGS(stmt);
1679         DT_DEBUG_SQLITE3_RESET(stmt);
1680         DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, v);
1681         DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, GPOINTER_TO_INT(r->data));
1682 
1683         if(sqlite3_step(stmt) != SQLITE_DONE) break;
1684 
1685         v++;
1686       }
1687 
1688       sqlite3_exec(dt_database_get(darktable.db), "COMMIT", NULL, NULL, NULL);
1689 
1690       g_list_free(rowids);
1691 
1692       // advance the current history by cnt amount, that is, make space
1693       // for the preset/default iops that will be *prepended* into the
1694       // history.
1695       DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
1696                                   "UPDATE main.history SET num=num+?1 WHERE imgid=?2",
1697                                   -1, &stmt, NULL);
1698       DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, cnt);
1699       DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);
1700 
1701       if(sqlite3_step(stmt) == SQLITE_DONE)
1702       {
1703         sqlite3_finalize(stmt);
1704         DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
1705                                     "UPDATE main.images"
1706                                     " SET history_end=history_end+?1"
1707                                     " WHERE id=?2",
1708                                     -1, &stmt, NULL);
1709         DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, cnt);
1710         DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);
1711 
1712         if(sqlite3_step(stmt) == SQLITE_DONE)
1713         {
1714           // and finally prepend the rest with increasing numbers (starting at 0)
1715           sqlite3_finalize(stmt);
1716           DT_DEBUG_SQLITE3_PREPARE_V2(
1717             dt_database_get(darktable.db),
1718             "INSERT INTO main.history"
1719             " SELECT imgid, num, module, operation, op_params, enabled, "
1720             "        blendop_params, blendop_version, multi_priority,"
1721             "        multi_name"
1722             " FROM memory.history",
1723             -1, &stmt, NULL);
1724           sqlite3_step(stmt);
1725           sqlite3_finalize(stmt);
1726         }
1727       }
1728     }
1729   }
1730 }
1731 
_dev_write_history(dt_develop_t * dev,const int imgid)1732 void _dev_write_history(dt_develop_t *dev, const int imgid)
1733 {
1734   _cleanup_history(imgid);
1735   // write history entries
1736   GList *history = dev->history;
1737   for(int i = 0; history; i++)
1738   {
1739     dt_dev_history_item_t *hist = (dt_dev_history_item_t *)(history->data);
1740     (void)dt_dev_write_history_item(imgid, hist, i);
1741     history = g_list_next(history);
1742   }
1743 }
1744 
1745 // helper function for debug strings
_print_validity(gboolean state)1746 char * _print_validity(gboolean state)
1747 {
1748   if(state)
1749     return "ok";
1750   else
1751     return "WRONG";
1752 }
1753 
dt_dev_read_history_ext(dt_develop_t * dev,const int imgid,gboolean no_image)1754 void dt_dev_read_history_ext(dt_develop_t *dev, const int imgid, gboolean no_image)
1755 {
1756   if(imgid <= 0) return;
1757   if(!dev->iop) return;
1758 
1759   dt_lock_image(imgid);
1760 
1761   dt_dev_undo_start_record(dev);
1762 
1763   int auto_apply_modules = 0;
1764   gboolean first_run = FALSE;
1765   gboolean legacy_params = FALSE;
1766 
1767   dt_ioppr_set_default_iop_order(dev, imgid);
1768 
1769   if(!no_image)
1770   {
1771     // cleanup
1772     DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "DELETE FROM memory.history", NULL, NULL, NULL);
1773 
1774     dt_print(DT_DEBUG_PARAMS, "[history] temporary history deleted\n");
1775 
1776     // make sure all modules default params are loaded to init history
1777     _dt_dev_load_pipeline_defaults(dev);
1778 
1779     // prepend all default modules to memory.history
1780     _dev_add_default_modules(dev, imgid);
1781     const int default_modules = _dev_get_module_nb_records();
1782 
1783     // maybe add auto-presets to memory.history
1784     first_run = _dev_auto_apply_presets(dev);
1785     auto_apply_modules = _dev_get_module_nb_records() - default_modules;
1786 
1787     dt_print(DT_DEBUG_PARAMS, "[history] temporary history initialised with default params and presets\n");
1788 
1789     // now merge memory.history into main.history
1790     _dev_merge_history(dev, imgid);
1791 
1792     dt_print(DT_DEBUG_PARAMS, "[history] temporary history merged with image history\n");
1793 
1794     //  first time we are loading the image, try to import lightroom .xmp if any
1795     if(dev->image_loading && first_run) dt_lightroom_import(dev->image_storage.id, dev, TRUE);
1796   }
1797 
1798   sqlite3_stmt *stmt;
1799 
1800   // Get the end of the history - What's that ???
1801 
1802   int history_end_current = 0;
1803 
1804   DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
1805                               "SELECT history_end FROM main.images WHERE id = ?1",
1806                               -1, &stmt, NULL);
1807   DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
1808   if(sqlite3_step(stmt) == SQLITE_ROW) // seriously, this should never fail
1809     if(sqlite3_column_type(stmt, 0) != SQLITE_NULL)
1810       history_end_current = sqlite3_column_int(stmt, 0);
1811   sqlite3_finalize(stmt);
1812 
1813   // Load current image history from DB
1814   DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
1815                               "SELECT imgid, num, module, operation,"
1816                               "       op_params, enabled, blendop_params,"
1817                               "       blendop_version, multi_priority, multi_name"
1818                               " FROM main.history"
1819                               " WHERE imgid = ?1"
1820                               " ORDER BY num",
1821                               -1, &stmt, NULL);
1822   DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
1823 
1824   dev->history_end = 0;
1825 
1826   // Strip rows from DB lookup. One row == One module in history
1827   while(sqlite3_step(stmt) == SQLITE_ROW)
1828   {
1829     // Unpack the DB blobs
1830     const int id = sqlite3_column_int(stmt, 0);
1831     const int num = sqlite3_column_int(stmt, 1);
1832     const int modversion = sqlite3_column_int(stmt, 2);
1833     const char *module_name = (const char *)sqlite3_column_text(stmt, 3);
1834     const void *module_params = sqlite3_column_blob(stmt, 4);
1835     const int enabled = sqlite3_column_int(stmt, 5);
1836     const void *blendop_params = sqlite3_column_blob(stmt, 6);
1837     const int blendop_version = sqlite3_column_int(stmt, 7);
1838     const int multi_priority = sqlite3_column_int(stmt, 8);
1839     const char *multi_name = (const char *)sqlite3_column_text(stmt, 9);
1840 
1841     const int param_length = sqlite3_column_bytes(stmt, 4);
1842     const int bl_length = sqlite3_column_bytes(stmt, 6);
1843 
1844     // Sanity checks
1845     const gboolean is_valid_id = (id == imgid);
1846     const gboolean has_module_name = (module_name != NULL);
1847 
1848     if(!(has_module_name && is_valid_id))
1849     {
1850       fprintf(stderr, "[dev_read_history] database history for image `%s' seems to be corrupted!\n",
1851               dev->image_storage.filename);
1852       continue;
1853     }
1854 
1855     const int iop_order = dt_ioppr_get_iop_order(dev->iop_order_list, module_name, multi_priority);
1856 
1857     dt_dev_history_item_t *hist = (dt_dev_history_item_t *)calloc(1, sizeof(dt_dev_history_item_t));
1858     hist->module = NULL;
1859 
1860     // Find a .so file that matches our history entry, aka a module to run the params stored in DB
1861     dt_iop_module_t *find_op = NULL;
1862     for(GList *modules = dev->iop; modules; modules = g_list_next(modules))
1863     {
1864       dt_iop_module_t *module = (dt_iop_module_t *)modules->data;
1865       if(!strcmp(module->op, module_name))
1866       {
1867         if(module->multi_priority == multi_priority)
1868         {
1869           hist->module = module;
1870           if(multi_name)
1871             g_strlcpy(module->multi_name, multi_name, sizeof(module->multi_name));
1872           else
1873             memset(module->multi_name, 0, sizeof(module->multi_name));
1874           break;
1875         }
1876         else if(multi_priority > 0)
1877         {
1878           // we just say that we find the name, so we just have to add new instance of this module
1879           find_op = module;
1880         }
1881       }
1882     }
1883     if(!hist->module && find_op)
1884     {
1885       // we have to add a new instance of this module and set index to modindex
1886       dt_iop_module_t *new_module = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
1887       if(!dt_iop_load_module(new_module, find_op->so, dev))
1888       {
1889         dt_iop_update_multi_priority(new_module, multi_priority);
1890         new_module->iop_order = iop_order;
1891 
1892         g_strlcpy(new_module->multi_name, multi_name, sizeof(new_module->multi_name));
1893 
1894         dev->iop = g_list_append(dev->iop, new_module);
1895 
1896         new_module->instance = find_op->instance;
1897         hist->module = new_module;
1898       }
1899     }
1900 
1901     if(!hist->module)
1902     {
1903       fprintf(
1904           stderr,
1905           "[dev_read_history] the module `%s' requested by image `%s' is not installed on this computer!\n",
1906           module_name, dev->image_storage.filename);
1907       free(hist);
1908       continue;
1909     }
1910 
1911     // module has no user params and won't bother us in GUI - exit early, we are done
1912     if(hist->module->flags() & IOP_FLAGS_NO_HISTORY_STACK)
1913     {
1914       free(hist);
1915       continue;
1916     }
1917 
1918     // Run a battery of tests
1919     const gboolean is_valid_module_name = (strcmp(module_name, hist->module->op) == 0);
1920     const gboolean is_valid_blendop_version = (blendop_version == dt_develop_blend_version());
1921     const gboolean is_valid_blendop_size = (bl_length == sizeof(dt_develop_blend_params_t));
1922     const gboolean is_valid_module_version = (modversion == hist->module->version());
1923     const gboolean is_valid_params_size = (param_length == hist->module->params_size);
1924 
1925     dt_print(DT_DEBUG_PARAMS, "[history] successfully loaded module %s from history\n"
1926                               "\t\t\tblendop v. %i:\tversion %s\tparams %s\n"
1927                               "\t\t\tparams v. %i:\tversion %s\tparams %s\n",
1928                               module_name,
1929                               blendop_version, _print_validity(is_valid_blendop_version), _print_validity(is_valid_blendop_size),
1930                               modversion, _print_validity(is_valid_module_version), _print_validity(is_valid_params_size));
1931 
1932     // Init buffers and values
1933     hist->enabled = enabled;
1934     hist->num = num;
1935     hist->iop_order = iop_order;
1936     hist->multi_priority = multi_priority;
1937     g_strlcpy(hist->op_name, hist->module->op, sizeof(hist->op_name));
1938     g_strlcpy(hist->multi_name, multi_name, sizeof(hist->multi_name));
1939     hist->params = malloc(hist->module->params_size);
1940     hist->blend_params = malloc(sizeof(dt_develop_blend_params_t));
1941 
1942     // update module iop_order only on active history entries
1943     if(history_end_current > dev->history_end) hist->module->iop_order = hist->iop_order;
1944 
1945     // Copy blending params if valid, else try to convert legacy params
1946     if(blendop_params && is_valid_blendop_version && is_valid_blendop_size)
1947     {
1948       memcpy(hist->blend_params, blendop_params, sizeof(dt_develop_blend_params_t));
1949     }
1950     else if(blendop_params
1951             && dt_develop_blend_legacy_params(hist->module, blendop_params, blendop_version,
1952                                               hist->blend_params, dt_develop_blend_version(), bl_length) == 0)
1953     {
1954       legacy_params = TRUE;
1955     }
1956     else
1957     {
1958       memcpy(hist->blend_params, hist->module->default_blendop_params, sizeof(dt_develop_blend_params_t));
1959     }
1960 
1961     // Copy module params if valid, else try to convert legacy params
1962     if(is_valid_module_version && is_valid_params_size && is_valid_module_name)
1963     {
1964       memcpy(hist->params, module_params, hist->module->params_size);
1965     }
1966     else
1967     {
1968       if(!hist->module->legacy_params
1969          || hist->module->legacy_params(hist->module, module_params, labs(modversion),
1970                                         hist->params, labs(hist->module->version())))
1971       {
1972         fprintf(stderr, "[dev_read_history] module `%s' version mismatch: history is %d, dt %d.\n",
1973                 hist->module->op, modversion, hist->module->version());
1974 
1975         const char *fname = dev->image_storage.filename + strlen(dev->image_storage.filename);
1976         while(fname > dev->image_storage.filename && *fname != '/') fname--;
1977 
1978         if(fname > dev->image_storage.filename) fname++;
1979         dt_control_log(_("%s: module `%s' version mismatch: %d != %d"), fname, hist->module->op,
1980                        hist->module->version(), modversion);
1981         dt_dev_free_history_item(hist);
1982         continue;
1983       }
1984       else
1985       {
1986         if(!strcmp(hist->module->op, "spots") && modversion == 1)
1987         {
1988           // quick and dirty hack to handle spot removal legacy_params
1989           memcpy(hist->blend_params, hist->module->blend_params, sizeof(dt_develop_blend_params_t));
1990         }
1991         legacy_params = TRUE;
1992       }
1993 
1994       /*
1995        * Fix for flip iop: previously it was not always needed, but it might be
1996        * in history stack as "orientation (off)", but now we always want it
1997        * by default, so if it is disabled, enable it, and replace params with
1998        * default_params. if user want to, he can disable it.
1999        */
2000       if(!strcmp(hist->module->op, "flip") && hist->enabled == 0 && labs(modversion) == 1)
2001       {
2002         memcpy(hist->params, hist->module->default_params, hist->module->params_size);
2003         hist->enabled = 1;
2004       }
2005     }
2006 
2007     // make sure that always-on modules are always on. duh.
2008     if(hist->module->default_enabled == 1 && hist->module->hide_enable_button == 1)
2009       hist->enabled = 1;
2010 
2011     dev->history = g_list_append(dev->history, hist);
2012     dev->history_end++;
2013   }
2014   sqlite3_finalize(stmt);
2015 
2016   dt_ioppr_resync_modules_order(dev);
2017 
2018   // find the new history end
2019   DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
2020                               "SELECT history_end FROM main.images WHERE id = ?1",
2021                               -1, &stmt, NULL);
2022   DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
2023   if(sqlite3_step(stmt) == SQLITE_ROW) // seriously, this should never fail
2024     if(sqlite3_column_type(stmt, 0) != SQLITE_NULL)
2025       dev->history_end = sqlite3_column_int(stmt, 0);
2026   sqlite3_finalize(stmt);
2027 
2028   dt_ioppr_check_iop_order(dev, imgid, "dt_dev_read_history_no_image end");
2029 
2030   dt_masks_read_masks_history(dev, imgid);
2031 
2032   // FIXME : this probably needs to capture dev thread lock
2033   if(dev->gui_attached && !no_image)
2034   {
2035     dev->pipe->changed |= DT_DEV_PIPE_SYNCH;
2036     dev->preview_pipe->changed |= DT_DEV_PIPE_SYNCH; // again, fixed topology for now.
2037     dev->preview2_pipe->changed |= DT_DEV_PIPE_SYNCH; // again, fixed topology for now.
2038     dt_dev_invalidate_all(dev);
2039 
2040     /* signal history changed */
2041     dt_dev_undo_end_record(dev);
2042   }
2043   dt_dev_masks_list_change(dev);
2044 
2045   // make sure module_dev is in sync with history
2046   _dev_write_history(dev, imgid);
2047   dt_ioppr_write_iop_order_list(dev->iop_order_list, imgid);
2048   dt_history_hash_t flags = DT_HISTORY_HASH_CURRENT;
2049   if(first_run)
2050   {
2051     const dt_history_hash_t hash_status = dt_history_hash_get_status(imgid);
2052     // if altered doesn't mask it
2053     if(!(hash_status & DT_HISTORY_HASH_CURRENT))
2054     {
2055       flags = flags | (auto_apply_modules ? DT_HISTORY_HASH_AUTO : DT_HISTORY_HASH_BASIC);
2056     }
2057     dt_history_hash_write_from_history(imgid, flags);
2058     // As we have a proper history right now and this is first_run we write the xmp now
2059     dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'w');
2060     dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_SAFE);
2061   }
2062   else if(legacy_params)
2063   {
2064     const dt_history_hash_t hash_status = dt_history_hash_get_status(imgid);
2065     if(hash_status & (DT_HISTORY_HASH_BASIC | DT_HISTORY_HASH_AUTO))
2066     {
2067       // if image not altered keep the current status
2068       flags = flags | hash_status;
2069     }
2070     dt_history_hash_write_from_history(imgid, flags);
2071   }
2072   else
2073   {
2074     dt_history_hash_write_from_history(imgid, flags);
2075   }
2076 
2077   dt_unlock_image(imgid);
2078 }
2079 
dt_dev_read_history(dt_develop_t * dev)2080 void dt_dev_read_history(dt_develop_t *dev)
2081 {
2082   dt_dev_read_history_ext(dev, dev->image_storage.id, FALSE);
2083 }
2084 
dt_dev_reprocess_all(dt_develop_t * dev)2085 void dt_dev_reprocess_all(dt_develop_t *dev)
2086 {
2087   if(darktable.gui->reset) return;
2088   if(dev && dev->gui_attached)
2089   {
2090     dev->pipe->changed |= DT_DEV_PIPE_SYNCH;
2091     dev->preview_pipe->changed |= DT_DEV_PIPE_SYNCH;
2092     dev->preview2_pipe->changed |= DT_DEV_PIPE_SYNCH;
2093     dev->pipe->cache_obsolete = 1;
2094     dev->preview_pipe->cache_obsolete = 1;
2095     dev->preview2_pipe->cache_obsolete = 1;
2096 
2097     // invalidate buffers and force redraw of darkroom
2098     dt_dev_invalidate_all(dev);
2099 
2100     /* redraw */
2101     dt_control_queue_redraw_center();
2102   }
2103 }
2104 
dt_dev_reprocess_center(dt_develop_t * dev)2105 void dt_dev_reprocess_center(dt_develop_t *dev)
2106 {
2107   if(darktable.gui->reset) return;
2108   if(dev && dev->gui_attached)
2109   {
2110     dev->pipe->changed |= DT_DEV_PIPE_SYNCH;
2111     dev->pipe->cache_obsolete = 1;
2112 
2113     // invalidate buffers and force redraw of darkroom
2114     dt_dev_invalidate_all(dev);
2115 
2116     /* redraw */
2117     dt_control_queue_redraw_center();
2118   }
2119 }
2120 
dt_dev_reprocess_preview(dt_develop_t * dev)2121 void dt_dev_reprocess_preview(dt_develop_t *dev)
2122 {
2123   if(darktable.gui->reset || !dev || !dev->gui_attached) return;
2124 
2125   dev->preview_pipe->changed |= DT_DEV_PIPE_SYNCH;
2126   dev->preview_pipe->cache_obsolete = 1;
2127 
2128   dt_dev_invalidate_preview(dev);
2129   dt_control_queue_redraw_center();
2130 }
2131 
dt_dev_check_zoom_bounds(dt_develop_t * dev,float * zoom_x,float * zoom_y,dt_dev_zoom_t zoom,int closeup,float * boxww,float * boxhh)2132 void dt_dev_check_zoom_bounds(dt_develop_t *dev, float *zoom_x, float *zoom_y, dt_dev_zoom_t zoom,
2133                               int closeup, float *boxww, float *boxhh)
2134 {
2135   int procw = 0, proch = 0;
2136   dt_dev_get_processed_size(dev, &procw, &proch);
2137   float boxw = 1.0f, boxh = 1.0f; // viewport in normalised space
2138                             //   if(zoom == DT_ZOOM_1)
2139                             //   {
2140                             //     const float imgw = (closeup ? 2 : 1)*procw;
2141                             //     const float imgh = (closeup ? 2 : 1)*proch;
2142                             //     const float devw = MIN(imgw, dev->width);
2143                             //     const float devh = MIN(imgh, dev->height);
2144                             //     boxw = fminf(1.0, devw/imgw);
2145                             //     boxh = fminf(1.0, devh/imgh);
2146                             //   }
2147   if(zoom == DT_ZOOM_FIT)
2148   {
2149     *zoom_x = *zoom_y = 0.0f;
2150     boxw = boxh = 1.0f;
2151   }
2152   else
2153   {
2154     const float scale = dt_dev_get_zoom_scale(dev, zoom, 1<<closeup, 0);
2155     const float imgw = procw;
2156     const float imgh = proch;
2157     const float devw = dev->width;
2158     const float devh = dev->height;
2159     boxw = devw / (imgw * scale);
2160     boxh = devh / (imgh * scale);
2161   }
2162 
2163   if(*zoom_x < boxw / 2 - .5) *zoom_x = boxw / 2 - .5;
2164   if(*zoom_x > .5 - boxw / 2) *zoom_x = .5 - boxw / 2;
2165   if(*zoom_y < boxh / 2 - .5) *zoom_y = boxh / 2 - .5;
2166   if(*zoom_y > .5 - boxh / 2) *zoom_y = .5 - boxh / 2;
2167   if(boxw > 1.0) *zoom_x = 0.0f;
2168   if(boxh > 1.0) *zoom_y = 0.0f;
2169 
2170   if(boxww) *boxww = boxw;
2171   if(boxhh) *boxhh = boxh;
2172 }
2173 
dt_dev_get_processed_size(const dt_develop_t * dev,int * procw,int * proch)2174 void dt_dev_get_processed_size(const dt_develop_t *dev, int *procw, int *proch)
2175 {
2176   if(!dev) return;
2177 
2178   // if pipe is processed, lets return its size
2179   if(dev->pipe && dev->pipe->processed_width)
2180   {
2181     *procw = dev->pipe->processed_width;
2182     *proch = dev->pipe->processed_height;
2183     return;
2184   }
2185 
2186   // fallback on preview pipe
2187   if(dev->preview_pipe && dev->preview_pipe->processed_width)
2188   {
2189     const float scale = (dev->preview_pipe->iscale / dev->preview_downsampling);
2190     *procw = scale * dev->preview_pipe->processed_width;
2191     *proch = scale * dev->preview_pipe->processed_height;
2192     return;
2193   }
2194 
2195   // no processed pipes, lets return 0 size
2196   *procw = *proch = 0;
2197   return;
2198 }
2199 
dt_dev_get_pointer_zoom_pos(dt_develop_t * dev,const float px,const float py,float * zoom_x,float * zoom_y)2200 void dt_dev_get_pointer_zoom_pos(dt_develop_t *dev, const float px, const float py, float *zoom_x,
2201                                  float *zoom_y)
2202 {
2203   dt_dev_zoom_t zoom;
2204   int closeup = 0, procw = 0, proch = 0;
2205   float zoom2_x = 0.0f, zoom2_y = 0.0f;
2206   zoom = dt_control_get_dev_zoom();
2207   closeup = dt_control_get_dev_closeup();
2208   zoom2_x = dt_control_get_dev_zoom_x();
2209   zoom2_y = dt_control_get_dev_zoom_y();
2210   dt_dev_get_processed_size(dev, &procw, &proch);
2211   const float scale = dt_dev_get_zoom_scale(dev, zoom, 1<<closeup, 0);
2212   // offset from center now (current zoom_{x,y} points there)
2213   const float mouse_off_x = px - .5 * dev->width, mouse_off_y = py - .5 * dev->height;
2214   zoom2_x += mouse_off_x / (procw * scale);
2215   zoom2_y += mouse_off_y / (proch * scale);
2216   *zoom_x = zoom2_x;
2217   *zoom_y = zoom2_y;
2218 }
2219 
dt_dev_get_history_item_label(dt_dev_history_item_t * hist,char * label,const int cnt)2220 void dt_dev_get_history_item_label(dt_dev_history_item_t *hist, char *label, const int cnt)
2221 {
2222   gchar *module_label = dt_history_item_get_name(hist->module);
2223   g_snprintf(label, cnt, "%s (%s)", module_label, hist->enabled ? _("on") : _("off"));
2224   g_free(module_label);
2225 }
2226 
dt_dev_is_current_image(dt_develop_t * dev,uint32_t imgid)2227 int dt_dev_is_current_image(dt_develop_t *dev, uint32_t imgid)
2228 {
2229   return (dev->image_storage.id == imgid) ? 1 : 0;
2230 }
2231 
find_last_exposure_instance(dt_develop_t * dev)2232 static dt_dev_proxy_exposure_t *find_last_exposure_instance(dt_develop_t *dev)
2233 {
2234   if(!dev->proxy.exposure.module) return NULL;
2235 
2236   dt_dev_proxy_exposure_t *instance = &dev->proxy.exposure;
2237 
2238   return instance;
2239 };
2240 
dt_dev_exposure_hooks_available(dt_develop_t * dev)2241 gboolean dt_dev_exposure_hooks_available(dt_develop_t *dev)
2242 {
2243   dt_dev_proxy_exposure_t *instance = find_last_exposure_instance(dev);
2244 
2245   /* check if exposure iop module has registered its hooks */
2246   if(instance && instance->module && instance->set_black && instance->get_black && instance->set_exposure
2247      && instance->get_exposure)
2248     return TRUE;
2249 
2250   return FALSE;
2251 }
2252 
dt_dev_exposure_reset_defaults(dt_develop_t * dev)2253 void dt_dev_exposure_reset_defaults(dt_develop_t *dev)
2254 {
2255   dt_dev_proxy_exposure_t *instance = find_last_exposure_instance(dev);
2256 
2257   if(!(instance && instance->module)) return;
2258 
2259   dt_iop_module_t *exposure = instance->module;
2260   memcpy(exposure->params, exposure->default_params, exposure->params_size);
2261   exposure->gui_update(exposure);
2262   dt_dev_add_history_item(exposure->dev, exposure, TRUE);
2263 }
2264 
dt_dev_exposure_set_exposure(dt_develop_t * dev,const float exposure)2265 void dt_dev_exposure_set_exposure(dt_develop_t *dev, const float exposure)
2266 {
2267   dt_dev_proxy_exposure_t *instance = find_last_exposure_instance(dev);
2268 
2269   if(instance && instance->module && instance->set_exposure) instance->set_exposure(instance->module, exposure);
2270 }
2271 
dt_dev_exposure_get_exposure(dt_develop_t * dev)2272 float dt_dev_exposure_get_exposure(dt_develop_t *dev)
2273 {
2274   dt_dev_proxy_exposure_t *instance = find_last_exposure_instance(dev);
2275 
2276   if(instance && instance->module && instance->get_exposure) return instance->get_exposure(instance->module);
2277 
2278   return 0.0;
2279 }
2280 
dt_dev_exposure_set_black(dt_develop_t * dev,const float black)2281 void dt_dev_exposure_set_black(dt_develop_t *dev, const float black)
2282 {
2283   dt_dev_proxy_exposure_t *instance = find_last_exposure_instance(dev);
2284 
2285   if(instance && instance->module && instance->set_black) instance->set_black(instance->module, black);
2286 }
2287 
dt_dev_exposure_get_black(dt_develop_t * dev)2288 float dt_dev_exposure_get_black(dt_develop_t *dev)
2289 {
2290   dt_dev_proxy_exposure_t *instance = find_last_exposure_instance(dev);
2291 
2292   if(instance && instance->module && instance->get_black) return instance->get_black(instance->module);
2293 
2294   return 0.0;
2295 }
2296 
dt_dev_modulegroups_set(dt_develop_t * dev,uint32_t group)2297 void dt_dev_modulegroups_set(dt_develop_t *dev, uint32_t group)
2298 {
2299   if(dev->proxy.modulegroups.module && dev->proxy.modulegroups.set && dev->first_load == FALSE)
2300     dev->proxy.modulegroups.set(dev->proxy.modulegroups.module, group);
2301 }
2302 
dt_dev_modulegroups_get_activated(dt_develop_t * dev)2303 uint32_t dt_dev_modulegroups_get_activated(dt_develop_t *dev)
2304 {
2305   if(dev->proxy.modulegroups.module && dev->proxy.modulegroups.get_activated)
2306     return dev->proxy.modulegroups.get_activated(dev->proxy.modulegroups.module);
2307 
2308   return 0;
2309 }
2310 
dt_dev_modulegroups_get(dt_develop_t * dev)2311 uint32_t dt_dev_modulegroups_get(dt_develop_t *dev)
2312 {
2313   if(dev->proxy.modulegroups.module && dev->proxy.modulegroups.get)
2314     return dev->proxy.modulegroups.get(dev->proxy.modulegroups.module);
2315 
2316   return 0;
2317 }
2318 
dt_dev_modulegroups_test(dt_develop_t * dev,uint32_t group,dt_iop_module_t * module)2319 gboolean dt_dev_modulegroups_test(dt_develop_t *dev, uint32_t group, dt_iop_module_t *module)
2320 {
2321   if(dev->proxy.modulegroups.module && dev->proxy.modulegroups.test)
2322     return dev->proxy.modulegroups.test(dev->proxy.modulegroups.module, group, module);
2323   return FALSE;
2324 }
2325 
dt_dev_modulegroups_switch(dt_develop_t * dev,dt_iop_module_t * module)2326 void dt_dev_modulegroups_switch(dt_develop_t *dev, dt_iop_module_t *module)
2327 {
2328   if(dev->proxy.modulegroups.module && dev->proxy.modulegroups.switch_group && dev->first_load == FALSE)
2329     dev->proxy.modulegroups.switch_group(dev->proxy.modulegroups.module, module);
2330 }
2331 
dt_dev_modulegroups_update_visibility(dt_develop_t * dev)2332 void dt_dev_modulegroups_update_visibility(dt_develop_t *dev)
2333 {
2334   if(dev->proxy.modulegroups.module && dev->proxy.modulegroups.switch_group && dev->first_load == FALSE)
2335     dev->proxy.modulegroups.update_visibility(dev->proxy.modulegroups.module);
2336 }
2337 
dt_dev_modulegroups_search_text_focus(dt_develop_t * dev)2338 void dt_dev_modulegroups_search_text_focus(dt_develop_t *dev)
2339 {
2340   if(dev->proxy.modulegroups.module && dev->proxy.modulegroups.search_text_focus && dev->first_load == 0)
2341     dev->proxy.modulegroups.search_text_focus(dev->proxy.modulegroups.module);
2342 }
2343 
dt_dev_modulegroups_is_visible(dt_develop_t * dev,gchar * module)2344 gboolean dt_dev_modulegroups_is_visible(dt_develop_t *dev, gchar *module)
2345 {
2346   if(dev->proxy.modulegroups.module && dev->proxy.modulegroups.test_visible)
2347     return dev->proxy.modulegroups.test_visible(dev->proxy.modulegroups.module, module);
2348   return FALSE;
2349 }
2350 
dt_dev_masks_list_change(dt_develop_t * dev)2351 void dt_dev_masks_list_change(dt_develop_t *dev)
2352 {
2353   if(dev->proxy.masks.module && dev->proxy.masks.list_change)
2354     dev->proxy.masks.list_change(dev->proxy.masks.module);
2355 }
dt_dev_masks_list_update(dt_develop_t * dev)2356 void dt_dev_masks_list_update(dt_develop_t *dev)
2357 {
2358   if(dev->proxy.masks.module && dev->proxy.masks.list_update)
2359     dev->proxy.masks.list_update(dev->proxy.masks.module);
2360 }
dt_dev_masks_list_remove(dt_develop_t * dev,int formid,int parentid)2361 void dt_dev_masks_list_remove(dt_develop_t *dev, int formid, int parentid)
2362 {
2363   if(dev->proxy.masks.module && dev->proxy.masks.list_remove)
2364     dev->proxy.masks.list_remove(dev->proxy.masks.module, formid, parentid);
2365 }
dt_dev_masks_selection_change(dt_develop_t * dev,int selectid,int throw_event)2366 void dt_dev_masks_selection_change(dt_develop_t *dev, int selectid, int throw_event)
2367 {
2368   if(dev->proxy.masks.module && dev->proxy.masks.selection_change)
2369     dev->proxy.masks.selection_change(dev->proxy.masks.module, selectid, throw_event);
2370 }
2371 
dt_dev_snapshot_request(dt_develop_t * dev,const char * filename)2372 void dt_dev_snapshot_request(dt_develop_t *dev, const char *filename)
2373 {
2374   dev->proxy.snapshot.filename = filename;
2375   dev->proxy.snapshot.request = TRUE;
2376   dt_control_queue_redraw_center();
2377 }
2378 
dt_dev_invalidate_from_gui(dt_develop_t * dev)2379 void dt_dev_invalidate_from_gui(dt_develop_t *dev)
2380 {
2381   dt_dev_pop_history_items(darktable.develop, darktable.develop->history_end);
2382 }
2383 
dt_dev_average_delay_update(const dt_times_t * start,uint32_t * average_delay)2384 void dt_dev_average_delay_update(const dt_times_t *start, uint32_t *average_delay)
2385 {
2386   dt_times_t end;
2387   dt_get_times(&end);
2388 
2389   *average_delay += ((end.clock - start->clock) * 1000 / DT_DEV_AVERAGE_DELAY_COUNT
2390                      - *average_delay / DT_DEV_AVERAGE_DELAY_COUNT);
2391 }
2392 
2393 
2394 /** duplicate a existent module */
dt_dev_module_duplicate(dt_develop_t * dev,dt_iop_module_t * base)2395 dt_iop_module_t *dt_dev_module_duplicate(dt_develop_t *dev, dt_iop_module_t *base)
2396 {
2397   // we create the new module
2398   dt_iop_module_t *module = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
2399   if(dt_iop_load_module(module, base->so, base->dev)) return NULL;
2400   module->instance = base->instance;
2401 
2402   // we set the multi-instance priority and the iop order
2403   int pmax = 0;
2404   for(GList *modules = base->dev->iop; modules; modules = g_list_next(modules))
2405   {
2406     dt_iop_module_t *mod = (dt_iop_module_t *)modules->data;
2407     if(mod->instance == base->instance)
2408     {
2409       if(pmax < mod->multi_priority) pmax = mod->multi_priority;
2410     }
2411   }
2412   // create a unique multi-priority
2413   pmax += 1;
2414   dt_iop_update_multi_priority(module, pmax);
2415 
2416   // add this new module position into the iop-order-list
2417   dt_ioppr_insert_module_instance(dev, module);
2418 
2419   // since we do not rename the module we need to check that an old module does not have the same name. Indeed
2420   // the multi_priority
2421   // are always rebased to start from 0, to it may be the case that the same multi_name be generated when
2422   // duplicating a module.
2423   int pname = module->multi_priority;
2424   char mname[128];
2425 
2426   do
2427   {
2428     snprintf(mname, sizeof(mname), "%d", pname);
2429     gboolean dup = FALSE;
2430 
2431     for(GList *modules = base->dev->iop; modules; modules = g_list_next(modules))
2432     {
2433       dt_iop_module_t *mod = (dt_iop_module_t *)modules->data;
2434       if(mod->instance == base->instance)
2435       {
2436         if(strcmp(mname, mod->multi_name) == 0)
2437         {
2438           dup = TRUE;
2439           break;
2440         }
2441       }
2442     }
2443 
2444     if(dup)
2445       pname++;
2446     else
2447       break;
2448   } while(1);
2449 
2450   // the multi instance name
2451   g_strlcpy(module->multi_name, mname, sizeof(module->multi_name));
2452   // we insert this module into dev->iop
2453   base->dev->iop = g_list_insert_sorted(base->dev->iop, module, dt_sort_iop_by_order);
2454 
2455   // always place the new instance after the base one
2456   if(!dt_ioppr_move_iop_after(base->dev, module, base))
2457   {
2458     fprintf(stderr, "[dt_dev_module_duplicate] can't move new instance after the base one\n");
2459   }
2460 
2461   // that's all. rest of insertion is gui work !
2462   return module;
2463 }
2464 
dt_dev_invalidate_history_module(GList * list,dt_iop_module_t * module)2465 void dt_dev_invalidate_history_module(GList *list, dt_iop_module_t *module)
2466 {
2467   for(; list; list = g_list_next(list))
2468   {
2469     dt_dev_history_item_t *hitem = (dt_dev_history_item_t *)list->data;
2470     if (hitem->module == module)
2471     {
2472       hitem->module = NULL;
2473     }
2474   }
2475 }
2476 
dt_dev_module_remove(dt_develop_t * dev,dt_iop_module_t * module)2477 void dt_dev_module_remove(dt_develop_t *dev, dt_iop_module_t *module)
2478 {
2479   // if(darktable.gui->reset) return;
2480   dt_pthread_mutex_lock(&dev->history_mutex);
2481   int del = 0;
2482 
2483   if(dev->gui_attached)
2484   {
2485     dt_dev_undo_start_record(dev);
2486 
2487     GList *elem = dev->history;
2488     while(elem != NULL)
2489     {
2490       GList *next = g_list_next(elem);
2491       dt_dev_history_item_t *hist = (dt_dev_history_item_t *)(elem->data);
2492 
2493       if(module == hist->module)
2494       {
2495         // printf("removing obsoleted history item: %s %s %p %p\n", hist->module->op, hist->module->multi_name,
2496         //        module, hist->module);
2497         dt_dev_free_history_item(hist);
2498         dev->history = g_list_delete_link(dev->history, elem);
2499         dev->history_end--;
2500         del = 1;
2501       }
2502       elem = next;
2503     }
2504   }
2505 
2506   dt_pthread_mutex_unlock(&dev->history_mutex);
2507 
2508   // and we remove it from the list
2509   for(GList *modules = dev->iop; modules; modules = g_list_next(modules))
2510   {
2511     dt_iop_module_t *mod = (dt_iop_module_t *)modules->data;
2512     if(mod == module)
2513     {
2514       dev->iop = g_list_remove_link(dev->iop, modules);
2515       break;
2516     }
2517   }
2518 
2519   if(dev->gui_attached && del)
2520   {
2521     /* signal that history has changed */
2522     dt_dev_undo_end_record(dev);
2523 
2524     DT_DEBUG_CONTROL_SIGNAL_RAISE(darktable.signals, DT_SIGNAL_DEVELOP_MODULE_REMOVE, module);
2525     /* redraw */
2526     dt_control_queue_redraw_center();
2527   }
2528 }
2529 
_dev_module_update_multishow(dt_develop_t * dev,struct dt_iop_module_t * module)2530 void _dev_module_update_multishow(dt_develop_t *dev, struct dt_iop_module_t *module)
2531 {
2532   // We count the number of other instances
2533   int nb_instances = 0;
2534   for(GList *modules = dev->iop; modules; modules = g_list_next(modules))
2535   {
2536     dt_iop_module_t *mod = (dt_iop_module_t *)modules->data;
2537 
2538     if(mod->instance == module->instance) nb_instances++;
2539   }
2540 
2541   dt_iop_module_t *mod_prev = dt_iop_gui_get_previous_visible_module(module);
2542   dt_iop_module_t *mod_next = dt_iop_gui_get_next_visible_module(module);
2543 
2544   const gboolean move_next = (mod_next && mod_next->iop_order != INT_MAX) ? dt_ioppr_check_can_move_after_iop(dev->iop, module, mod_next) : -1.0;
2545   const gboolean move_prev = (mod_prev && mod_prev->iop_order != INT_MAX) ? dt_ioppr_check_can_move_before_iop(dev->iop, module, mod_prev) : -1.0;
2546 
2547   module->multi_show_new = !(module->flags() & IOP_FLAGS_ONE_INSTANCE);
2548   module->multi_show_close = (nb_instances > 1);
2549   if(mod_next)
2550     module->multi_show_up = move_next;
2551   else
2552     module->multi_show_up = 0;
2553   if(mod_prev)
2554     module->multi_show_down = move_prev;
2555   else
2556     module->multi_show_down = 0;
2557 }
2558 
dt_dev_modules_update_multishow(dt_develop_t * dev)2559 void dt_dev_modules_update_multishow(dt_develop_t *dev)
2560 {
2561   dt_ioppr_check_iop_order(dev, 0, "dt_dev_modules_update_multishow");
2562 
2563   for(GList *modules = dev->iop; modules; modules = g_list_next(modules))
2564   {
2565     dt_iop_module_t *mod = (dt_iop_module_t *)modules->data;
2566 
2567     // only for visible modules
2568     GtkWidget *expander = mod->expander;
2569     if(expander && gtk_widget_is_visible(expander))
2570     {
2571       _dev_module_update_multishow(dev, mod);
2572     }
2573   }
2574 }
2575 
dt_history_item_get_name(const struct dt_iop_module_t * module)2576 gchar *dt_history_item_get_name(const struct dt_iop_module_t *module)
2577 {
2578   gchar *label;
2579   /* create a history button and add to box */
2580   if(!module->multi_name[0] || strcmp(module->multi_name, "0") == 0)
2581     label = g_strdup_printf("%s", module->name());
2582   else
2583     label = g_strdup_printf("%s %s", module->name(), module->multi_name);
2584   return label;
2585 }
2586 
dt_history_item_get_name_html(const struct dt_iop_module_t * module)2587 gchar *dt_history_item_get_name_html(const struct dt_iop_module_t *module)
2588 {
2589   gchar *label;
2590   /* create a history button and add to box */
2591   if(!module->multi_name[0] || strcmp(module->multi_name, "0") == 0)
2592     label = g_strdup_printf("%s", module->name());
2593   else
2594     label = g_markup_printf_escaped("%s <span size=\"smaller\">%s</span>", module->name(), module->multi_name);
2595   return label;
2596 }
2597 
dt_dev_distort_transform(dt_develop_t * dev,float * points,size_t points_count)2598 int dt_dev_distort_transform(dt_develop_t *dev, float *points, size_t points_count)
2599 {
2600   return dt_dev_distort_transform_plus(dev, dev->preview_pipe, 0.0f, DT_DEV_TRANSFORM_DIR_ALL, points, points_count);
2601 }
dt_dev_distort_backtransform(dt_develop_t * dev,float * points,size_t points_count)2602 int dt_dev_distort_backtransform(dt_develop_t *dev, float *points, size_t points_count)
2603 {
2604   return dt_dev_distort_backtransform_plus(dev, dev->preview_pipe, 0.0f, DT_DEV_TRANSFORM_DIR_ALL, points, points_count);
2605 }
2606 
2607 // only call directly or indirectly from dt_dev_distort_transform_plus, so that it runs with the history locked
dt_dev_distort_transform_locked(dt_develop_t * dev,dt_dev_pixelpipe_t * pipe,const double iop_order,const int transf_direction,float * points,size_t points_count)2608 int dt_dev_distort_transform_locked(dt_develop_t *dev, dt_dev_pixelpipe_t *pipe, const double iop_order,
2609                                     const int transf_direction, float *points, size_t points_count)
2610 {
2611   GList *modules = pipe->iop;
2612   GList *pieces = pipe->nodes;
2613   while(modules)
2614   {
2615     if(!pieces)
2616     {
2617       return 0;
2618     }
2619     dt_iop_module_t *module = (dt_iop_module_t *)(modules->data);
2620     dt_dev_pixelpipe_iop_t *piece = (dt_dev_pixelpipe_iop_t *)(pieces->data);
2621     if(piece->enabled
2622        && ((transf_direction == DT_DEV_TRANSFORM_DIR_ALL)
2623            || (transf_direction == DT_DEV_TRANSFORM_DIR_FORW_INCL && module->iop_order >= iop_order)
2624            || (transf_direction == DT_DEV_TRANSFORM_DIR_FORW_EXCL && module->iop_order > iop_order)
2625            || (transf_direction == DT_DEV_TRANSFORM_DIR_BACK_INCL && module->iop_order <= iop_order)
2626            || (transf_direction == DT_DEV_TRANSFORM_DIR_BACK_EXCL && module->iop_order < iop_order))
2627        && !(dev->gui_module && dev->gui_module != module
2628             && (dev->gui_module->operation_tags_filter() & module->operation_tags())))
2629     {
2630       module->distort_transform(module, piece, points, points_count);
2631     }
2632     modules = g_list_next(modules);
2633     pieces = g_list_next(pieces);
2634   }
2635   return 1;
2636 }
2637 
dt_dev_distort_transform_plus(dt_develop_t * dev,dt_dev_pixelpipe_t * pipe,const double iop_order,const int transf_direction,float * points,size_t points_count)2638 int dt_dev_distort_transform_plus(dt_develop_t *dev, dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction,
2639                                   float *points, size_t points_count)
2640 {
2641   dt_pthread_mutex_lock(&dev->history_mutex);
2642   const int success = dt_dev_distort_transform_locked(dev,pipe,iop_order,transf_direction,points,points_count);
2643 
2644   if (success
2645       && (dev->preview_downsampling != 1.0f)
2646       && (transf_direction == DT_DEV_TRANSFORM_DIR_ALL
2647           || transf_direction == DT_DEV_TRANSFORM_DIR_FORW_EXCL
2648           || transf_direction == DT_DEV_TRANSFORM_DIR_FORW_INCL))
2649     for(size_t idx=0; idx < 2 * points_count; idx++)
2650       points[idx] *= dev->preview_downsampling;
2651 
2652   dt_pthread_mutex_unlock(&dev->history_mutex);
2653   return 1;
2654 }
2655 
2656 // only call directly or indirectly from dt_dev_distort_transform_plus, so that it runs with the history locked
dt_dev_distort_backtransform_locked(dt_develop_t * dev,dt_dev_pixelpipe_t * pipe,const double iop_order,const int transf_direction,float * points,size_t points_count)2657 int dt_dev_distort_backtransform_locked(dt_develop_t *dev, dt_dev_pixelpipe_t *pipe, const double iop_order,
2658                                         const int transf_direction, float *points, size_t points_count)
2659 {
2660   GList *modules = g_list_last(pipe->iop);
2661   GList *pieces = g_list_last(pipe->nodes);
2662   while(modules)
2663   {
2664     if(!pieces)
2665     {
2666       return 0;
2667     }
2668     dt_iop_module_t *module = (dt_iop_module_t *)(modules->data);
2669     dt_dev_pixelpipe_iop_t *piece = (dt_dev_pixelpipe_iop_t *)(pieces->data);
2670     if(piece->enabled
2671        && ((transf_direction == DT_DEV_TRANSFORM_DIR_ALL)
2672            || (transf_direction == DT_DEV_TRANSFORM_DIR_FORW_INCL && module->iop_order >= iop_order)
2673            || (transf_direction == DT_DEV_TRANSFORM_DIR_FORW_EXCL && module->iop_order > iop_order)
2674            || (transf_direction == DT_DEV_TRANSFORM_DIR_BACK_INCL && module->iop_order <= iop_order)
2675            || (transf_direction == DT_DEV_TRANSFORM_DIR_BACK_EXCL && module->iop_order < iop_order))
2676        && !(dev->gui_module && dev->gui_module != module
2677             && (dev->gui_module->operation_tags_filter() & module->operation_tags())))
2678     {
2679       module->distort_backtransform(module, piece, points, points_count);
2680     }
2681     modules = g_list_previous(modules);
2682     pieces = g_list_previous(pieces);
2683   }
2684   return 1;
2685 }
2686 
dt_dev_distort_backtransform_plus(dt_develop_t * dev,dt_dev_pixelpipe_t * pipe,const double iop_order,const int transf_direction,float * points,size_t points_count)2687 int dt_dev_distort_backtransform_plus(dt_develop_t *dev, dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction,
2688                                       float *points, size_t points_count)
2689 {
2690   dt_pthread_mutex_lock(&dev->history_mutex);
2691   if ((dev->preview_downsampling != 1.0f) && (transf_direction == DT_DEV_TRANSFORM_DIR_ALL
2692     || transf_direction == DT_DEV_TRANSFORM_DIR_FORW_EXCL
2693     || transf_direction == DT_DEV_TRANSFORM_DIR_FORW_INCL))
2694       for(size_t idx=0; idx < 2 * points_count; idx++)
2695         points[idx] /= dev->preview_downsampling;
2696 
2697   const int success = dt_dev_distort_backtransform_locked(dev, pipe, iop_order, transf_direction, points, points_count);
2698   dt_pthread_mutex_unlock(&dev->history_mutex);
2699   return success;
2700 }
2701 
dt_dev_distort_get_iop_pipe(dt_develop_t * dev,struct dt_dev_pixelpipe_t * pipe,struct dt_iop_module_t * module)2702 dt_dev_pixelpipe_iop_t *dt_dev_distort_get_iop_pipe(dt_develop_t *dev, struct dt_dev_pixelpipe_t *pipe,
2703                                                     struct dt_iop_module_t *module)
2704 {
2705   for(const GList *pieces = g_list_last(pipe->nodes); pieces; pieces = g_list_previous(pieces))
2706   {
2707     dt_dev_pixelpipe_iop_t *piece = (dt_dev_pixelpipe_iop_t *)(pieces->data);
2708     if(piece->module == module)
2709     {
2710       return piece;
2711     }
2712   }
2713   return NULL;
2714 }
2715 
dt_dev_hash(dt_develop_t * dev)2716 uint64_t dt_dev_hash(dt_develop_t *dev)
2717 {
2718   return dt_dev_hash_plus(dev, dev->preview_pipe, 0.0f, DT_DEV_TRANSFORM_DIR_ALL);
2719 }
2720 
dt_dev_hash_plus(dt_develop_t * dev,struct dt_dev_pixelpipe_t * pipe,const double iop_order,const int transf_direction)2721 uint64_t dt_dev_hash_plus(dt_develop_t *dev, struct dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction)
2722 {
2723   uint64_t hash = 5381;
2724   dt_pthread_mutex_lock(&dev->history_mutex);
2725   GList *modules = g_list_last(pipe->iop);
2726   GList *pieces = g_list_last(pipe->nodes);
2727   while(modules)
2728   {
2729     if(!pieces)
2730     {
2731       dt_pthread_mutex_unlock(&dev->history_mutex);
2732       return 0;
2733     }
2734     dt_iop_module_t *module = (dt_iop_module_t *)(modules->data);
2735     dt_dev_pixelpipe_iop_t *piece = (dt_dev_pixelpipe_iop_t *)(pieces->data);
2736     if(piece->enabled && ((transf_direction == DT_DEV_TRANSFORM_DIR_ALL)
2737                           || (transf_direction == DT_DEV_TRANSFORM_DIR_FORW_INCL && module->iop_order >= iop_order)
2738                           || (transf_direction == DT_DEV_TRANSFORM_DIR_FORW_EXCL && module->iop_order > iop_order)
2739                           || (transf_direction == DT_DEV_TRANSFORM_DIR_BACK_INCL && module->iop_order <= iop_order)
2740                           || (transf_direction == DT_DEV_TRANSFORM_DIR_BACK_EXCL && module->iop_order < iop_order)))
2741     {
2742       hash = ((hash << 5) + hash) ^ piece->hash;
2743     }
2744     modules = g_list_previous(modules);
2745     pieces = g_list_previous(pieces);
2746   }
2747   dt_pthread_mutex_unlock(&dev->history_mutex);
2748   return hash;
2749 }
2750 
dt_dev_wait_hash(dt_develop_t * dev,struct dt_dev_pixelpipe_t * pipe,const double iop_order,const int transf_direction,dt_pthread_mutex_t * lock,const volatile uint64_t * const hash)2751 int dt_dev_wait_hash(dt_develop_t *dev, struct dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction, dt_pthread_mutex_t *lock,
2752                      const volatile uint64_t *const hash)
2753 {
2754   const int usec = 5000;
2755   int nloop;
2756 
2757 #ifdef HAVE_OPENCL
2758   if(pipe->devid >= 0)
2759     nloop = darktable.opencl->opencl_synchronization_timeout;
2760   else
2761     nloop = dt_conf_get_int("pixelpipe_synchronization_timeout");
2762 #else
2763   nloop = dt_conf_get_int("pixelpipe_synchronization_timeout");
2764 #endif
2765 
2766   if(nloop <= 0) return TRUE;  // non-positive values omit pixelpipe synchronization
2767 
2768   for(int n = 0; n < nloop; n++)
2769   {
2770     if(dt_atomic_get_int(&pipe->shutdown))
2771       return TRUE;  // stop waiting if pipe shuts down
2772 
2773     uint64_t probehash;
2774 
2775     if(lock)
2776     {
2777       dt_pthread_mutex_lock(lock);
2778       probehash = *hash;
2779       dt_pthread_mutex_unlock(lock);
2780     }
2781     else
2782       probehash = *hash;
2783 
2784     if(probehash == dt_dev_hash_plus(dev, pipe, iop_order, transf_direction))
2785       return TRUE;
2786 
2787     dt_iop_nap(usec);
2788   }
2789 
2790   return FALSE;
2791 }
2792 
dt_dev_sync_pixelpipe_hash(dt_develop_t * dev,struct dt_dev_pixelpipe_t * pipe,const double iop_order,const int transf_direction,dt_pthread_mutex_t * lock,const volatile uint64_t * const hash)2793 int dt_dev_sync_pixelpipe_hash(dt_develop_t *dev, struct dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction, dt_pthread_mutex_t *lock,
2794                                const volatile uint64_t *const hash)
2795 {
2796   // first wait for matching hash values
2797   if(dt_dev_wait_hash(dev, pipe, iop_order, transf_direction, lock, hash))
2798     return TRUE;
2799 
2800   // timed out. let's see if history stack has changed
2801   if(pipe->changed & (DT_DEV_PIPE_TOP_CHANGED | DT_DEV_PIPE_REMOVE | DT_DEV_PIPE_SYNCH))
2802   {
2803     // history stack has changed. let's trigger reprocessing
2804     dt_control_queue_redraw_center();
2805     // pretend that everything is fine
2806     return TRUE;
2807   }
2808 
2809   // no way to get pixelpipes in sync
2810   return FALSE;
2811 }
2812 
dt_dev_hash_distort(dt_develop_t * dev)2813 uint64_t dt_dev_hash_distort(dt_develop_t *dev)
2814 {
2815   return dt_dev_hash_distort_plus(dev, dev->preview_pipe, 0.0f, DT_DEV_TRANSFORM_DIR_ALL);
2816 }
2817 
dt_dev_hash_distort_plus(dt_develop_t * dev,struct dt_dev_pixelpipe_t * pipe,const double iop_order,const int transf_direction)2818 uint64_t dt_dev_hash_distort_plus(dt_develop_t *dev, struct dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction)
2819 {
2820   uint64_t hash = 5381;
2821   dt_pthread_mutex_lock(&dev->history_mutex);
2822   GList *modules = g_list_last(pipe->iop);
2823   GList *pieces = g_list_last(pipe->nodes);
2824   while(modules)
2825   {
2826     if(!pieces)
2827     {
2828       dt_pthread_mutex_unlock(&dev->history_mutex);
2829       return 0;
2830     }
2831     dt_iop_module_t *module = (dt_iop_module_t *)(modules->data);
2832     dt_dev_pixelpipe_iop_t *piece = (dt_dev_pixelpipe_iop_t *)(pieces->data);
2833     if(piece->enabled && module->operation_tags() & IOP_TAG_DISTORT
2834        && ((transf_direction == DT_DEV_TRANSFORM_DIR_ALL)
2835            || (transf_direction == DT_DEV_TRANSFORM_DIR_FORW_INCL && module->iop_order >= iop_order)
2836            || (transf_direction == DT_DEV_TRANSFORM_DIR_FORW_EXCL && module->iop_order > iop_order)
2837            || (transf_direction == DT_DEV_TRANSFORM_DIR_BACK_INCL && module->iop_order <= iop_order)
2838            || (transf_direction == DT_DEV_TRANSFORM_DIR_BACK_EXCL && module->iop_order < iop_order)))
2839     {
2840       hash = ((hash << 5) + hash) ^ piece->hash;
2841     }
2842     modules = g_list_previous(modules);
2843     pieces = g_list_previous(pieces);
2844   }
2845   dt_pthread_mutex_unlock(&dev->history_mutex);
2846   return hash;
2847 }
2848 
dt_dev_wait_hash_distort(dt_develop_t * dev,struct dt_dev_pixelpipe_t * pipe,const double iop_order,const int transf_direction,dt_pthread_mutex_t * lock,const volatile uint64_t * const hash)2849 int dt_dev_wait_hash_distort(dt_develop_t *dev, struct dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction, dt_pthread_mutex_t *lock,
2850                      const volatile uint64_t *const hash)
2851 {
2852   const int usec = 5000;
2853   int nloop = 0;
2854 
2855 #ifdef HAVE_OPENCL
2856   if(pipe->devid >= 0)
2857     nloop = darktable.opencl->opencl_synchronization_timeout;
2858   else
2859     nloop = dt_conf_get_int("pixelpipe_synchronization_timeout");
2860 #else
2861   nloop = dt_conf_get_int("pixelpipe_synchronization_timeout");
2862 #endif
2863 
2864   if(nloop <= 0) return TRUE;  // non-positive values omit pixelpipe synchronization
2865 
2866   for(int n = 0; n < nloop; n++)
2867   {
2868     if(dt_atomic_get_int(&pipe->shutdown))
2869       return TRUE;  // stop waiting if pipe shuts down
2870 
2871     uint64_t probehash = 0;
2872 
2873     if(lock)
2874     {
2875       dt_pthread_mutex_lock(lock);
2876       probehash = *hash;
2877       dt_pthread_mutex_unlock(lock);
2878     }
2879     else
2880       probehash = *hash;
2881 
2882     if(probehash == dt_dev_hash_distort_plus(dev, pipe, iop_order, transf_direction))
2883       return TRUE;
2884 
2885     dt_iop_nap(usec);
2886   }
2887 
2888   return FALSE;
2889 }
2890 
dt_dev_sync_pixelpipe_hash_distort(dt_develop_t * dev,struct dt_dev_pixelpipe_t * pipe,const double iop_order,const int transf_direction,dt_pthread_mutex_t * lock,const volatile uint64_t * const hash)2891 int dt_dev_sync_pixelpipe_hash_distort(dt_develop_t *dev, struct dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction, dt_pthread_mutex_t *lock,
2892                                        const volatile uint64_t *const hash)
2893 {
2894   // first wait for matching hash values
2895   if(dt_dev_wait_hash_distort(dev, pipe, iop_order, transf_direction, lock, hash))
2896     return TRUE;
2897 
2898   // timed out. let's see if history stack has changed
2899   if(pipe->changed & (DT_DEV_PIPE_TOP_CHANGED | DT_DEV_PIPE_REMOVE | DT_DEV_PIPE_SYNCH))
2900   {
2901     // history stack has changed. let's trigger reprocessing
2902     dt_control_queue_redraw_center();
2903     // pretend that everything is fine
2904     return TRUE;
2905   }
2906 
2907   // no way to get pixelpipes in sync
2908   return FALSE;
2909 }
2910 
2911 // set the module list order
dt_dev_reorder_gui_module_list(dt_develop_t * dev)2912 void dt_dev_reorder_gui_module_list(dt_develop_t *dev)
2913 {
2914   int pos_module = 0;
2915   for(const GList *modules = g_list_last(dev->iop); modules; modules = g_list_previous(modules))
2916   {
2917     dt_iop_module_t *module = (dt_iop_module_t *)(modules->data);
2918 
2919     GtkWidget *expander = module->expander;
2920     if(expander)
2921     {
2922       gtk_box_reorder_child(dt_ui_get_container(darktable.gui->ui, DT_UI_CONTAINER_PANEL_RIGHT_CENTER), expander,
2923                             pos_module++);
2924     }
2925   }
2926 }
2927 
2928 //-----------------------------------------------------------
2929 // second darkroom window
2930 //-----------------------------------------------------------
2931 
dt_second_window_get_dev_zoom(dt_develop_t * dev)2932 dt_dev_zoom_t dt_second_window_get_dev_zoom(dt_develop_t *dev)
2933 {
2934   return dev->second_window.zoom;
2935 }
2936 
dt_second_window_set_dev_zoom(dt_develop_t * dev,const dt_dev_zoom_t value)2937 void dt_second_window_set_dev_zoom(dt_develop_t *dev, const dt_dev_zoom_t value)
2938 {
2939   dev->second_window.zoom = value;
2940 }
2941 
dt_second_window_get_dev_closeup(dt_develop_t * dev)2942 int dt_second_window_get_dev_closeup(dt_develop_t *dev)
2943 {
2944   return dev->second_window.closeup;
2945 }
2946 
dt_second_window_set_dev_closeup(dt_develop_t * dev,const int value)2947 void dt_second_window_set_dev_closeup(dt_develop_t *dev, const int value)
2948 {
2949   dev->second_window.closeup = value;
2950 }
2951 
dt_second_window_get_dev_zoom_x(dt_develop_t * dev)2952 float dt_second_window_get_dev_zoom_x(dt_develop_t *dev)
2953 {
2954   return dev->second_window.zoom_x;
2955 }
2956 
dt_second_window_set_dev_zoom_x(dt_develop_t * dev,const float value)2957 void dt_second_window_set_dev_zoom_x(dt_develop_t *dev, const float value)
2958 {
2959   dev->second_window.zoom_x = value;
2960 }
2961 
dt_second_window_get_dev_zoom_y(dt_develop_t * dev)2962 float dt_second_window_get_dev_zoom_y(dt_develop_t *dev)
2963 {
2964   return dev->second_window.zoom_y;
2965 }
2966 
dt_second_window_set_dev_zoom_y(dt_develop_t * dev,const float value)2967 void dt_second_window_set_dev_zoom_y(dt_develop_t *dev, const float value)
2968 {
2969   dev->second_window.zoom_y = value;
2970 }
2971 
dt_second_window_get_free_zoom_scale(dt_develop_t * dev)2972 float dt_second_window_get_free_zoom_scale(dt_develop_t *dev)
2973 {
2974   return dev->second_window.zoom_scale;
2975 }
2976 
dt_second_window_get_zoom_scale(dt_develop_t * dev,const dt_dev_zoom_t zoom,const int closeup_factor,const int preview)2977 float dt_second_window_get_zoom_scale(dt_develop_t *dev, const dt_dev_zoom_t zoom, const int closeup_factor,
2978                                       const int preview)
2979 {
2980   float zoom_scale = 0.0f;
2981 
2982   const float w = preview ? dev->preview_pipe->processed_width : dev->preview2_pipe->processed_width;
2983   const float h = preview ? dev->preview_pipe->processed_height : dev->preview2_pipe->processed_height;
2984   const float ps = dev->preview2_pipe->backbuf_width
2985                        ? dev->preview2_pipe->processed_width / (float)dev->preview_pipe->processed_width
2986                        : dev->preview_pipe->iscale;
2987 
2988   switch(zoom)
2989   {
2990     case DT_ZOOM_FIT:
2991       zoom_scale = fminf(dev->second_window.width / w, dev->second_window.height / h);
2992       break;
2993     case DT_ZOOM_FILL:
2994       zoom_scale = fmaxf(dev->second_window.width / w, dev->second_window.height / h);
2995       break;
2996     case DT_ZOOM_1:
2997       zoom_scale = closeup_factor;
2998       if(preview) zoom_scale *= ps;
2999       break;
3000     default: // DT_ZOOM_FREE
3001       zoom_scale = dt_second_window_get_free_zoom_scale(dev);
3002       if(preview) zoom_scale *= ps;
3003       break;
3004   }
3005   if (preview) zoom_scale /= dev->preview_downsampling;
3006   return zoom_scale;
3007 }
3008 
dt_second_window_set_zoom_scale(dt_develop_t * dev,const float value)3009 void dt_second_window_set_zoom_scale(dt_develop_t *dev, const float value)
3010 {
3011   dev->second_window.zoom_scale = value;
3012 }
3013 
dt_second_window_get_processed_size(const dt_develop_t * dev,int * procw,int * proch)3014 void dt_second_window_get_processed_size(const dt_develop_t *dev, int *procw, int *proch)
3015 {
3016   if(!dev) return;
3017 
3018   // if preview2 is processed, lets return its size
3019   if(dev->preview2_pipe && dev->preview2_pipe->processed_width)
3020   {
3021     *procw = dev->preview2_pipe->processed_width;
3022     *proch = dev->preview2_pipe->processed_height;
3023     return;
3024   }
3025 
3026   // fallback on preview pipe
3027   if(dev->preview_pipe && dev->preview_pipe->processed_width)
3028   {
3029     const float scale = (dev->preview_pipe->iscale / dev->preview_downsampling);
3030     *procw = scale * dev->preview_pipe->processed_width;
3031     *proch = scale * dev->preview_pipe->processed_height;
3032     return;
3033   }
3034 
3035   // no processed pipes, lets return 0 size
3036   *procw = *proch = 0;
3037   return;
3038 }
3039 
dt_second_window_check_zoom_bounds(dt_develop_t * dev,float * zoom_x,float * zoom_y,const dt_dev_zoom_t zoom,const int closeup,float * boxww,float * boxhh)3040 void dt_second_window_check_zoom_bounds(dt_develop_t *dev, float *zoom_x, float *zoom_y, const dt_dev_zoom_t zoom,
3041                                         const int closeup, float *boxww, float *boxhh)
3042 {
3043   int procw = 0, proch = 0;
3044   dt_second_window_get_processed_size(dev, &procw, &proch);
3045   float boxw = 1.0f, boxh = 1.0f; // viewport in normalised space
3046                             //   if(zoom == DT_ZOOM_1)
3047                             //   {
3048                             //     const float imgw = (closeup ? 2 : 1)*procw;
3049                             //     const float imgh = (closeup ? 2 : 1)*proch;
3050                             //     const float devw = MIN(imgw, dev->width);
3051                             //     const float devh = MIN(imgh, dev->height);
3052                             //     boxw = fminf(1.0, devw/imgw);
3053                             //     boxh = fminf(1.0, devh/imgh);
3054                             //   }
3055   if(zoom == DT_ZOOM_FIT)
3056   {
3057     *zoom_x = *zoom_y = 0.0f;
3058     boxw = boxh = 1.0f;
3059   }
3060   else
3061   {
3062     const float scale = dt_second_window_get_zoom_scale(dev, zoom, 1 << closeup, 0);
3063     const float imgw = procw;
3064     const float imgh = proch;
3065     const float devw = dev->second_window.width;
3066     const float devh = dev->second_window.height;
3067     boxw = devw / (imgw * scale);
3068     boxh = devh / (imgh * scale);
3069   }
3070 
3071   if(*zoom_x < boxw / 2 - .5) *zoom_x = boxw / 2 - .5;
3072   if(*zoom_x > .5 - boxw / 2) *zoom_x = .5 - boxw / 2;
3073   if(*zoom_y < boxh / 2 - .5) *zoom_y = boxh / 2 - .5;
3074   if(*zoom_y > .5 - boxh / 2) *zoom_y = .5 - boxh / 2;
3075   if(boxw > 1.0) *zoom_x = 0.0f;
3076   if(boxh > 1.0) *zoom_y = 0.0f;
3077 
3078   if(boxww) *boxww = boxw;
3079   if(boxhh) *boxhh = boxh;
3080 }
3081 
dt_dev_undo_start_record(dt_develop_t * dev)3082 void dt_dev_undo_start_record(dt_develop_t *dev)
3083 {
3084   const dt_view_t *cv = dt_view_manager_get_current_view(darktable.view_manager);
3085 
3086   /* record current history state : before change (needed for undo) */
3087   if(dev->gui_attached && cv->view((dt_view_t *)cv) == DT_VIEW_DARKROOM)
3088   {
3089     DT_DEBUG_CONTROL_SIGNAL_RAISE
3090       (darktable.signals, DT_SIGNAL_DEVELOP_HISTORY_WILL_CHANGE,
3091        dt_history_duplicate(dev->history),
3092        dev->history_end,
3093        dt_ioppr_iop_order_copy_deep(dev->iop_order_list));
3094   }
3095 }
3096 
dt_dev_undo_end_record(dt_develop_t * dev)3097 void dt_dev_undo_end_record(dt_develop_t *dev)
3098 {
3099   const dt_view_t *cv = dt_view_manager_get_current_view(darktable.view_manager);
3100 
3101   /* record current history state : after change (needed for undo) */
3102   if(dev->gui_attached && cv->view((dt_view_t *)cv) == DT_VIEW_DARKROOM)
3103   {
3104     DT_DEBUG_CONTROL_SIGNAL_RAISE(darktable.signals, DT_SIGNAL_DEVELOP_HISTORY_CHANGE);
3105   }
3106 }
3107 
3108 // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
3109 // vim: shiftwidth=2 expandtab tabstop=2 cindent
3110 // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
3111