Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
signal.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2011-2012 Henrik Andersson.
4 Copyright (C) 2011-2012 johannes hanika.
5 Copyright (C) 2012 Ivan Tarozzi.
6 Copyright (C) 2012 José Carlos García Sogo.
7 Copyright (C) 2012-2015 Jérémy Rosen.
8 Copyright (C) 2012 Richard Wonka.
9 Copyright (C) 2012-2016 Tobias Ellinghaus.
10 Copyright (C) 2014, 2016 Roman Lebedev.
11 Copyright (C) 2014 Ronny Kahl.
12 Copyright (C) 2015 Edouard Gomez.
13 Copyright (C) 2016, 2019-2021 Pascal Obry.
14 Copyright (C) 2018-2019 Edgardo Hoszowski.
15 Copyright (C) 2018 Rikard Öxler.
16 Copyright (C) 2019-2022 Aldric Renaudin.
17 Copyright (C) 2019 Ulrich Pegelow.
18 Copyright (C) 2020 Chris Elston.
19 Copyright (C) 2020 Hanno Schwalm.
20 Copyright (C) 2020 Hubert Kowalski.
21 Copyright (C) 2020-2021 Philippe Weyland.
22 Copyright (C) 2021 Ralf Brown.
23 Copyright (C) 2022-2023, 2025 Aurélien PIERRE.
24 Copyright (C) 2022 Martin Bařinka.
25
26 darktable is free software: you can redistribute it and/or modify
27 it under the terms of the GNU General Public License as published by
28 the Free Software Foundation, either version 3 of the License, or
29 (at your option) any later version.
30
31 darktable is distributed in the hope that it will be useful,
32 but WITHOUT ANY WARRANTY; without even the implied warranty of
33 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34 GNU General Public License for more details.
35
36 You should have received a copy of the GNU General Public License
37 along with darktable. If not, see <http://www.gnu.org/licenses/>.
38*/
39#include "common/darktable.h"
40#include "control/signal.h"
41#include "control/control.h"
42#include <glib.h>
43#include <string.h>
44
45#ifdef DT_HAVE_SIGNAL_TRACE
46#include <execinfo.h>
47#endif
48
49typedef struct dt_control_signal_t
50{
51 /* the sinks for the signals */
52 GObject *sink;
54
55/*
56 GSignalFlags signal_flags,
57 ...);
58 */
60{
61 const char *name;
62 GSignalAccumulator accumulator;
63 gpointer accu_data;
65 GSignalCMarshaller c_marshaller;
66 guint n_params;
68 GCallback destructor;
69 gboolean synchronous;
71
72
73static GType uint_arg[] = { G_TYPE_UINT };
74static GType uint64_2arg[] = { G_TYPE_UINT64, G_TYPE_UINT64 };
75static GType int_arg[] = { G_TYPE_INT };
76static GType uint_2arg[] = { G_TYPE_UINT, G_TYPE_UINT };
77static GType pointer_arg[] = { G_TYPE_POINTER };
78static GType pointer_2arg[] = { G_TYPE_POINTER, G_TYPE_POINTER };
79static GType collection_args[] = { G_TYPE_UINT, G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_UINT };
80static GType image_export_arg[]
81 = { G_TYPE_UINT, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER };
83= { G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_POINTER };
84static GType geotag_arg[] = { G_TYPE_POINTER, G_TYPE_UINT };
85static GType file_crawling_arg[] = { G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT };
86static GType mask_change_arg[] = { G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_UINT };
87
88// callback for the destructor of DT_SIGNAL_COLLECTION_CHANGED
89static void _collection_changed_destroy_callback(gpointer instance, int query_change, int changed_property,
90 gpointer imgs, const int next, gpointer user_data)
91{
92 if(imgs)
93 {
94 g_list_free(imgs);
95 imgs = NULL;
96 }
97}
98
99// callback for the destructor of DT_SIGNAL_IMAGE_INFO_CHANGED
100static void _image_info_changed_destroy_callback(gpointer instance, gpointer imgs, gpointer user_data)
101{
102 if(!IS_NULL_PTR(imgs))
103 {
104 g_list_free(imgs);
105 imgs = NULL;
106 }
107}
108
109// callback for the destructor of DT_SIGNAL_PRESETS_CHANGED
110static void _presets_changed_destroy_callback(gpointer instance, gpointer module, gpointer user_data)
111{
112 dt_free(module);
113}
114
115// callback for the destructor of DT_SIGNAL_GEOTAG_CHANGED
116static void _image_geotag_destroy_callback(gpointer instance, gpointer imgs, const int locid, gpointer user_data)
117{
118 if(!IS_NULL_PTR(imgs))
119 {
120 g_list_free(imgs);
121 imgs = NULL;
122 }
123}
124
126 /* Global signals */
127 { "dt-global-mouse-over-image-change", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
128 FALSE }, // DT_SIGNAL_MOUSE_OVER_IMAGE_CHANGE
129 { "dt-global-active-images-change", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
130 FALSE }, // DT_SIGNAL_ACTIVE_IMAGES_CHANGE
131
132 { "dt-control-redraw-all", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
133 FALSE }, // DT_SIGNAL_CONTROL_REDRAW_ALL
134 { "dt-control-redraw-center", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
135 FALSE }, // DT_SIGNAL_CONTROL_REDRAW_CENTER
136
137 { "dt-viewmanager-view-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 2, pointer_2arg, NULL,
138 FALSE }, // DT_SIGNAL_VIEWMANAGER_VIEW_CHANGED
139 { "dt-viewmanager-view-cannot-change", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 2, pointer_2arg,
140 NULL, FALSE }, // DT_SIGNAL_VIEWMANAGER_VIEW_CANNOT_CHANGE
141 { "dt-viewmanager-thumbtable-activate", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__UINT, 1, uint_arg,
142 NULL, FALSE }, // DT_SIGNAL_VIEWMANAGER_THUMBTABLE_ACTIVATE
143 { "dt-viewmanager-filmstrip-activate", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__UINT, 1, uint_arg,
144 NULL, FALSE }, // DT_SIGNAL_VIEWMANAGER_FILMSTRIP_ACTIVATE
145 { "dt-viewmanager-filmstrip-drag-begin", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__UINT, 1, uint_arg,
146 NULL, FALSE }, // DT_SIGNAL_VIEWMANAGER_FILMSTRIP_DRAG_BEGIN
147
148 { "dt-collection-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 4, collection_args,
149 G_CALLBACK(_collection_changed_destroy_callback), FALSE }, // DT_SIGNAL_COLLECTION_CHANGED
150 { "dt-selection-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
151 FALSE }, // DT_SIGNAL_SELECTION_CHANGED
152 { "dt-tag-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
153 FALSE }, // DT_SIGNAL_TAG_CHANGED
154 { "dt-geotag-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 2, geotag_arg,
155 G_CALLBACK(_image_geotag_destroy_callback), FALSE }, // DT_SIGNAL_GEOTAG_CHANGED
156 { "dt-metadata-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__UINT, 1, uint_arg, NULL,
157 FALSE }, // DT_SIGNAL_METADATA_CHANGED
158 { "dt-image-info-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 1, pointer_arg,
159 G_CALLBACK(_image_info_changed_destroy_callback), FALSE }, // DT_SIGNAL_IMAGE_INFO_CHANGED
160 { "dt-style-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
161 FALSE }, // DT_SIGNAL_STYLE_CHANGED
162 { "dt-images-order-change", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 1, pointer_arg, NULL,
163 FALSE }, // DT_SIGNAL_IMAGES_ORDER_CHANGE
164 { "dt-filmrolls-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
165 FALSE }, // DT_SIGNAL_FILMROLLS_CHANGED
166 { "dt-filmrolls-removed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
167 FALSE }, // DT_SIGNAL_FILMROLLS_REMOVED
168 { "dt-presets-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 1, pointer_arg,
169 G_CALLBACK(_presets_changed_destroy_callback), FALSE }, // DT_SIGNAL_PRESETS_CHANGED
170
171 /* Develop related signals */
172 { "dt-develop-initialized", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
173 FALSE }, // DT_SIGNAL_DEVELOP_INITIALIZED
174 { "dt-develop-preview-pipe-finished", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
175 FALSE }, // DT_SIGNAL_DEVELOP_PREVIEW_PIPE_FINISHED
176 { "dt-develop-ui-pipe-finished", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
177 FALSE }, // DT_SIGNAL_DEVELOP_UI_PIPE_FINISHED
178 { "dt-cacheline-ready", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 2, uint64_2arg, NULL,
179 FALSE }, // DT_SIGNAL_CACHELINE_READY (hash, producer_node_key)
180 { "dt-develop-modulegroups-set", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__POINTER, 1, pointer_arg, NULL,
181 FALSE }, // DT_SIGNAL_DEVELOP_MODULEGROUPS_SET
182 { "dt-develop-history-will-change", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 3,
183 history_will_change_arg, NULL, FALSE }, // DT_SIGNAL_HISTORY_WILL_CHANGE
184 { "dt-develop-history-change", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
185 FALSE }, // DT_SIGNAL_HISTORY_CHANGE
186 { "dt-history-resync", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
187 FALSE }, // DT_SIGNAL_HISTORY_RESYNC
188 { "dt-develop-module-remove", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 1, pointer_arg, NULL,
189 TRUE }, // DT_SIGNAL_MODULE_REMOVE
190 { "dt-develop-module-moved", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
191 FALSE }, // DT_SIGNAL_DEVELOP_MODULE_MOVED
192 { "dt-develop-image-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
193 FALSE }, // DT_SIGNAL_DEVELOP_IMAGE_CHANGED
194 { "dt-darkroom-ui-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
195 FALSE}, // DT_SIGNAL_DARKROOM_UI_CHANGED
196 { "dt-image-loaded", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 2, uint_2arg,
197 NULL, FALSE }, // DT_SIGNAL_IMAGE_LOADED
198 { "dt-control-profile-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
199 FALSE }, // DT_SIGNAL_CONTROL_PROFILE_CHANGED
200 { "dt-control-profile-user-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__UINT, 1, uint_arg, NULL,
201 FALSE }, // DT_SIGNAL_CONTROL_PROFILE_USER_CHANGED
202 { "dt-image-import", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__INT, 1, int_arg, NULL,
203 FALSE }, // DT_SIGNAL_IMAGE_IMPORT
204 { "dt-image-export-tmpfile", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 6, image_export_arg, NULL,
205 TRUE }, // DT_SIGNAL_IMAGE_EXPORT_TMPFILE
206 { "dt-imageio-storage-change", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
207 FALSE }, // DT_SIGNAL_IMAGEIO_STORAGE_CHANGE
208
209
210 { "dt-preferences-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
211 FALSE }, // DT_SIGNAL_PREFERENCES_CHANGE
212
213
214 { "dt-control-navigation-redraw", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
215 FALSE }, // DT_SIGNAL_CONTROL_NAVIGATION_REDRAW
216
217 { "dt-control-log-redraw", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
218 FALSE }, // DT_SIGNAL_CONTROL_LOG_REDRAW
219
220 { "dt-control-toast-redraw", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
221 FALSE }, // DT_SIGNAL_CONTROL_TOAST_REDRAW
222
223 { "dt-control-pickerdata-ready", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
224 TRUE }, // DT_SIGNAL_CONTROL_PICKERDATA_REAEDY
225
226 { "dt-control-notebook-tab-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 1, pointer_arg, NULL,
227 FALSE }, // DT_SIGNAL_CONTROL_NOTEBOOK_TAB_CHANGED (owner)
228
229 { "dt-metadata-update", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
230 FALSE }, // DT_SIGNAL_METADATA_UPDATE
231
232 { "dt-location-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 1, pointer_arg, NULL,
233 TRUE }, // DT_SIGNAL_LOCATION_CHANGED
234
235 { "dt-mask-selection-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 2, pointer_2arg, NULL,
236 TRUE }, // DT_SIGNAL_MASK_SELECTION_CHANGED
237 { "dt-mask-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 3, mask_change_arg, NULL,
238 FALSE }, //DT_SIGNAL_MASK_CHANGED
239 { "dt-mask-shape-buttons-deactivate", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 1, pointer_arg, NULL,
240 FALSE }, // DT_SIGNAL_MASK_SHAPE_BUTTONS_DEACTIVATE
241 { "dt-develop-masks-gui-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
242 FALSE }, // DT_SIGNAL_DEVELOP_MASKS_GUI_CHANGED
243
244 { "dt-control-filelist-update", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 3, file_crawling_arg, NULL,
245 TRUE }, // DT_SIGNAL_FILELIST_UPDATED: synchronous so crawler-owned pointers stay valid until handlers return.
246
247 { "dt-folder-survey-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
248 FALSE }, // DT_SIGNAL_FOLDER_SURVEY_CHANGED
249};
250
251static GType _signal_type;
252
254{
255 dt_control_signal_t *ctlsig = g_malloc0(sizeof(dt_control_signal_t));
256
257 /* setup dummy gobject typeinfo */
258 GTypeQuery query;
259 GTypeInfo type_info = { 0, (GBaseInitFunc)NULL, (GBaseFinalizeFunc)NULL, (GClassInitFunc)NULL,
260 (GClassFinalizeFunc)NULL, NULL, 0, 0, (GInstanceInitFunc)NULL };
261
262 g_type_query(G_TYPE_OBJECT, &query);
263 type_info.class_size = query.class_size;
264 type_info.instance_size = query.instance_size;
265 _signal_type = g_type_register_static(G_TYPE_OBJECT, "DarktableSignals", &type_info, 0);
266
267 /* create our pretty empty gobject */
268 ctlsig->sink = g_object_new(_signal_type, NULL);
269
270 /* create the signals */
271 for(int k = 0; k < DT_SIGNAL_COUNT; k++)
272 {
273 g_signal_newv(_signal_description[k].name, _signal_type, G_SIGNAL_RUN_LAST, 0,
274 _signal_description[k].accumulator, _signal_description[k].accu_data,
275 _signal_description[k].c_marshaller, _signal_description[k].return_type,
276 _signal_description[k].n_params, _signal_description[k].param_types);
277 if(_signal_description[k].destructor)
278 {
279 g_signal_connect_after(G_OBJECT(ctlsig->sink), _signal_description[k].name,
281 }
282 }
283 return ctlsig;
284}
285
287{
288 if(IS_NULL_PTR(ctlsig)) return;
289 if(!IS_NULL_PTR(ctlsig->sink)) g_object_unref(ctlsig->sink);
290 dt_free(ctlsig);
291}
292
299
300static gboolean _signal_emit(gpointer user_data)
301{
302 _signal_param_t *params = (_signal_param_t *)user_data;
303 g_signal_emitv(params->instance_and_params, params->signal_id, 0, NULL);
304 return G_SOURCE_REMOVE;
305}
306
307static void _signal_param_cleanup(gpointer user_data)
308{
309 _signal_param_t *params = (_signal_param_t *)user_data;
310 if(IS_NULL_PTR(params)) return;
311 // We iterate over the whole emitted argument vector (instance at index 0 + signal params)
312 // and only unset slots that currently hold a valid GValue type.
313 for(int i = 0; i <= params->n_params; i++)
314 {
315 GValue *value = &params->instance_and_params[i];
316 const GType value_type = G_VALUE_TYPE(value);
317 if(value_type == G_TYPE_INVALID) continue;
318 if(!g_type_check_is_value_type(value_type)) continue;
319 g_value_unset(value);
320 }
321 dt_free(params->instance_and_params);
322 dt_free(params);
323}
324
325typedef struct async_com_data
326{
327 GCond end_cond;
328 GMutex end_mutex;
329 gpointer user_data;
331
332gboolean _async_com_callback(gpointer data)
333{
334 async_com_data *communication = (async_com_data*)data;
335 g_mutex_lock(&communication->end_mutex);
336 _signal_emit(communication->user_data);
337 _signal_param_cleanup(communication->user_data);
338
339 g_cond_signal(&communication->end_cond);
340 g_mutex_unlock(&communication->end_mutex);
341 return FALSE;
342}
343
344static void _print_trace (const char* op)
345{
346#ifdef DT_HAVE_SIGNAL_TRACE
348 {
349 void *array[10];
350 size_t size;
351 char **strings;
352 size_t i;
353
354 size = backtrace (array, 10);
355 strings = backtrace_symbols (array, size);
356
357 for (i = 0; i < size; i++)
358 dt_print(DT_DEBUG_SIGNAL, "[signal-trace-%s]: %s\n", op, strings[i]);
359
360 dt_free(strings);
361 }
362#endif
363}
364
366{
367 // ignore all signals on shutdown
368 if(!dt_control_running()) return;
369
370 dt_signal_description *signal_description = &_signal_description[signal];
371
372 _signal_param_t *params = (_signal_param_t *)malloc(sizeof(_signal_param_t));
373 if(IS_NULL_PTR(params)) return;
374
375 GValue *instance_and_params = calloc(1 + signal_description->n_params, sizeof(GValue));
376 if(IS_NULL_PTR(instance_and_params))
377 {
378 dt_free(params);
379 return;
380 }
381
383 {
384 dt_print(DT_DEBUG_SIGNAL, "[signal] raised: %s\n", signal_description->name);
385 _print_trace("raise");
386 }
387
388 // 0th element has to be the instance to call
389 g_value_init(instance_and_params, _signal_type);
390 g_value_set_object(instance_and_params, ctlsig->sink);
391
392 // the rest of instance_and_params will be the params for the callback
393 va_list extra_args;
394 va_start(extra_args, signal);
395
396 for(int i = 1; i <= signal_description->n_params; i++)
397 {
398 GType type = signal_description->param_types[i-1];
399 g_value_init(&instance_and_params[i], type);
400 switch(type)
401 {
402 case G_TYPE_UINT:
403 g_value_set_uint(&instance_and_params[i], va_arg(extra_args, guint));
404 break;
405 case G_TYPE_UINT64:
406 g_value_set_uint64(&instance_and_params[i], va_arg(extra_args, guint64));
407 break;
408 case G_TYPE_STRING:
409 g_value_set_string(&instance_and_params[i], va_arg(extra_args, const char *));
410 break;
411 case G_TYPE_INT:
412 g_value_set_int(&instance_and_params[i], va_arg(extra_args, int));
413 break;
414 case G_TYPE_POINTER:
415 g_value_set_pointer(&instance_and_params[i], va_arg(extra_args, void *));
416 break;
417 default:
418 fprintf(stderr, "error: unsupported parameter type `%s' for signal `%s'\n",
419 g_type_name(type), signal_description->name);
420 va_end(extra_args);
421 for(int j = 0; j <= i; j++) g_value_unset(&instance_and_params[j]);
422 dt_free(instance_and_params);
423 dt_free(params);
424 return;
425 }
426 }
427
428 va_end(extra_args);
429
430 params->instance_and_params = instance_and_params;
431 params->signal_id = g_signal_lookup(_signal_description[signal].name, _signal_type);
432 params->n_params = signal_description->n_params;
433
434 if(!signal_description->synchronous)
435 {
436 g_main_context_invoke_full(NULL, G_PRIORITY_DEFAULT, _signal_emit, params, _signal_param_cleanup);
437 }
438 else
439 {
440 if(pthread_equal(darktable.control->gui_thread, pthread_self()))
441 {
442 _signal_emit(params);
443 _signal_param_cleanup(params);
444 }
445 else
446 {
447 async_com_data communication;
448 g_mutex_init(&communication.end_mutex);
449 g_cond_init(&communication.end_cond);
450 g_mutex_lock(&communication.end_mutex);
451 communication.user_data = params;
452 g_main_context_invoke(NULL,_async_com_callback,&communication);
453 g_cond_wait(&communication.end_cond,&communication.end_mutex);
454 g_mutex_unlock(&communication.end_mutex);
455 g_mutex_clear(&communication.end_mutex);
456 }
457 }
458}
459
460void dt_control_signal_connect(const dt_control_signal_t *ctlsig, dt_signal_t signal, GCallback cb,
461 gpointer user_data)
462{
464 {
465 dt_print(DT_DEBUG_SIGNAL, "[signal] connected: %s\n", _signal_description[signal].name);
466 _print_trace("connect");
467 }
468 g_signal_connect(G_OBJECT(ctlsig->sink), _signal_description[signal].name, G_CALLBACK(cb), user_data);
469}
470
471void dt_control_signal_disconnect(const struct dt_control_signal_t *ctlsig, GCallback cb, gpointer user_data)
472{
474 {
475 dt_print(DT_DEBUG_SIGNAL, "[signal] disconnected\n");
476 _print_trace("disconnect");
477 }
478 g_signal_handlers_disconnect_matched(G_OBJECT(ctlsig->sink), G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0,
479 0, NULL, cb, user_data);
480}
481
482void dt_control_signal_disconnect_all(const struct dt_control_signal_t *ctlsig, gpointer user_data)
483{
484 if(IS_NULL_PTR(ctlsig) || IS_NULL_PTR(user_data)) return;
486 {
487 dt_print(DT_DEBUG_SIGNAL, "[signal] disconnected all\n");
488 _print_trace("disconnect_all");
489 }
490 // G_SIGNAL_MATCH_DATA only: matches on user_data alone, across every signal id and callback
491 // function ever connected on this sink for that data -- the blanket variant of the (func, data)
492 // matched disconnect above.
493 g_signal_handlers_disconnect_matched(G_OBJECT(ctlsig->sink), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
494 user_data);
495}
496
497void dt_control_signal_block_by_func(const struct dt_control_signal_t *ctlsig, GCallback cb, gpointer user_data)
498{
499 g_signal_handlers_block_by_func(G_OBJECT(ctlsig->sink), cb, user_data);
500}
501
502void dt_control_signal_unblock_by_func(const struct dt_control_signal_t *ctlsig, GCallback cb, gpointer user_data)
503{
504 g_signal_handlers_unblock_by_func(G_OBJECT(ctlsig->sink), cb, user_data);
505}
506
507// clang-format off
508// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
509// vim: shiftwidth=2 expandtab tabstop=2 cindent
510// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
511// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
int type
char * name
int dt_control_running()
Definition control.c:433
darktable_t darktable
Definition darktable.c:183
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1600
@ DT_DEBUG_SIGNAL
Definition darktable.h:757
#define dt_free(ptr)
Definition darktable.h:478
static const dt_aligned_pixel_simd_t value
Definition darktable.h:599
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:293
float *const restrict const size_t k
size_t size
Definition mipmap_cache.c:3
static GType _signal_type
Definition signal.c:251
static GType file_crawling_arg[]
Definition signal.c:85
static GType int_arg[]
Definition signal.c:75
static dt_signal_description _signal_description[DT_SIGNAL_COUNT]
Definition signal.c:125
void dt_control_signal_raise(const dt_control_signal_t *ctlsig, dt_signal_t signal,...)
Definition signal.c:365
static void _image_info_changed_destroy_callback(gpointer instance, gpointer imgs, gpointer user_data)
Definition signal.c:100
static GType uint64_2arg[]
Definition signal.c:74
static void _collection_changed_destroy_callback(gpointer instance, int query_change, int changed_property, gpointer imgs, const int next, gpointer user_data)
Definition signal.c:89
static gboolean _signal_emit(gpointer user_data)
Definition signal.c:300
static GType pointer_arg[]
Definition signal.c:77
static GType pointer_2arg[]
Definition signal.c:78
void dt_control_signal_unblock_by_func(const struct dt_control_signal_t *ctlsig, GCallback cb, gpointer user_data)
Definition signal.c:502
static void _signal_param_cleanup(gpointer user_data)
Definition signal.c:307
void dt_control_signal_cleanup(dt_control_signal_t *ctlsig)
Definition signal.c:286
static GType image_export_arg[]
Definition signal.c:81
static GType collection_args[]
Definition signal.c:79
static void _print_trace(const char *op)
Definition signal.c:344
dt_control_signal_t * dt_control_signal_init()
Definition signal.c:253
static GType mask_change_arg[]
Definition signal.c:86
static void _image_geotag_destroy_callback(gpointer instance, gpointer imgs, const int locid, gpointer user_data)
Definition signal.c:116
void dt_control_signal_disconnect_all(const struct dt_control_signal_t *ctlsig, gpointer user_data)
Definition signal.c:482
gboolean _async_com_callback(gpointer data)
Definition signal.c:332
static void _presets_changed_destroy_callback(gpointer instance, gpointer module, gpointer user_data)
Definition signal.c:110
void dt_control_signal_disconnect(const struct dt_control_signal_t *ctlsig, GCallback cb, gpointer user_data)
Definition signal.c:471
static GType history_will_change_arg[]
Definition signal.c:83
static GType uint_arg[]
Definition signal.c:73
static GType uint_2arg[]
Definition signal.c:76
static GType geotag_arg[]
Definition signal.c:84
void dt_control_signal_block_by_func(const struct dt_control_signal_t *ctlsig, GCallback cb, gpointer user_data)
Definition signal.c:497
void dt_control_signal_connect(const dt_control_signal_t *ctlsig, dt_signal_t signal, GCallback cb, gpointer user_data)
Definition signal.c:460
@ DT_DEBUG_SIGNAL_ACT_DISCONNECT
Definition signal.h:341
@ DT_DEBUG_SIGNAL_ACT_CONNECT
Definition signal.h:340
@ DT_DEBUG_SIGNAL_ACT_RAISE
Definition signal.h:339
@ DT_DEBUG_SIGNAL_ACT_PRINT_TRACE
Definition signal.h:342
dt_signal_t
enum of signals to listen for in darktable.
Definition signal.h:54
@ DT_SIGNAL_COUNT
Definition signal.h:333
guint signal_id
Definition signal.c:296
guint n_params
Definition signal.c:297
GValue * instance_and_params
Definition signal.c:295
GCond end_cond
Definition signal.c:327
GMutex end_mutex
Definition signal.c:328
gpointer user_data
Definition signal.c:329
int32_t unmuted_signal_dbg_acts
Definition darktable.h:858
gboolean unmuted_signal_dbg[DT_SIGNAL_COUNT]
Definition darktable.h:859
struct dt_control_t * control
Definition darktable.h:801
GObject * sink
Definition signal.c:52
pthread_t gui_thread
Definition control.h:219
const char * name
Definition signal.c:61
gpointer accu_data
Definition signal.c:63
GSignalCMarshaller c_marshaller
Definition signal.c:65
GType * param_types
Definition signal.c:67
GSignalAccumulator accumulator
Definition signal.c:62
GCallback destructor
Definition signal.c:68
gboolean synchronous
Definition signal.c:69