1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3 * Libbrasero-burn
4 * Copyright (C) Philippe Rouquier 2005-2009 <bonfire-app@wanadoo.fr>
5 *
6 * Libbrasero-burn is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * The Libbrasero-burn authors hereby grant permission for non-GPL compatible
12 * GStreamer plugins to be used and distributed together with GStreamer
13 * and Libbrasero-burn. This permission is above and beyond the permissions granted
14 * by the GPL license by which Libbrasero-burn is covered. If you modify this code
15 * you may extend this exception to your version of the code, but you are not
16 * obligated to do so. If you do not wish to do so, delete this exception
17 * statement from your version.
18 *
19 * Libbrasero-burn is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to:
26 * The Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor
28 * Boston, MA 02110-1301, USA.
29 */
30
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34
35 #include <math.h>
36
37 #include <glib.h>
38 #include <glib-object.h>
39 #include <glib/gi18n-lib.h>
40
41 #include "burn-basics.h"
42 #include "brasero-session.h"
43 #include "brasero-session-helper.h"
44 #include "burn-debug.h"
45 #include "burn-task-ctx.h"
46
47 typedef struct _BraseroTaskCtxPrivate BraseroTaskCtxPrivate;
48 struct _BraseroTaskCtxPrivate
49 {
50 /* these two are set at creation time and can't be changed */
51 BraseroTaskAction action;
52 BraseroBurnSession *session;
53
54 GMutex *lock;
55
56 BraseroTrack *current_track;
57 GSList *tracks;
58
59 /* used to poll for progress (every 0.5 sec) */
60 gdouble progress;
61 goffset track_bytes;
62 goffset session_bytes;
63
64 goffset size;
65 goffset blocks;
66
67 /* keep track of time */
68 GTimer *timer;
69 goffset first_written;
70 gdouble first_progress;
71
72 /* used for immediate rate */
73 gdouble current_elapsed;
74 gdouble last_elapsed;
75
76 goffset last_written;
77 gdouble last_progress;
78
79 /* used for remaining time */
80 GSList *times;
81 gdouble total_time;
82
83 /* used for rates that certain jobs are able to report */
84 guint64 rate;
85
86 /* the current action */
87 BraseroBurnAction current_action;
88 gchar *action_string;
89
90 guint dangerous;
91
92 guint fake:1;
93 guint action_changed:1;
94 guint update_action_string:1;
95
96 guint written_changed:1;
97 guint progress_changed:1;
98 guint use_average_rate:1;
99 };
100
101 #define BRASERO_TASK_CTX_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_TASK_CTX, BraseroTaskCtxPrivate))
102
103 G_DEFINE_TYPE (BraseroTaskCtx, brasero_task_ctx, G_TYPE_OBJECT);
104
105 #define MAX_VALUE_AVERAGE 16
106
107 enum _BraseroTaskCtxSignalType {
108 ACTION_CHANGED_SIGNAL,
109 PROGRESS_CHANGED_SIGNAL,
110 LAST_SIGNAL
111 };
112 static guint brasero_task_ctx_signals [LAST_SIGNAL] = { 0 };
113
114 enum
115 {
116 PROP_0,
117 PROP_ACTION,
118 PROP_SESSION
119 };
120
121 static GObjectClass* parent_class = NULL;
122
123 void
brasero_task_ctx_set_dangerous(BraseroTaskCtx * self,gboolean value)124 brasero_task_ctx_set_dangerous (BraseroTaskCtx *self, gboolean value)
125 {
126 BraseroTaskCtxPrivate *priv;
127
128 priv = BRASERO_TASK_CTX_PRIVATE (self);
129 if (value)
130 priv->dangerous ++;
131 else
132 priv->dangerous --;
133 }
134
135 guint
brasero_task_ctx_get_dangerous(BraseroTaskCtx * self)136 brasero_task_ctx_get_dangerous (BraseroTaskCtx *self)
137 {
138 BraseroTaskCtxPrivate *priv;
139
140 priv = BRASERO_TASK_CTX_PRIVATE (self);
141 return priv->dangerous;
142 }
143
144 void
brasero_task_ctx_reset(BraseroTaskCtx * self)145 brasero_task_ctx_reset (BraseroTaskCtx *self)
146 {
147 BraseroTaskCtxPrivate *priv;
148 GSList *tracks;
149
150 priv = BRASERO_TASK_CTX_PRIVATE (self);
151
152 if (priv->tracks) {
153 g_slist_foreach (priv->tracks, (GFunc) g_object_unref, NULL);
154 g_slist_free (priv->tracks);
155 priv->tracks = NULL;
156 }
157
158 tracks = brasero_burn_session_get_tracks (priv->session);
159 BRASERO_BURN_LOG ("Setting current track (%i tracks)", g_slist_length (tracks));
160 if (priv->current_track)
161 g_object_unref (priv->current_track);
162
163 if (tracks) {
164 priv->current_track = tracks->data;
165 g_object_ref (priv->current_track);
166 }
167 else
168 BRASERO_BURN_LOG ("no tracks");
169
170 if (priv->timer) {
171 g_timer_destroy (priv->timer);
172 priv->timer = NULL;
173 }
174
175 priv->dangerous = 0;
176 priv->progress = -1.0;
177 priv->track_bytes = -1;
178 priv->session_bytes = -1;
179 priv->written_changed = 0;
180
181 priv->current_elapsed = 0;
182 priv->last_written = 0;
183 priv->last_elapsed = 0;
184 priv->last_progress = 0;
185
186 if (priv->times) {
187 g_slist_free (priv->times);
188 priv->times = NULL;
189 }
190
191 g_signal_emit (self,
192 brasero_task_ctx_signals [PROGRESS_CHANGED_SIGNAL],
193 0);
194 }
195
196 void
brasero_task_ctx_set_fake(BraseroTaskCtx * ctx,gboolean fake)197 brasero_task_ctx_set_fake (BraseroTaskCtx *ctx,
198 gboolean fake)
199 {
200 BraseroTaskCtxPrivate *priv;
201
202 priv = BRASERO_TASK_CTX_PRIVATE (ctx);
203 priv->fake = fake;
204 }
205
206 /**
207 * Used to get config
208 */
209
210 BraseroBurnSession *
brasero_task_ctx_get_session(BraseroTaskCtx * self)211 brasero_task_ctx_get_session (BraseroTaskCtx *self)
212 {
213 BraseroTaskCtxPrivate *priv;
214
215 g_return_val_if_fail (BRASERO_IS_TASK_CTX (self), NULL);
216
217 priv = BRASERO_TASK_CTX_PRIVATE (self);
218 if (!priv->session)
219 return NULL;
220
221 return priv->session;
222 }
223
224 BraseroBurnResult
brasero_task_ctx_get_stored_tracks(BraseroTaskCtx * self,GSList ** tracks)225 brasero_task_ctx_get_stored_tracks (BraseroTaskCtx *self,
226 GSList **tracks)
227 {
228 BraseroTaskCtxPrivate *priv;
229
230 priv = BRASERO_TASK_CTX_PRIVATE (self);
231 if (!priv->current_track)
232 return BRASERO_BURN_ERR;
233
234 if (tracks)
235 *tracks = priv->tracks;
236
237 /* If no track has been added let the caller
238 * know with BRASERO_BURN_NOT_READY */
239 if (!priv->tracks)
240 return BRASERO_BURN_NOT_READY;
241
242 return BRASERO_BURN_OK;
243 }
244
245 BraseroBurnResult
brasero_task_ctx_get_current_track(BraseroTaskCtx * self,BraseroTrack ** track)246 brasero_task_ctx_get_current_track (BraseroTaskCtx *self,
247 BraseroTrack **track)
248 {
249 BraseroTaskCtxPrivate *priv;
250
251 g_return_val_if_fail (track != NULL, BRASERO_BURN_ERR);
252
253 priv = BRASERO_TASK_CTX_PRIVATE (self);
254 if (!priv->current_track)
255 return BRASERO_BURN_ERR;
256
257 *track = priv->current_track;
258 return BRASERO_BURN_OK;
259 }
260
261 BraseroTaskAction
brasero_task_ctx_get_action(BraseroTaskCtx * self)262 brasero_task_ctx_get_action (BraseroTaskCtx *self)
263 {
264 BraseroTaskCtxPrivate *priv;
265
266 priv = BRASERO_TASK_CTX_PRIVATE (self);
267
268 if (priv->fake)
269 return BRASERO_TASK_ACTION_NONE;
270
271 return priv->action;
272 }
273
274 /**
275 * Used to report task status
276 */
277
278 BraseroBurnResult
brasero_task_ctx_add_track(BraseroTaskCtx * self,BraseroTrack * track)279 brasero_task_ctx_add_track (BraseroTaskCtx *self,
280 BraseroTrack *track)
281 {
282 BraseroTaskCtxPrivate *priv;
283
284 priv = BRASERO_TASK_CTX_PRIVATE (self);
285
286 BRASERO_BURN_LOG ("Adding track %s",
287 // brasero_track_get_track_type (track, NULL),
288 priv->tracks? "already some tracks":"");
289
290 /* Ref the track and store it for later. */
291 g_object_ref (track);
292 priv->tracks = g_slist_prepend (priv->tracks, track);
293 return BRASERO_BURN_OK;
294 }
295
296 static gboolean
brasero_task_ctx_set_next_track(BraseroTaskCtx * self)297 brasero_task_ctx_set_next_track (BraseroTaskCtx *self)
298 {
299 BraseroTaskCtxPrivate *priv;
300 GSList *tracks;
301 GSList *node;
302
303 priv = BRASERO_TASK_CTX_PRIVATE (self);
304
305 /* we need to set the next track if our action is NORMAL or CHECKSUM */
306 if (priv->action != BRASERO_TASK_ACTION_NORMAL
307 && priv->action != BRASERO_TASK_ACTION_CHECKSUM)
308 return BRASERO_BURN_OK;
309
310 /* see if there is another track left */
311 tracks = brasero_burn_session_get_tracks (priv->session);
312 node = g_slist_find (tracks, priv->current_track);
313 if (!node || !node->next)
314 return BRASERO_BURN_OK;
315
316 priv->session_bytes += priv->track_bytes;
317 priv->track_bytes = 0;
318 priv->last_written = 0;
319 priv->progress = 0;
320
321 if (priv->current_track)
322 g_object_unref (priv->current_track);
323
324 priv->current_track = node->next->data;
325 g_object_ref (priv->current_track);
326
327 return BRASERO_BURN_RETRY;
328 }
329
330 BraseroBurnResult
brasero_task_ctx_next_track(BraseroTaskCtx * self)331 brasero_task_ctx_next_track (BraseroTaskCtx *self)
332
333 {
334 BraseroBurnResult retval;
335
336 g_return_val_if_fail (BRASERO_IS_TASK_CTX (self), BRASERO_BURN_ERR);
337
338 retval = brasero_task_ctx_set_next_track (self);
339 if (retval == BRASERO_BURN_RETRY) {
340 BraseroTaskCtxClass *klass;
341
342 BRASERO_BURN_LOG ("Set next track to be processed");
343
344 klass = BRASERO_TASK_CTX_GET_CLASS (self);
345 if (!klass->finished)
346 return BRASERO_BURN_NOT_SUPPORTED;
347
348 klass->finished (self,
349 BRASERO_BURN_RETRY,
350 NULL);
351 return BRASERO_BURN_RETRY;
352 }
353
354 BRASERO_BURN_LOG ("No next track to process");
355 return BRASERO_BURN_OK;
356 }
357
358 BraseroBurnResult
brasero_task_ctx_finished(BraseroTaskCtx * self)359 brasero_task_ctx_finished (BraseroTaskCtx *self)
360 {
361 BraseroTaskCtxPrivate *priv;
362 BraseroTaskCtxClass *klass;
363 GError *error = NULL;
364 GSList *iter;
365
366 priv = BRASERO_TASK_CTX_PRIVATE (self);
367 klass = BRASERO_TASK_CTX_GET_CLASS (self);
368 if (!klass->finished)
369 return BRASERO_BURN_NOT_SUPPORTED;
370
371 klass->finished (self,
372 BRASERO_BURN_OK,
373 error);
374
375 if (priv->tracks) {
376 brasero_burn_session_push_tracks (priv->session);
377 priv->tracks = g_slist_reverse (priv->tracks);
378 for (iter = priv->tracks; iter; iter = iter->next) {
379 BraseroTrack *track;
380
381 track = iter->data;
382 brasero_burn_session_add_track (priv->session, track, NULL);
383
384 /* It's good practice to unref the track afterwards as
385 * we don't need it anymore. BraseroBurnSession refs it.
386 */
387 g_object_unref (track);
388 }
389
390 g_slist_free (priv->tracks);
391 priv->tracks = NULL;
392 }
393
394 return BRASERO_BURN_OK;
395 }
396
397 BraseroBurnResult
brasero_task_ctx_error(BraseroTaskCtx * self,BraseroBurnResult retval,GError * error)398 brasero_task_ctx_error (BraseroTaskCtx *self,
399 BraseroBurnResult retval,
400 GError *error)
401 {
402 BraseroTaskCtxClass *klass;
403
404 klass = BRASERO_TASK_CTX_GET_CLASS (self);
405 if (!klass->finished)
406 return BRASERO_BURN_NOT_SUPPORTED;
407
408 klass->finished (self,
409 retval,
410 error);
411
412 return BRASERO_BURN_OK;
413 }
414
415 BraseroBurnResult
brasero_task_ctx_start_progress(BraseroTaskCtx * self,gboolean force)416 brasero_task_ctx_start_progress (BraseroTaskCtx *self,
417 gboolean force)
418
419 {
420 BraseroTaskCtxPrivate *priv;
421
422 g_return_val_if_fail (BRASERO_IS_TASK_CTX (self), BRASERO_BURN_ERR);
423
424 priv = BRASERO_TASK_CTX_PRIVATE (self);
425
426 if (!priv->timer) {
427 priv->timer = g_timer_new ();
428 priv->first_written = priv->session_bytes + priv->track_bytes;
429 priv->first_progress = priv->progress;
430 }
431 else if (force) {
432 g_timer_start (priv->timer);
433 priv->first_written = priv->session_bytes + priv->track_bytes;
434 priv->first_progress = priv->progress;
435 }
436
437 return BRASERO_BURN_OK;
438 }
439
440 static gdouble
brasero_task_ctx_get_average(GSList ** values,gdouble value)441 brasero_task_ctx_get_average (GSList **values, gdouble value)
442 {
443 const unsigned int scale = 10000;
444 unsigned int num = 0;
445 gdouble average;
446 gint32 int_value;
447 GSList *l;
448
449 if (value * scale < G_MAXINT)
450 int_value = (gint32) ceil (scale * value);
451 else if (value / scale < G_MAXINT)
452 int_value = (gint32) ceil (-1.0 * value / scale);
453 else
454 return value;
455
456 *values = g_slist_prepend (*values, GINT_TO_POINTER (int_value));
457
458 average = 0;
459 for (l = *values; l; l = l->next) {
460 gdouble r = (gdouble) GPOINTER_TO_INT (l->data);
461
462 if (r < 0)
463 r *= scale * -1.0;
464 else
465 r /= scale;
466
467 average += r;
468 num++;
469 if (num == MAX_VALUE_AVERAGE && l->next)
470 l = g_slist_delete_link (l, l->next);
471 }
472
473 average /= num;
474 return average;
475 }
476
477 void
brasero_task_ctx_report_progress(BraseroTaskCtx * self)478 brasero_task_ctx_report_progress (BraseroTaskCtx *self)
479 {
480 BraseroTaskCtxPrivate *priv;
481 gdouble progress, elapsed;
482
483 priv = BRASERO_TASK_CTX_PRIVATE (self);
484
485 if (priv->action_changed) {
486 /* Give a last progress-changed signal
487 * setting previous action as completely
488 * finished only if the plugin set any
489 * progress for it.
490 * This helps having the tray icon or the
491 * taskbar icon set to be full on quick
492 * burns. */
493
494 if (priv->progress >= 0.0
495 || priv->track_bytes >= 0
496 || priv->session_bytes >= 0) {
497 goffset total = 0;
498
499 priv->progress = 1.0;
500 priv->track_bytes = 0;
501 brasero_task_ctx_get_session_output_size (self, NULL, &total);
502 priv->session_bytes = total;
503
504 g_signal_emit (self,
505 brasero_task_ctx_signals [PROGRESS_CHANGED_SIGNAL],
506 0);
507 }
508
509 g_signal_emit (self,
510 brasero_task_ctx_signals [ACTION_CHANGED_SIGNAL],
511 0,
512 priv->current_action);
513
514 brasero_task_ctx_reset_progress (self);
515 g_signal_emit (self,
516 brasero_task_ctx_signals [PROGRESS_CHANGED_SIGNAL],
517 0);
518
519 priv->action_changed = 0;
520 }
521 else if (priv->update_action_string) {
522 g_signal_emit (self,
523 brasero_task_ctx_signals [ACTION_CHANGED_SIGNAL],
524 0,
525 priv->current_action);
526
527 priv->update_action_string = 0;
528 }
529
530 if (priv->timer) {
531 elapsed = g_timer_elapsed (priv->timer, NULL);
532 if (brasero_task_ctx_get_progress (self, &progress) == BRASERO_BURN_OK) {
533 gdouble total_time;
534
535 total_time = (gdouble) elapsed / (gdouble) progress;
536
537 g_mutex_lock (priv->lock);
538 priv->total_time = brasero_task_ctx_get_average (&priv->times,
539 total_time);
540 g_mutex_unlock (priv->lock);
541 }
542 }
543
544 if (priv->progress_changed) {
545 priv->progress_changed = 0;
546 g_signal_emit (self,
547 brasero_task_ctx_signals [PROGRESS_CHANGED_SIGNAL],
548 0);
549 }
550 else if (priv->written_changed) {
551 priv->written_changed = 0;
552 g_signal_emit (self,
553 brasero_task_ctx_signals [PROGRESS_CHANGED_SIGNAL],
554 0);
555 }
556 }
557
558 BraseroBurnResult
brasero_task_ctx_set_rate(BraseroTaskCtx * self,gint64 rate)559 brasero_task_ctx_set_rate (BraseroTaskCtx *self,
560 gint64 rate)
561 {
562 BraseroTaskCtxPrivate *priv;
563
564 g_return_val_if_fail (BRASERO_IS_TASK_CTX (self), BRASERO_BURN_ERR);
565
566 priv = BRASERO_TASK_CTX_PRIVATE (self);
567 priv->rate = rate;
568 return BRASERO_BURN_OK;
569 }
570
571 /**
572 * This is used by jobs that are imaging to tell what's going to be the output
573 * size for a particular track
574 */
575
576 BraseroBurnResult
brasero_task_ctx_set_output_size_for_current_track(BraseroTaskCtx * self,goffset sectors,goffset bytes)577 brasero_task_ctx_set_output_size_for_current_track (BraseroTaskCtx *self,
578 goffset sectors,
579 goffset bytes)
580 {
581 BraseroTaskCtxPrivate *priv;
582
583 /* NOTE: we don't need block size here as it's pretty easy to have it by
584 * dividing size by sectors or by guessing it with image or audio format
585 * of the output */
586
587 g_return_val_if_fail (BRASERO_IS_TASK_CTX (self), BRASERO_BURN_ERR);
588
589 priv = BRASERO_TASK_CTX_PRIVATE (self);
590
591 /* we only allow plugins to set these values during the init phase of a
592 * task when it's fakely running. One exception is if size or blocks are
593 * 0 at the start of a task in normal mode */
594 if (sectors >= 0)
595 priv->blocks += sectors;
596
597 if (bytes >= 0)
598 priv->size += bytes;
599
600 BRASERO_BURN_LOG ("Task output modified %lli blocks %lli bytes",
601 priv->blocks,
602 priv->size);
603
604 return BRASERO_BURN_OK;
605 }
606
607 BraseroBurnResult
brasero_task_ctx_set_written_track(BraseroTaskCtx * self,gint64 written)608 brasero_task_ctx_set_written_track (BraseroTaskCtx *self,
609 gint64 written)
610 {
611 BraseroTaskCtxPrivate *priv;
612 gdouble elapsed = 0.0;
613
614 g_return_val_if_fail (BRASERO_IS_TASK_CTX (self), BRASERO_BURN_ERR);
615
616 priv = BRASERO_TASK_CTX_PRIVATE (self);
617
618 priv->written_changed = 1;
619
620 if (priv->use_average_rate) {
621 priv->track_bytes = written;
622 return BRASERO_BURN_OK;
623 }
624
625 if (priv->timer)
626 elapsed = g_timer_elapsed (priv->timer, NULL);
627
628 if ((elapsed - priv->last_elapsed) > 0.5) {
629 priv->last_written = priv->track_bytes;
630 priv->last_elapsed = priv->current_elapsed;
631 priv->current_elapsed = elapsed;
632 }
633
634 priv->track_bytes = written;
635 return BRASERO_BURN_OK;
636 }
637
638 BraseroBurnResult
brasero_task_ctx_set_written_session(BraseroTaskCtx * self,gint64 written)639 brasero_task_ctx_set_written_session (BraseroTaskCtx *self,
640 gint64 written)
641 {
642 BraseroTaskCtxPrivate *priv;
643
644 g_return_val_if_fail (BRASERO_IS_TASK_CTX (self), BRASERO_BURN_ERR);
645
646 priv = BRASERO_TASK_CTX_PRIVATE (self);
647
648 priv->session_bytes = 0;
649 return brasero_task_ctx_set_written_track (self, written);
650 }
651
652 BraseroBurnResult
brasero_task_ctx_set_progress(BraseroTaskCtx * self,gdouble progress)653 brasero_task_ctx_set_progress (BraseroTaskCtx *self,
654 gdouble progress)
655 {
656 BraseroTaskCtxPrivate *priv;
657 gdouble elapsed;
658
659 g_return_val_if_fail (BRASERO_IS_TASK_CTX (self), BRASERO_BURN_ERR);
660
661 priv = BRASERO_TASK_CTX_PRIVATE (self);
662
663 priv->progress_changed = 1;
664
665 if (priv->use_average_rate) {
666 if (priv->progress < progress)
667 priv->progress = progress;
668
669 return BRASERO_BURN_OK;
670 }
671
672 /* here we prefer to use track written bytes instead of progress.
673 * NOTE: usually plugins will return only one information. */
674 if (priv->last_written) {
675 if (priv->progress < progress)
676 priv->progress = progress;
677 return BRASERO_BURN_OK;
678 }
679
680 if (priv->timer) {
681 elapsed = g_timer_elapsed (priv->timer, NULL);
682
683 if ((elapsed - priv->last_elapsed) > 0.5) {
684 priv->last_progress = priv->progress;
685 priv->last_elapsed = priv->current_elapsed;
686 priv->current_elapsed = elapsed;
687 }
688 }
689
690 if (priv->progress < progress)
691 priv->progress = progress;
692
693 return BRASERO_BURN_OK;
694 }
695
696 BraseroBurnResult
brasero_task_ctx_reset_progress(BraseroTaskCtx * self)697 brasero_task_ctx_reset_progress (BraseroTaskCtx *self)
698 {
699 BraseroTaskCtxPrivate *priv;
700
701 g_return_val_if_fail (BRASERO_IS_TASK_CTX (self), BRASERO_BURN_ERR);
702
703 priv = BRASERO_TASK_CTX_PRIVATE (self);
704
705 priv->progress_changed = 1;
706
707 if (priv->timer) {
708 g_timer_destroy (priv->timer);
709 priv->timer = NULL;
710 }
711
712 priv->dangerous = 0;
713 priv->progress = -1.0;
714 priv->track_bytes = -1;
715 priv->session_bytes = -1;
716
717 priv->current_elapsed = 0;
718 priv->last_written = 0;
719 priv->last_elapsed = 0;
720 priv->last_progress = 0;
721
722 if (priv->times) {
723 g_slist_free (priv->times);
724 priv->times = NULL;
725 }
726
727 return BRASERO_BURN_OK;
728 }
729
730 BraseroBurnResult
brasero_task_ctx_set_current_action(BraseroTaskCtx * self,BraseroBurnAction action,const gchar * string,gboolean force)731 brasero_task_ctx_set_current_action (BraseroTaskCtx *self,
732 BraseroBurnAction action,
733 const gchar *string,
734 gboolean force)
735 {
736 BraseroTaskCtxPrivate *priv;
737
738 g_return_val_if_fail (BRASERO_IS_TASK_CTX (self), BRASERO_BURN_ERR);
739
740 priv = BRASERO_TASK_CTX_PRIVATE (self);
741
742 if (priv->current_action == action) {
743 if (!force)
744 return BRASERO_BURN_OK;
745
746 g_mutex_lock (priv->lock);
747
748 priv->update_action_string = 1;
749 }
750 else {
751 g_mutex_lock (priv->lock);
752
753 priv->current_action = action;
754 priv->action_changed = 1;
755 }
756
757 if (priv->action_string)
758 g_free (priv->action_string);
759
760 priv->action_string = string ? g_strdup (string): NULL;
761
762 if (!force) {
763 g_slist_free (priv->times);
764 priv->times = NULL;
765 }
766
767 g_mutex_unlock (priv->lock);
768
769 return BRASERO_BURN_OK;
770 }
771
772 BraseroBurnResult
brasero_task_ctx_set_use_average(BraseroTaskCtx * self,gboolean use_average)773 brasero_task_ctx_set_use_average (BraseroTaskCtx *self,
774 gboolean use_average)
775 {
776 BraseroTaskCtxPrivate *priv;
777
778 g_return_val_if_fail (BRASERO_IS_TASK_CTX (self), BRASERO_BURN_ERR);
779
780 priv = BRASERO_TASK_CTX_PRIVATE (self);
781 priv->use_average_rate = use_average;
782 return BRASERO_BURN_OK;
783 }
784
785 /**
786 * Used to retrieve the values for a given task
787 */
788
789 BraseroBurnResult
brasero_task_ctx_get_rate(BraseroTaskCtx * self,guint64 * rate)790 brasero_task_ctx_get_rate (BraseroTaskCtx *self,
791 guint64 *rate)
792 {
793 BraseroTaskCtxPrivate *priv;
794
795 g_return_val_if_fail (BRASERO_IS_TASK_CTX (self), BRASERO_BURN_ERR);
796 g_return_val_if_fail (rate != NULL, BRASERO_BURN_ERR);
797
798 priv = BRASERO_TASK_CTX_PRIVATE (self);
799
800 if (priv->current_action != BRASERO_BURN_ACTION_RECORDING
801 && priv->current_action != BRASERO_BURN_ACTION_DRIVE_COPY) {
802 *rate = -1;
803 return BRASERO_BURN_NOT_SUPPORTED;
804 }
805
806 if (priv->rate) {
807 *rate = priv->rate;
808 return BRASERO_BURN_OK;
809 }
810
811 if (priv->use_average_rate) {
812 gdouble elapsed;
813
814 if (!priv->timer)
815 return BRASERO_BURN_NOT_READY;
816
817 elapsed = g_timer_elapsed (priv->timer, NULL);
818
819 if ((priv->session_bytes + priv->track_bytes) > 0)
820 *rate = (gdouble) ((priv->session_bytes + priv->track_bytes) - priv->first_written) / elapsed;
821 else if (priv->progress > 0.0)
822 *rate = (gdouble) (priv->progress - priv->first_progress) * priv->size / elapsed;
823 else
824 return BRASERO_BURN_NOT_READY;
825 }
826 else {
827 if (priv->last_written > 0) {
828 *rate = (gdouble) (priv->track_bytes - priv->last_written) /
829 (gdouble) (priv->current_elapsed - priv->last_elapsed);
830 }
831 else if (priv->last_progress > 0.0) {
832 *rate = (gdouble) priv->size *
833 (gdouble) (priv->progress - priv->last_progress) /
834 (gdouble) (priv->current_elapsed - priv->last_elapsed);
835 }
836 else
837 return BRASERO_BURN_NOT_READY;
838 }
839
840 return BRASERO_BURN_OK;
841 }
842
843 BraseroBurnResult
brasero_task_ctx_get_remaining_time(BraseroTaskCtx * self,long * remaining)844 brasero_task_ctx_get_remaining_time (BraseroTaskCtx *self,
845 long *remaining)
846 {
847 BraseroTaskCtxPrivate *priv;
848 gdouble elapsed;
849 gint len;
850
851 g_return_val_if_fail (BRASERO_IS_TASK_CTX (self), BRASERO_BURN_ERR);
852 g_return_val_if_fail (remaining != NULL, BRASERO_BURN_ERR);
853
854 priv = BRASERO_TASK_CTX_PRIVATE (self);
855
856 g_mutex_lock (priv->lock);
857 len = g_slist_length (priv->times);
858 g_mutex_unlock (priv->lock);
859
860 if (len < MAX_VALUE_AVERAGE)
861 return BRASERO_BURN_NOT_READY;
862
863 elapsed = g_timer_elapsed (priv->timer, NULL);
864 *remaining = priv->total_time - elapsed;
865
866 return BRASERO_BURN_OK;
867 }
868
869 BraseroBurnResult
brasero_task_ctx_get_session_output_size(BraseroTaskCtx * self,goffset * blocks,goffset * bytes)870 brasero_task_ctx_get_session_output_size (BraseroTaskCtx *self,
871 goffset *blocks,
872 goffset *bytes)
873 {
874 BraseroTaskCtxPrivate *priv;
875
876 g_return_val_if_fail (BRASERO_IS_TASK_CTX (self), BRASERO_BURN_ERR);
877 g_return_val_if_fail (blocks != NULL || bytes != NULL, BRASERO_BURN_ERR);
878
879 priv = BRASERO_TASK_CTX_PRIVATE (self);
880
881 if (priv->size <= 0 && priv->blocks <= 0)
882 return BRASERO_BURN_NOT_READY;
883
884 if (bytes)
885 *bytes = priv->size;
886
887 if (blocks)
888 *blocks = priv->blocks;
889
890 return BRASERO_BURN_OK;
891 }
892
893 BraseroBurnResult
brasero_task_ctx_get_written(BraseroTaskCtx * self,gint64 * written)894 brasero_task_ctx_get_written (BraseroTaskCtx *self,
895 gint64 *written)
896 {
897 BraseroTaskCtxPrivate *priv;
898
899 g_return_val_if_fail (BRASERO_IS_TASK_CTX (self), BRASERO_BURN_ERR);
900 g_return_val_if_fail (written != NULL, BRASERO_BURN_ERR);
901
902 priv = BRASERO_TASK_CTX_PRIVATE (self);
903
904 if (priv->track_bytes + priv->session_bytes <= 0)
905 return BRASERO_BURN_NOT_READY;
906
907 if (!written)
908 return BRASERO_BURN_OK;
909
910 *written = priv->track_bytes + priv->session_bytes;
911 return BRASERO_BURN_OK;
912 }
913
914 BraseroBurnResult
brasero_task_ctx_get_current_action_string(BraseroTaskCtx * self,BraseroBurnAction action,gchar ** string)915 brasero_task_ctx_get_current_action_string (BraseroTaskCtx *self,
916 BraseroBurnAction action,
917 gchar **string)
918 {
919 BraseroTaskCtxPrivate *priv;
920
921 g_return_val_if_fail (string != NULL, BRASERO_BURN_ERR);
922
923 priv = BRASERO_TASK_CTX_PRIVATE (self);
924
925 if (action != priv->current_action)
926 return BRASERO_BURN_ERR;
927
928 *string = priv->action_string ? g_strdup (priv->action_string):
929 g_strdup (brasero_burn_action_to_string (priv->current_action));
930
931 return BRASERO_BURN_OK;
932 }
933
934 BraseroBurnResult
brasero_task_ctx_get_progress(BraseroTaskCtx * self,gdouble * progress)935 brasero_task_ctx_get_progress (BraseroTaskCtx *self,
936 gdouble *progress)
937 {
938 BraseroTaskCtxPrivate *priv;
939 gdouble track_num = 0;
940 gdouble track_nb = 0;
941 goffset total = 0;
942
943 priv = BRASERO_TASK_CTX_PRIVATE (self);
944
945 /* The following can happen when we're blanking since there's no track */
946 if (priv->action == BRASERO_TASK_ACTION_ERASE) {
947 track_num = 1.0;
948 track_nb = 0.0;
949 }
950 else {
951 GSList *tracks;
952
953 tracks = brasero_burn_session_get_tracks (priv->session);
954 track_num = g_slist_length (tracks);
955 track_nb = g_slist_index (tracks, priv->current_track);
956 }
957
958 if (priv->progress >= 0.0) {
959 if (progress)
960 *progress = (gdouble) (track_nb + priv->progress) / (gdouble) track_num;
961
962 return BRASERO_BURN_OK;
963 }
964
965 total = 0;
966 brasero_task_ctx_get_session_output_size (self, NULL, &total);
967
968 if ((priv->session_bytes + priv->track_bytes) <= 0 || total <= 0) {
969 /* if brasero_task_ctx_start_progress () was called (and a timer
970 * created), assume that the task will report either a progress
971 * of the written bytes. Then it means we just started. */
972 if (priv->timer) {
973 if (progress)
974 *progress = 0.0;
975
976 return BRASERO_BURN_OK;
977 }
978
979 if (progress)
980 *progress = -1.0;
981
982 return BRASERO_BURN_NOT_READY;
983 }
984
985 if (!progress)
986 return BRASERO_BURN_OK;
987
988 *progress = (gdouble) ((gdouble) (priv->track_bytes + priv->session_bytes) / (gdouble) total);
989 return BRASERO_BURN_OK;
990 }
991
992 BraseroBurnResult
brasero_task_ctx_get_current_action(BraseroTaskCtx * self,BraseroBurnAction * action)993 brasero_task_ctx_get_current_action (BraseroTaskCtx *self,
994 BraseroBurnAction *action)
995 {
996 BraseroTaskCtxPrivate *priv;
997
998 g_return_val_if_fail (action != NULL, BRASERO_BURN_ERR);
999
1000 priv = BRASERO_TASK_CTX_PRIVATE (self);
1001
1002 g_mutex_lock (priv->lock);
1003 *action = priv->current_action;
1004 g_mutex_unlock (priv->lock);
1005
1006 return BRASERO_BURN_OK;
1007 }
1008
1009 void
brasero_task_ctx_stop_progress(BraseroTaskCtx * self)1010 brasero_task_ctx_stop_progress (BraseroTaskCtx *self)
1011 {
1012 BraseroTaskCtxPrivate *priv;
1013
1014 priv = BRASERO_TASK_CTX_PRIVATE (self);
1015
1016 /* one last report */
1017 g_signal_emit (self,
1018 brasero_task_ctx_signals [PROGRESS_CHANGED_SIGNAL],
1019 0);
1020
1021 priv->current_action = BRASERO_BURN_ACTION_NONE;
1022 priv->action_changed = 0;
1023 priv->update_action_string = 0;
1024
1025 if (priv->timer) {
1026 g_timer_destroy (priv->timer);
1027 priv->timer = NULL;
1028 }
1029 priv->first_written = 0;
1030 priv->first_progress = 0.0;
1031
1032 g_mutex_lock (priv->lock);
1033
1034 if (priv->action_string) {
1035 g_free (priv->action_string);
1036 priv->action_string = NULL;
1037 }
1038
1039 if (priv->times) {
1040 g_slist_free (priv->times);
1041 priv->times = NULL;
1042 }
1043
1044 g_mutex_unlock (priv->lock);
1045 }
1046
1047 static void
brasero_task_ctx_init(BraseroTaskCtx * object)1048 brasero_task_ctx_init (BraseroTaskCtx *object)
1049 {
1050 BraseroTaskCtxPrivate *priv;
1051
1052 priv = BRASERO_TASK_CTX_PRIVATE (object);
1053 priv->lock = g_mutex_new ();
1054 }
1055
1056 static void
brasero_task_ctx_finalize(GObject * object)1057 brasero_task_ctx_finalize (GObject *object)
1058 {
1059 BraseroTaskCtxPrivate *priv;
1060
1061 priv = BRASERO_TASK_CTX_PRIVATE (object);
1062
1063 if (priv->lock) {
1064 g_mutex_free (priv->lock);
1065 priv->lock = NULL;
1066 }
1067
1068 if (priv->timer) {
1069 g_timer_destroy (priv->timer);
1070 priv->timer = NULL;
1071 }
1072
1073 if (priv->current_track) {
1074 g_object_unref (priv->current_track);
1075 priv->current_track = NULL;
1076 }
1077
1078 if (priv->tracks) {
1079 g_slist_foreach (priv->tracks, (GFunc) g_object_unref, NULL);
1080 g_slist_free (priv->tracks);
1081 priv->tracks = NULL;
1082 }
1083
1084 if (priv->session) {
1085 g_object_unref (priv->session);
1086 priv->session = NULL;
1087 }
1088
1089 G_OBJECT_CLASS (parent_class)->finalize (object);
1090 }
1091
1092 static void
brasero_task_ctx_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1093 brasero_task_ctx_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
1094 {
1095 BraseroTaskCtx *self;
1096 BraseroTaskCtxPrivate *priv;
1097
1098 g_return_if_fail (BRASERO_IS_TASK_CTX (object));
1099
1100 self = BRASERO_TASK_CTX (object);
1101 priv = BRASERO_TASK_CTX_PRIVATE (self);
1102
1103 switch (prop_id)
1104 {
1105 case PROP_ACTION:
1106 priv->action = g_value_get_int (value);
1107 break;
1108 case PROP_SESSION:
1109 priv->session = g_value_get_object (value);
1110 g_object_ref (priv->session);
1111 break;
1112 default:
1113 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1114 break;
1115 }
1116 }
1117
1118 static void
brasero_task_ctx_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1119 brasero_task_ctx_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
1120 {
1121 BraseroTaskCtx *self;
1122 BraseroTaskCtxPrivate *priv;
1123
1124 g_return_if_fail (BRASERO_IS_TASK_CTX (object));
1125
1126 self = BRASERO_TASK_CTX (object);
1127 priv = BRASERO_TASK_CTX_PRIVATE (self);
1128
1129 switch (prop_id)
1130 {
1131 case PROP_ACTION:
1132 g_value_set_int (value, priv->action);
1133 break;
1134 case PROP_SESSION:
1135 g_value_set_object (value, priv->session);
1136 break;
1137 default:
1138 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1139 break;
1140 }
1141 }
1142
1143 static void
brasero_task_ctx_class_init(BraseroTaskCtxClass * klass)1144 brasero_task_ctx_class_init (BraseroTaskCtxClass *klass)
1145 {
1146 GObjectClass* object_class = G_OBJECT_CLASS (klass);
1147 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
1148
1149 g_type_class_add_private (klass, sizeof (BraseroTaskCtxPrivate));
1150
1151 object_class->finalize = brasero_task_ctx_finalize;
1152 object_class->set_property = brasero_task_ctx_set_property;
1153 object_class->get_property = brasero_task_ctx_get_property;
1154
1155 brasero_task_ctx_signals [PROGRESS_CHANGED_SIGNAL] =
1156 g_signal_new ("progress_changed",
1157 G_TYPE_FROM_CLASS (klass),
1158 G_SIGNAL_RUN_LAST,
1159 0,
1160 NULL, NULL,
1161 g_cclosure_marshal_VOID__VOID,
1162 G_TYPE_NONE,
1163 0);
1164
1165 brasero_task_ctx_signals [ACTION_CHANGED_SIGNAL] =
1166 g_signal_new ("action_changed",
1167 G_TYPE_FROM_CLASS (klass),
1168 G_SIGNAL_RUN_LAST,
1169 0,
1170 NULL, NULL,
1171 g_cclosure_marshal_VOID__INT,
1172 G_TYPE_NONE,
1173 1,
1174 G_TYPE_INT);
1175
1176 g_object_class_install_property (object_class,
1177 PROP_ACTION,
1178 g_param_spec_int ("action",
1179 "The action the task must perform",
1180 "The action the task must perform",
1181 BRASERO_TASK_ACTION_ERASE,
1182 BRASERO_TASK_ACTION_CHECKSUM,
1183 BRASERO_TASK_ACTION_NORMAL,
1184 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
1185
1186 g_object_class_install_property (object_class,
1187 PROP_SESSION,
1188 g_param_spec_object ("session",
1189 "The session this object is tied to",
1190 "The session this object is tied to",
1191 BRASERO_TYPE_BURN_SESSION,
1192 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
1193 }
1194