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_arg[] = { 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, 1, uint64_arg, NULL,
179 FALSE }, // DT_SIGNAL_CACHELINE_READY
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-metadata-update", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
227 FALSE }, // DT_SIGNAL_METADATA_UPDATE
228
229 { "dt-location-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 1, pointer_arg, NULL,
230 TRUE }, // DT_SIGNAL_LOCATION_CHANGED
231
232 { "dt-mask-selection-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 2, pointer_2arg, NULL,
233 TRUE }, // DT_SIGNAL_MASK_SELECTION_CHANGED
234 { "dt-mask-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 3, mask_change_arg, NULL,
235 FALSE }, //DT_SIGNAL_MASK_CHANGED
236 { "dt-mask-shape-buttons-deactivate", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 1, pointer_arg, NULL,
237 FALSE }, // DT_SIGNAL_MASK_SHAPE_BUTTONS_DEACTIVATE
238 { "dt-develop-masks-gui-changed", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_VOID__VOID, 0, NULL, NULL,
239 FALSE }, // DT_SIGNAL_DEVELOP_MASKS_GUI_CHANGED
240
241 { "dt-control-filelist-update", NULL, NULL, G_TYPE_NONE, g_cclosure_marshal_generic, 3, file_crawling_arg, NULL,
242 TRUE }, // DT_SIGNAL_FILELIST_UPDATED: synchronous so crawler-owned pointers stay valid until handlers return.
243};
244
245static GType _signal_type;
246
248{
249 dt_control_signal_t *ctlsig = g_malloc0(sizeof(dt_control_signal_t));
250
251 /* setup dummy gobject typeinfo */
252 GTypeQuery query;
253 GTypeInfo type_info = { 0, (GBaseInitFunc)NULL, (GBaseFinalizeFunc)NULL, (GClassInitFunc)NULL,
254 (GClassFinalizeFunc)NULL, NULL, 0, 0, (GInstanceInitFunc)NULL };
255
256 g_type_query(G_TYPE_OBJECT, &query);
257 type_info.class_size = query.class_size;
258 type_info.instance_size = query.instance_size;
259 _signal_type = g_type_register_static(G_TYPE_OBJECT, "DarktableSignals", &type_info, 0);
260
261 /* create our pretty empty gobject */
262 ctlsig->sink = g_object_new(_signal_type, NULL);
263
264 /* create the signals */
265 for(int k = 0; k < DT_SIGNAL_COUNT; k++)
266 {
267 g_signal_newv(_signal_description[k].name, _signal_type, G_SIGNAL_RUN_LAST, 0,
268 _signal_description[k].accumulator, _signal_description[k].accu_data,
269 _signal_description[k].c_marshaller, _signal_description[k].return_type,
270 _signal_description[k].n_params, _signal_description[k].param_types);
271 if(_signal_description[k].destructor)
272 {
273 g_signal_connect_after(G_OBJECT(ctlsig->sink), _signal_description[k].name,
275 }
276 }
277 return ctlsig;
278}
279
281{
282 if(IS_NULL_PTR(ctlsig)) return;
283 if(!IS_NULL_PTR(ctlsig->sink)) g_object_unref(ctlsig->sink);
284 dt_free(ctlsig);
285}
286
293
294static gboolean _signal_emit(gpointer user_data)
295{
296 _signal_param_t *params = (_signal_param_t *)user_data;
297 g_signal_emitv(params->instance_and_params, params->signal_id, 0, NULL);
298 return G_SOURCE_REMOVE;
299}
300
301static void _signal_param_cleanup(gpointer user_data)
302{
303 _signal_param_t *params = (_signal_param_t *)user_data;
304 if(IS_NULL_PTR(params)) return;
305 // We iterate over the whole emitted argument vector (instance at index 0 + signal params)
306 // and only unset slots that currently hold a valid GValue type.
307 for(int i = 0; i <= params->n_params; i++)
308 {
309 GValue *value = &params->instance_and_params[i];
310 const GType value_type = G_VALUE_TYPE(value);
311 if(value_type == G_TYPE_INVALID) continue;
312 if(!g_type_check_is_value_type(value_type)) continue;
313 g_value_unset(value);
314 }
315 dt_free(params->instance_and_params);
316 dt_free(params);
317}
318
319typedef struct async_com_data
320{
321 GCond end_cond;
322 GMutex end_mutex;
323 gpointer user_data;
325
326gboolean _async_com_callback(gpointer data)
327{
328 async_com_data *communication = (async_com_data*)data;
329 g_mutex_lock(&communication->end_mutex);
330 _signal_emit(communication->user_data);
331 _signal_param_cleanup(communication->user_data);
332
333 g_cond_signal(&communication->end_cond);
334 g_mutex_unlock(&communication->end_mutex);
335 return FALSE;
336}
337
338static void _print_trace (const char* op)
339{
340#ifdef DT_HAVE_SIGNAL_TRACE
342 {
343 void *array[10];
344 size_t size;
345 char **strings;
346 size_t i;
347
348 size = backtrace (array, 10);
349 strings = backtrace_symbols (array, size);
350
351 for (i = 0; i < size; i++)
352 dt_print(DT_DEBUG_SIGNAL, "[signal-trace-%s]: %s\n", op, strings[i]);
353
354 dt_free(strings);
355 }
356#endif
357}
358
360{
361 // ignore all signals on shutdown
362 if(!dt_control_running()) return;
363
364 dt_signal_description *signal_description = &_signal_description[signal];
365
366 _signal_param_t *params = (_signal_param_t *)malloc(sizeof(_signal_param_t));
367 if(IS_NULL_PTR(params)) return;
368
369 GValue *instance_and_params = calloc(1 + signal_description->n_params, sizeof(GValue));
370 if(IS_NULL_PTR(instance_and_params))
371 {
372 dt_free(params);
373 return;
374 }
375
377 {
378 dt_print(DT_DEBUG_SIGNAL, "[signal] raised: %s\n", signal_description->name);
379 _print_trace("raise");
380 }
381
382 // 0th element has to be the instance to call
383 g_value_init(instance_and_params, _signal_type);
384 g_value_set_object(instance_and_params, ctlsig->sink);
385
386 // the rest of instance_and_params will be the params for the callback
387 va_list extra_args;
388 va_start(extra_args, signal);
389
390 for(int i = 1; i <= signal_description->n_params; i++)
391 {
392 GType type = signal_description->param_types[i-1];
393 g_value_init(&instance_and_params[i], type);
394 switch(type)
395 {
396 case G_TYPE_UINT:
397 g_value_set_uint(&instance_and_params[i], va_arg(extra_args, guint));
398 break;
399 case G_TYPE_UINT64:
400 g_value_set_uint64(&instance_and_params[i], va_arg(extra_args, guint64));
401 break;
402 case G_TYPE_STRING:
403 g_value_set_string(&instance_and_params[i], va_arg(extra_args, const char *));
404 break;
405 case G_TYPE_INT:
406 g_value_set_int(&instance_and_params[i], va_arg(extra_args, int));
407 break;
408 case G_TYPE_POINTER:
409 g_value_set_pointer(&instance_and_params[i], va_arg(extra_args, void *));
410 break;
411 default:
412 fprintf(stderr, "error: unsupported parameter type `%s' for signal `%s'\n",
413 g_type_name(type), signal_description->name);
414 va_end(extra_args);
415 for(int j = 0; j <= i; j++) g_value_unset(&instance_and_params[j]);
416 dt_free(instance_and_params);
417 dt_free(params);
418 return;
419 }
420 }
421
422 va_end(extra_args);
423
424 params->instance_and_params = instance_and_params;
425 params->signal_id = g_signal_lookup(_signal_description[signal].name, _signal_type);
426 params->n_params = signal_description->n_params;
427
428 if(!signal_description->synchronous)
429 {
430 g_main_context_invoke_full(NULL, G_PRIORITY_DEFAULT, _signal_emit, params, _signal_param_cleanup);
431 }
432 else
433 {
434 if(pthread_equal(darktable.control->gui_thread, pthread_self()))
435 {
436 _signal_emit(params);
437 _signal_param_cleanup(params);
438 }
439 else
440 {
441 async_com_data communication;
442 g_mutex_init(&communication.end_mutex);
443 g_cond_init(&communication.end_cond);
444 g_mutex_lock(&communication.end_mutex);
445 communication.user_data = params;
446 g_main_context_invoke(NULL,_async_com_callback,&communication);
447 g_cond_wait(&communication.end_cond,&communication.end_mutex);
448 g_mutex_unlock(&communication.end_mutex);
449 g_mutex_clear(&communication.end_mutex);
450 }
451 }
452}
453
454void dt_control_signal_connect(const dt_control_signal_t *ctlsig, dt_signal_t signal, GCallback cb,
455 gpointer user_data)
456{
458 {
459 dt_print(DT_DEBUG_SIGNAL, "[signal] connected: %s\n", _signal_description[signal].name);
460 _print_trace("connect");
461 }
462 g_signal_connect(G_OBJECT(ctlsig->sink), _signal_description[signal].name, G_CALLBACK(cb), user_data);
463}
464
465void dt_control_signal_disconnect(const struct dt_control_signal_t *ctlsig, GCallback cb, gpointer user_data)
466{
468 {
469 dt_print(DT_DEBUG_SIGNAL, "[signal] disconnected\n");
470 _print_trace("disconnect");
471 }
472 g_signal_handlers_disconnect_matched(G_OBJECT(ctlsig->sink), G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0,
473 0, NULL, cb, user_data);
474}
475
476void dt_control_signal_block_by_func(const struct dt_control_signal_t *ctlsig, GCallback cb, gpointer user_data)
477{
478 g_signal_handlers_block_by_func(G_OBJECT(ctlsig->sink), cb, user_data);
479}
480
481void dt_control_signal_unblock_by_func(const struct dt_control_signal_t *ctlsig, GCallback cb, gpointer user_data)
482{
483 g_signal_handlers_unblock_by_func(G_OBJECT(ctlsig->sink), cb, user_data);
484}
485
486// clang-format off
487// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
488// vim: shiftwidth=2 expandtab tabstop=2 cindent
489// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
490// 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:423
darktable_t darktable
Definition darktable.c:181
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
@ DT_DEBUG_SIGNAL
Definition darktable.h:735
#define dt_free(ptr)
Definition darktable.h:456
static const dt_aligned_pixel_simd_t value
Definition darktable.h:577
#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:281
float *const restrict const size_t k
size_t size
Definition mipmap_cache.c:3
static GType _signal_type
Definition signal.c:245
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:359
static void _image_info_changed_destroy_callback(gpointer instance, gpointer imgs, gpointer user_data)
Definition signal.c:100
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:294
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:481
static void _signal_param_cleanup(gpointer user_data)
Definition signal.c:301
void dt_control_signal_cleanup(dt_control_signal_t *ctlsig)
Definition signal.c:280
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:338
dt_control_signal_t * dt_control_signal_init()
Definition signal.c:247
static GType uint64_arg[]
Definition signal.c:74
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
gboolean _async_com_callback(gpointer data)
Definition signal.c:326
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:465
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:476
void dt_control_signal_connect(const dt_control_signal_t *ctlsig, dt_signal_t signal, GCallback cb, gpointer user_data)
Definition signal.c:454
@ DT_DEBUG_SIGNAL_ACT_DISCONNECT
Definition signal.h:327
@ DT_DEBUG_SIGNAL_ACT_CONNECT
Definition signal.h:326
@ DT_DEBUG_SIGNAL_ACT_RAISE
Definition signal.h:325
@ DT_DEBUG_SIGNAL_ACT_PRINT_TRACE
Definition signal.h:328
dt_signal_t
enum of signals to listen for in darktable.
Definition signal.h:54
@ DT_SIGNAL_COUNT
Definition signal.h:319
guint signal_id
Definition signal.c:290
guint n_params
Definition signal.c:291
GValue * instance_and_params
Definition signal.c:289
GCond end_cond
Definition signal.c:321
GMutex end_mutex
Definition signal.c:322
gpointer user_data
Definition signal.c:323
int32_t unmuted_signal_dbg_acts
Definition darktable.h:830
gboolean unmuted_signal_dbg[DT_SIGNAL_COUNT]
Definition darktable.h:831
struct dt_control_t * control
Definition darktable.h:773
GObject * sink
Definition signal.c:52
pthread_t gui_thread
Definition control.h:215
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