Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
progress.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2014, 2016-2017 Tobias Ellinghaus.
4 Copyright (C) 2015 Roman Lebedev.
5 Copyright (C) 2016 parafin.
6 Copyright (C) 2019-2020 Pascal Obry.
7 Copyright (C) 2021 Ralf Brown.
8 Copyright (C) 2022-2023 Aurélien PIERRE.
9 Copyright (C) 2022 Martin Bařinka.
10 Copyright (C) 2025 Hubert Figuière.
11
12 darktable is free software: you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
16
17 darktable is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with darktable. If not, see <http://www.gnu.org/licenses/>.
24*/
25
26#include "common/darktable.h"
27#include "common/dbus.h"
28#include "control/progress.h"
29#include "control/control.h"
30
31#ifdef MAC_INTEGRATION
32#include <gtkosxapplication.h>
33#endif
34
35#ifdef _WIN32
36#include <gdk/gdkwin32.h>
37#ifndef ITaskbarList3_SetProgressValue
38 #define ITaskbarList3_SetProgressValue(This,hwnd,ullCompleted,ullTotal) (This)->lpVtbl->SetProgressValue(This,hwnd,ullCompleted,ullTotal)
39#endif
40#ifndef ITaskbarList3_SetProgressState
41 #define ITaskbarList3_SetProgressState(This,hwnd,tbpFlags) (This)->lpVtbl->SetProgressState(This,hwnd,tbpFlags)
42#endif
43#ifndef ITaskbarList3_HrInit
44 #define ITaskbarList3_HrInit(This) (This)->lpVtbl->HrInit(This)
45#endif
46#endif
47
48
49typedef struct _dt_progress_t
50{
51 double progress;
52 gchar *message;
54 dt_pthread_mutex_t mutex;
55 void *gui_data;
56
57 // cancel callback and its data
60
62
63static void global_progress_start(dt_control_t *control, dt_progress_t *progress)
64{
66
67#ifndef _WIN32
68 // this should work for unity as well as kde
69 // https://wiki.ubuntu.com/Unity/LauncherAPI#Low_level_DBus_API:_com.canonical.Unity.LauncherEntry
71 {
72 GError *error = NULL;
73 g_object_ref(G_OBJECT(darktable.dbus->dbus_connection));
74
75 GVariantBuilder builder;
76 g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
77 g_variant_builder_add(&builder, "{sv}", "progress", g_variant_new_double(control->progress_system.global_progress));
78 g_variant_builder_add(&builder, "{sv}", "progress-visible", g_variant_new_boolean(TRUE));
79 GVariant *params = g_variant_new("(sa{sv})", "application://photos.ansel.ansel.desktop", &builder);
80
81 g_dbus_connection_emit_signal(darktable.dbus->dbus_connection,
82 "com.canonical.Unity",
83 "/darktable",
84 "com.canonical.Unity.LauncherEntry",
85 "Update",
86 params,
87 &error);
88 if(error)
89 {
90 fprintf(stderr, "[progress_create] dbus error: %s\n", error->message);
91 g_error_free(error);
92 }
93 }
94
95#else // _WIN32
96
97 // we can't init this in dt_control_progress_init as it's run too early :/
98 if(!control->progress_system.taskbarlist)
99 {
100 void *taskbarlist;
101 if(CoCreateInstance(&CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, &IID_ITaskbarList3, (void **)&taskbarlist) == S_OK)
102 if(ITaskbarList3_HrInit((ITaskbarList3 *)taskbarlist) == S_OK)
103 control->progress_system.taskbarlist = taskbarlist;
104 }
105
106 if(control->progress_system.taskbarlist)
107 {
108 HWND hwnd = GDK_WINDOW_HWND(gtk_widget_get_window(dt_ui_main_window(darktable.gui->ui)));
109 if(ITaskbarList3_SetProgressState(control->progress_system.taskbarlist, hwnd, TBPF_NORMAL) != S_OK)
110 fprintf(stderr, "[progress_create] SetProgressState failed\n");
111 if(ITaskbarList3_SetProgressValue(control->progress_system.taskbarlist, hwnd, control->progress_system.global_progress * 100, 100) != S_OK)
112 fprintf(stderr, "[progress_create] SetProgressValue failed\n");
113 }
114
115#endif
116}
117
118static void global_progress_set(dt_control_t *control, dt_progress_t *progress, double value)
119{
121
122#ifndef _WIN32
123
125 {
126 GError *error = NULL;
127
128 GVariantBuilder builder;
129 g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
130 g_variant_builder_add(&builder, "{sv}", "progress", g_variant_new_double(control->progress_system.global_progress));
131 GVariant *params = g_variant_new("(sa{sv})", "application://photos.ansel.ansel.desktop", &builder);
132
133 g_dbus_connection_emit_signal(darktable.dbus->dbus_connection,
134 "com.canonical.Unity",
135 "/darktable",
136 "com.canonical.Unity.LauncherEntry",
137 "Update",
138 params,
139 &error);
140 if(error)
141 {
142 fprintf(stderr, "[progress_set] dbus error: %s\n", error->message);
143 g_error_free(error);
144 }
145 }
146
147#else // _WIN32
148
149 if(control->progress_system.taskbarlist)
150 {
151 HWND hwnd = GDK_WINDOW_HWND(gtk_widget_get_window(dt_ui_main_window(darktable.gui->ui)));
152 if(ITaskbarList3_SetProgressValue(control->progress_system.taskbarlist, hwnd, control->progress_system.global_progress * 100, 100) != S_OK)
153 fprintf(stderr, "[progress_create] SetProgressValue failed\n");
154 }
155
156#endif
157}
158
159static void global_progress_end(dt_control_t *control, dt_progress_t *progress)
160{
162
163 // find the biggest progress value among the remaining progress bars
164 control->progress_system.global_progress = 0.0;
165 for(GList *iter = control->progress_system.list; iter; iter = g_list_next(iter))
166 {
167 // this is called after the current progress got removed from the list!
168 dt_progress_t *p = (dt_progress_t *)iter->data;
171 }
172
173#ifndef _WIN32
174
176 {
177 GError *error = NULL;
178
179 GVariantBuilder builder;
180 g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
181 if(control->progress_system.n_progress_bar == 0)
182 g_variant_builder_add(&builder, "{sv}", "progress-visible", g_variant_new_boolean(FALSE));
183 g_variant_builder_add(&builder, "{sv}", "progress", g_variant_new_double(control->progress_system.global_progress));
184 GVariant *params = g_variant_new("(sa{sv})", "application://photos.ansel.ansel.desktop", &builder);
185
186 g_dbus_connection_emit_signal(darktable.dbus->dbus_connection,
187 "com.canonical.Unity",
188 "/darktable",
189 "com.canonical.Unity.LauncherEntry",
190 "Update",
191 params,
192 &error);
193 if(error)
194 {
195 fprintf(stderr, "[progress_destroy] dbus error: %s\n", error->message);
196 g_error_free(error);
197 }
198
199 g_object_unref(G_OBJECT(darktable.dbus->dbus_connection));
201 }
202
203#else // _WIN32
204
205 if(control->progress_system.taskbarlist)
206 {
207 HWND hwnd = GDK_WINDOW_HWND(gtk_widget_get_window(dt_ui_main_window(darktable.gui->ui)));
208 if(control->progress_system.n_progress_bar == 0)
209 {
210 if(ITaskbarList3_SetProgressState(control->progress_system.taskbarlist, hwnd, TBPF_NOPROGRESS) != S_OK)
211 fprintf(stderr, "[progress_create] SetProgressState failed\n");
212 }
213 else
214 {
215 if(ITaskbarList3_SetProgressValue(control->progress_system.taskbarlist, hwnd,
216 control->progress_system.global_progress * 100, 100) != S_OK)
217 fprintf(stderr, "[progress_create] SetProgressValue failed\n");
218 }
219 }
220
221#endif
222}
223
225{
226#ifndef _WIN32
227
229 {
230 GError *error = NULL;
231
232 GVariantBuilder builder;
233 g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
234 g_variant_builder_add(&builder, "{sv}", "progress-visible", g_variant_new_boolean(FALSE));
235 GVariant *params = g_variant_new("(sa{sv})", "application://photos.ansel.ansel.desktop", &builder);
236
237 g_dbus_connection_emit_signal(darktable.dbus->dbus_connection,
238 "com.canonical.Unity",
239 "/darktable",
240 "com.canonical.Unity.LauncherEntry",
241 "Update",
242 params,
243 &error);
244 if(error)
245 {
246 fprintf(stderr, "[progress_init] dbus error: %s\n", error->message);
247 g_error_free(error);
248 }
249
250 g_object_unref(G_OBJECT(darktable.dbus->dbus_connection));
252 }
253
254#else // _WIN32
255
256 // initializing control->progress_system.taskbarlist in here doesn't work,
257 // it seems to only succeed after dt_gui_gtk_init
258
259#endif // _WIN32
260}
261
262dt_progress_t *dt_control_progress_create(dt_control_t *control, gboolean has_progress_bar,
263 const gchar *message)
264{
265 // create the object
266 dt_progress_t *progress = (dt_progress_t *)calloc(1, sizeof(dt_progress_t));
267 dt_pthread_mutex_init(&(progress->mutex), NULL);
268
269 // fill it with values
270 progress->message = g_strdup(message);
271 progress->has_progress_bar = has_progress_bar;
272
274
275 // add it to the global list
276 control->progress_system.list = g_list_append(control->progress_system.list, progress);
277 control->progress_system.list_length++;
278 if(has_progress_bar) global_progress_start(control, progress);
279
280 // tell the gui
281 if(!IS_NULL_PTR(control->progress_system.proxy.module))
282 progress->gui_data = control->progress_system.proxy.added(control->progress_system.proxy.module,
283 has_progress_bar, message);
284
286
287 return progress;
288}
289
291{
293
294 // tell the gui
295 if(!IS_NULL_PTR(control->progress_system.proxy.module))
296 control->progress_system.proxy.destroyed(control->progress_system.proxy.module, progress->gui_data);
297
298 // remove the object from the global list
299 control->progress_system.list = g_list_remove(control->progress_system.list, progress);
300 control->progress_system.list_length--;
301 if(progress->has_progress_bar) global_progress_end(control, progress);
302
304
305 // free the object
307 dt_free(progress->message);
308 dt_free(progress);
309}
310
312 dt_progress_cancel_callback_t cancel, void *data)
313{
314 // set the value
315 dt_pthread_mutex_lock(&progress->mutex);
316 progress->cancel = cancel;
317 progress->cancel_data = data;
318 dt_pthread_mutex_unlock(&progress->mutex);
319
320 // tell the gui
322 if(!IS_NULL_PTR(control->progress_system.proxy.module))
323 control->progress_system.proxy.cancellable(control->progress_system.proxy.module, progress->gui_data,
324 progress);
326}
327
328static void dt_control_progress_cancel_callback(dt_progress_t *progress, void *data)
329{
331}
332
337
339{
340 dt_pthread_mutex_lock(&progress->mutex);
341 if(IS_NULL_PTR(progress->cancel))
342 {
343 dt_pthread_mutex_unlock(&progress->mutex);
344 return;
345 }
346
347 // call the cancel callback
348 progress->cancel(progress, progress->cancel_data);
349
350 dt_pthread_mutex_unlock(&progress->mutex);
351
352 // the gui doesn't need to know I guess, it wouldn't to anything with that bit of information
353}
354
356{
357 // set the value
358 value = CLAMP(value, 0.0, 1.0);
359 dt_pthread_mutex_lock(&progress->mutex);
360 progress->progress = value;
361 dt_pthread_mutex_unlock(&progress->mutex);
362
363 // tell the gui
365 if(!IS_NULL_PTR(control->progress_system.proxy.module))
366 control->progress_system.proxy.updated(control->progress_system.proxy.module, progress->gui_data, value);
367
368 if(progress->has_progress_bar) global_progress_set(control, progress, value);
369
371}
372
374{
375 dt_pthread_mutex_lock(&progress->mutex);
376 double res = progress->progress;
377 dt_pthread_mutex_unlock(&progress->mutex);
378 return res;
379}
380
382{
383 dt_pthread_mutex_lock(&progress->mutex);
384 const gchar *res = progress->message;
385 dt_pthread_mutex_unlock(&progress->mutex);
386 return res;
387}
388
389void dt_control_progress_set_message(dt_control_t *control, dt_progress_t *progress, const char *message)
390{
391 dt_pthread_mutex_lock(&progress->mutex);
392 dt_free(progress->message);
393 progress->message = g_strdup(message);
394 dt_pthread_mutex_unlock(&progress->mutex);
395
396 // tell the gui
398 if(!IS_NULL_PTR(control->progress_system.proxy.module))
399 control->progress_system.proxy.message_updated(control->progress_system.proxy.module, progress->gui_data,
400 message);
402}
403
405{
406 dt_pthread_mutex_lock(&progress->mutex);
407 progress->gui_data = data;
408 dt_pthread_mutex_unlock(&progress->mutex);
409}
410
412{
413 dt_pthread_mutex_lock(&progress->mutex);
414 void *res = progress->gui_data;
415 dt_pthread_mutex_unlock(&progress->mutex);
416 return res;
417}
418
420{
421 dt_pthread_mutex_lock(&progress->mutex);
422 gboolean res = progress->has_progress_bar;
423 dt_pthread_mutex_unlock(&progress->mutex);
424 return res;
425}
426
428{
429 dt_pthread_mutex_lock(&progress->mutex);
430 gboolean res = !IS_NULL_PTR(progress->cancel);
431 dt_pthread_mutex_unlock(&progress->mutex);
432 return res;
433}
434
435// clang-format off
436// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
437// vim: shiftwidth=2 expandtab tabstop=2 cindent
438// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
439// clang-format on
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
darktable_t darktable
Definition darktable.c:181
#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
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:374
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Definition dtpthread.h:359
static int dt_pthread_mutex_destroy(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:379
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:364
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
void dt_control_job_cancel(_dt_job_t *job)
Definition jobs.c:180
void dt_control_progress_set_progress(dt_control_t *control, dt_progress_t *progress, double value)
Definition progress.c:355
static void dt_control_progress_cancel_callback(dt_progress_t *progress, void *data)
Definition progress.c:328
void dt_control_progress_set_message(dt_control_t *control, dt_progress_t *progress, const char *message)
Definition progress.c:389
double dt_control_progress_get_progress(dt_progress_t *progress)
Definition progress.c:373
gboolean dt_control_progress_cancellable(dt_progress_t *progress)
Definition progress.c:427
const gchar * dt_control_progress_get_message(dt_progress_t *progress)
Definition progress.c:381
static void global_progress_set(dt_control_t *control, dt_progress_t *progress, double value)
Definition progress.c:118
static void global_progress_start(dt_control_t *control, dt_progress_t *progress)
Definition progress.c:63
void dt_control_progress_make_cancellable(struct dt_control_t *control, dt_progress_t *progress, dt_progress_cancel_callback_t cancel, void *data)
Definition progress.c:311
dt_progress_t * dt_control_progress_create(dt_control_t *control, gboolean has_progress_bar, const gchar *message)
Definition progress.c:262
void dt_control_progress_init(struct dt_control_t *control)
Definition progress.c:224
void dt_control_progress_destroy(dt_control_t *control, dt_progress_t *progress)
Definition progress.c:290
void dt_control_progress_set_gui_data(dt_progress_t *progress, void *data)
Definition progress.c:404
void dt_control_progress_cancel(dt_control_t *control, dt_progress_t *progress)
Definition progress.c:338
void dt_control_progress_attach_job(dt_control_t *control, dt_progress_t *progress, dt_job_t *job)
Definition progress.c:333
static void global_progress_end(dt_control_t *control, dt_progress_t *progress)
Definition progress.c:159
gboolean dt_control_progress_has_progress_bar(dt_progress_t *progress)
Definition progress.c:419
void * dt_control_progress_get_gui_data(dt_progress_t *progress)
Definition progress.c:411
void(* dt_progress_cancel_callback_t)(dt_progress_t *progress, void *data)
Definition progress.h:31
gchar * message
Definition progress.c:52
void * cancel_data
Definition progress.c:59
dt_progress_cancel_callback_t cancel
Definition progress.c:58
void * gui_data
Definition progress.c:55
dt_pthread_mutex_t mutex
Definition progress.c:54
double progress
Definition progress.c:51
gboolean has_progress_bar
Definition progress.c:53
struct dt_dbus_t * dbus
Definition darktable.h:786
struct dt_gui_gtk_t * gui
Definition darktable.h:775
dt_pthread_mutex_t mutex
Definition control.h:276
void(* destroyed)(dt_lib_module_t *self, struct dt_lib_backgroundjob_element_t *instance)
Definition control.h:287
struct dt_control_t::@13 progress_system
struct dt_control_t::@13::@15 proxy
GList * list
Definition control.h:272
void(* message_updated)(dt_lib_module_t *self, struct dt_lib_backgroundjob_element_t *instance, const char *message)
Definition control.h:291
void(* updated)(dt_lib_module_t *self, struct dt_lib_backgroundjob_element_t *instance, double value)
Definition control.h:290
dt_lib_module_t *void *(* added)(dt_lib_module_t *self, gboolean has_progress_bar, const gchar *message)
Definition control.h:286
size_t list_length
Definition control.h:273
double global_progress
Definition control.h:275
void(* cancellable)(dt_lib_module_t *self, struct dt_lib_backgroundjob_element_t *instance, dt_progress_t *progress)
Definition control.h:288
size_t n_progress_bar
Definition control.h:274
GDBusConnection * dbus_connection
Definition dbus.h:38
dt_ui_t * ui
Definition gtk.h:164
#define MAX(a, b)
Definition thinplate.c:29