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 <glib.h>
36 #include <glib-object.h>
37 #include <glib/gi18n-lib.h>
38 
39 #include <gdk/gdk.h>
40 
41 #include "burn-basics.h"
42 #include "burn-debug.h"
43 #include "brasero-session.h"
44 #include "burn-task.h"
45 #include "burn-task-item.h"
46 #include "burn-task-ctx.h"
47 
48 #include "brasero-track-image.h"
49 #include "brasero-track-stream.h"
50 
51 static void brasero_task_class_init (BraseroTaskClass *klass);
52 static void brasero_task_init (BraseroTask *sp);
53 static void brasero_task_finalize (GObject *object);
54 
55 typedef struct _BraseroTaskPrivate BraseroTaskPrivate;
56 
57 struct _BraseroTaskPrivate {
58 	/* The loop for the task */
59 	GMainLoop *loop;
60 
61 	/* used to poll for progress (every 0.5 sec) */
62 	gint clock_id;
63 
64 	BraseroTaskItem *leader;
65 	BraseroTaskItem *first;
66 
67 	/* result of the task */
68 	BraseroBurnResult retval;
69 	GError *error;
70 };
71 
72 #define BRASERO_TASK_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_TASK, BraseroTaskPrivate))
73 G_DEFINE_TYPE (BraseroTask, brasero_task, BRASERO_TYPE_TASK_CTX);
74 
75 static GObjectClass *parent_class = NULL;
76 
77 #define MAX_JOB_START_ATTEMPTS			5
78 #define JOB_ATTEMPTS_WAIT_TIME			1
79 
80 void
brasero_task_add_item(BraseroTask * task,BraseroTaskItem * item)81 brasero_task_add_item (BraseroTask *task, BraseroTaskItem *item)
82 {
83 	BraseroTaskPrivate *priv;
84 
85 	g_return_if_fail (BRASERO_IS_TASK (task));
86 	g_return_if_fail (BRASERO_IS_TASK_ITEM (item));
87 
88 	priv = BRASERO_TASK_PRIVATE (task);
89 
90 	if (priv->leader) {
91 		brasero_task_item_link (priv->leader, item);
92 		g_object_unref (priv->leader);
93 	}
94 
95 	if (!priv->first)
96 		priv->first = item;
97 
98 	priv->leader = item;
99 	g_object_ref (priv->leader);
100 }
101 
102 static void
brasero_task_reset_real(BraseroTask * task)103 brasero_task_reset_real (BraseroTask *task)
104 {
105 	BraseroTaskPrivate *priv;
106 
107 	priv = BRASERO_TASK_PRIVATE (task);
108 
109 	if (priv->loop)
110 		g_main_loop_unref (priv->loop);
111 
112 	priv->loop = NULL;
113 	priv->clock_id = 0;
114 	priv->retval = BRASERO_BURN_OK;
115 
116 	if (priv->error) {
117 		g_error_free (priv->error);
118 		priv->error = NULL;
119 	}
120 
121 	brasero_task_ctx_reset (BRASERO_TASK_CTX (task));
122 }
123 
124 void
brasero_task_reset(BraseroTask * task)125 brasero_task_reset (BraseroTask *task)
126 {
127 	BraseroTaskPrivate *priv;
128 
129 	priv = BRASERO_TASK_PRIVATE (task);
130 
131 	if (brasero_task_is_running (task))
132 		brasero_task_cancel (task, TRUE);
133 
134 	g_object_unref (priv->leader);
135 	brasero_task_reset_real (task);
136 }
137 
138 static gboolean
brasero_task_clock_tick(gpointer data)139 brasero_task_clock_tick (gpointer data)
140 {
141 	BraseroTask *task = BRASERO_TASK (data);
142 	BraseroTaskPrivate *priv;
143 	BraseroTaskItem *item;
144 
145 	priv = BRASERO_TASK_PRIVATE (task);
146 
147 	/* some jobs need to be called periodically to update their status
148 	 * because the main process run in a thread. We do it before calling
149 	 * progress/action changed so they can update the task on time */
150 	for (item = priv->leader; item; item = brasero_task_item_previous (item)) {
151 		BraseroTaskItemIFace *klass;
152 
153 		klass = BRASERO_TASK_ITEM_GET_CLASS (item);
154 		if (klass->clock_tick)
155 			klass->clock_tick (item, BRASERO_TASK_CTX (task), NULL);
156 	}
157 
158 	/* now call ctx to update progress */
159 	brasero_task_ctx_report_progress (BRASERO_TASK_CTX (data));
160 
161 	return TRUE;
162 }
163 
164 /**
165  * Used to run/stop task
166  */
167 
168 static BraseroBurnResult
brasero_task_deactivate_item(BraseroTask * task,BraseroTaskItem * item,GError ** error)169 brasero_task_deactivate_item (BraseroTask *task,
170 			      BraseroTaskItem *item,
171 			      GError **error)
172 {
173 	BraseroBurnResult result = BRASERO_BURN_OK;
174 	BraseroTaskItemIFace *klass;
175 
176 	if (!brasero_task_item_is_active (item)) {
177 		BRASERO_BURN_LOG ("%s already stopped", G_OBJECT_TYPE_NAME (item));
178 		return BRASERO_BURN_OK;
179 	}
180 
181 	/* stop task for real now */
182 	BRASERO_BURN_LOG ("stopping %s", G_OBJECT_TYPE_NAME (item));
183 
184 	klass = BRASERO_TASK_ITEM_GET_CLASS (item);
185 	if (klass->stop)
186 		result = klass->stop (item,
187 				      BRASERO_TASK_CTX (task),
188 				      error);
189 
190 	BRASERO_BURN_LOG ("stopped %s", G_OBJECT_TYPE_NAME (item));
191 	return result;
192 }
193 
194 static BraseroBurnResult
brasero_task_send_stop_signal(BraseroTask * task,BraseroBurnResult retval,GError ** error)195 brasero_task_send_stop_signal (BraseroTask *task,
196 			       BraseroBurnResult retval,
197 			       GError **error)
198 {
199 	BraseroTaskItem *item;
200 	BraseroTaskPrivate *priv;
201 	GError *local_error = NULL;
202 	BraseroBurnResult result = retval;
203 
204 	priv = BRASERO_TASK_PRIVATE (task);
205 
206 	item = priv->leader;
207 	while (brasero_task_item_previous (item))
208 		item = brasero_task_item_previous (item);
209 
210 	/* we stop all the slaves first and then go up the list */
211 	for (; item; item = brasero_task_item_next (item)) {
212 		GError *item_error;
213 
214 		item_error = NULL;
215 
216 		/* stop task for real now */
217 		result = brasero_task_deactivate_item (task, item, &item_error);
218 		if (item_error) {
219 			g_error_free (local_error);
220 			local_error = item_error;
221 		}
222 	}
223 
224 	if (local_error) {
225 		if (error && *error == NULL)
226 			g_propagate_error (error, local_error);
227 		else
228 			g_error_free (local_error);
229 	}
230 
231 	/* we don't want to lose the original result if it was not OK */
232 	return (result == BRASERO_BURN_OK? retval:result);
233 }
234 
235 static gboolean
brasero_task_wakeup(gpointer user_data)236 brasero_task_wakeup (gpointer user_data)
237 {
238 	BraseroTaskPrivate *priv;
239 
240 	priv = BRASERO_TASK_PRIVATE (user_data);
241 
242 	if (priv->loop)
243 		g_main_loop_quit (priv->loop);
244 
245 	priv->clock_id = 0;
246 	priv->retval = BRASERO_BURN_OK;
247 	return FALSE;
248 }
249 
250 static BraseroBurnResult
brasero_task_sleep(BraseroTask * self,guint sec)251 brasero_task_sleep (BraseroTask *self, guint sec)
252 {
253 	BraseroTaskPrivate *priv;
254 
255 	priv = BRASERO_TASK_PRIVATE (self);
256 
257 	BRASERO_BURN_LOG ("wait loop");
258 
259 	priv->loop = g_main_loop_new (NULL, FALSE);
260 	priv->clock_id = g_timeout_add_seconds (sec,
261 	                                        brasero_task_wakeup,
262 	                                        self);
263 
264 	GDK_THREADS_LEAVE ();
265 	g_main_loop_run (priv->loop);
266 	GDK_THREADS_ENTER ();
267 
268 	g_main_loop_unref (priv->loop);
269 	priv->loop = NULL;
270 
271 	if (priv->clock_id) {
272 		g_source_remove (priv->clock_id);
273 		priv->clock_id = 0;
274 	}
275 
276 	return priv->retval;
277 }
278 
279 static BraseroBurnResult
brasero_task_start_item(BraseroTask * task,BraseroTaskItem * item,GError ** error)280 brasero_task_start_item (BraseroTask *task,
281 			 BraseroTaskItem *item,
282 			 GError **error)
283 {
284 	guint attempts = 0;
285 	BraseroBurnResult result;
286 	GError *ret_error = NULL;
287 	BraseroTaskItemIFace *klass;
288 
289 	klass = BRASERO_TASK_ITEM_GET_CLASS (item);
290 	if (!klass->start)
291 		return BRASERO_BURN_ERR;
292 
293 	BRASERO_BURN_LOG ("::start method %s", G_OBJECT_TYPE_NAME (item));
294 
295 	result = klass->start (item, &ret_error);
296 	while (result == BRASERO_BURN_RETRY) {
297 		/* FIXME: a GError?? */
298 		if (attempts >= MAX_JOB_START_ATTEMPTS) {
299 			if (ret_error)
300 				g_propagate_error (error, ret_error);
301 
302 			return BRASERO_BURN_ERR;
303 		}
304 
305 		if (ret_error) {
306 			g_error_free (ret_error);
307 			ret_error = NULL;
308 		}
309 
310 		result = brasero_task_sleep (task, 1);
311 		if (result != BRASERO_BURN_OK)
312 			return result;
313 
314 		attempts ++;
315 		result = klass->start (item, &ret_error);
316 	}
317 
318 	if (ret_error)
319 		g_propagate_error (error, ret_error);
320 
321 	return result;
322 }
323 
324 static BraseroBurnResult
brasero_task_activate_item(BraseroTask * task,BraseroTaskItem * item,GError ** error)325 brasero_task_activate_item (BraseroTask *task,
326 			    BraseroTaskItem *item,
327 			    GError **error)
328 {
329 	BraseroTaskItemIFace *klass;
330 	BraseroBurnResult result = BRASERO_BURN_OK;
331 
332 	klass = BRASERO_TASK_ITEM_GET_CLASS (item);
333 	if (!klass->activate)
334 		return BRASERO_BURN_ERR;
335 
336 	BRASERO_BURN_LOG ("::activate method %s", G_OBJECT_TYPE_NAME (item));
337 
338 	result = klass->activate (item, BRASERO_TASK_CTX (task), error);
339 	return result;
340 }
341 
342 static void
brasero_task_stop(BraseroTask * task,BraseroBurnResult retval,GError * error)343 brasero_task_stop (BraseroTask *task,
344 		   BraseroBurnResult retval,
345 		   GError *error)
346 {
347 	BraseroBurnResult result;
348 	BraseroTaskPrivate *priv;
349 
350 	priv = BRASERO_TASK_PRIVATE (task);
351 
352 	/* brasero_job_error/brasero_job_finished ()
353 	 * should not be called during ::init and ::start.
354 	 * Instead a job should return errors directly */
355 	result = brasero_task_send_stop_signal (task, retval, &error);
356 
357 	priv->retval = retval;
358 	priv->error = error;
359 
360 	if (priv->loop && g_main_loop_is_running (priv->loop))
361 		g_main_loop_quit (priv->loop);
362 	else
363 		BRASERO_BURN_LOG ("task was asked to stop (%i/%i) during ::init or ::start",
364 				  result, retval);
365 }
366 
367 BraseroBurnResult
brasero_task_cancel(BraseroTask * task,gboolean protect)368 brasero_task_cancel (BraseroTask *task,
369 		     gboolean protect)
370 {
371 	if (protect && brasero_task_ctx_get_dangerous (BRASERO_TASK_CTX (task)))
372 		return BRASERO_BURN_DANGEROUS;
373 
374 	brasero_task_stop (task, BRASERO_BURN_CANCEL, NULL);
375 	return BRASERO_BURN_OK;
376 }
377 
378 gboolean
brasero_task_is_running(BraseroTask * task)379 brasero_task_is_running (BraseroTask *task)
380 {
381 	BraseroTaskPrivate *priv;
382 
383 	priv = BRASERO_TASK_PRIVATE (task);
384 	return (priv->loop && g_main_loop_is_running (priv->loop));
385 }
386 
387 static void
brasero_task_finished(BraseroTaskCtx * ctx,BraseroBurnResult retval,GError * error)388 brasero_task_finished (BraseroTaskCtx *ctx,
389 		       BraseroBurnResult retval,
390 		       GError *error)
391 {
392 	BraseroTask *self;
393 	BraseroTaskPrivate *priv;
394 
395 	self = BRASERO_TASK (ctx);
396 	priv = BRASERO_TASK_PRIVATE (self);
397 
398 	/* see if we have really started a loop */
399 	/* FIXME: shouldn't it be an error if it is called
400 	 * while the loop is not running ? */
401 	if (!brasero_task_is_running (self))
402 		return;
403 
404 	if (retval == BRASERO_BURN_RETRY) {
405 		BraseroTaskItem *item;
406 		GError *error_item = NULL;
407 
408 		/* There are some tracks left, get the first
409 		 * task item and restart it. */
410 		item = priv->leader;
411 		while (brasero_task_item_previous (item))
412 			item = brasero_task_item_previous (item);
413 
414 		if (brasero_task_item_start (item, &error_item) != BRASERO_BURN_OK)
415 			brasero_task_stop (self, BRASERO_BURN_ERR, error_item);
416 
417 		return;
418 	}
419 
420 	brasero_task_stop (self, retval, error);
421 }
422 
423 static BraseroBurnResult
brasero_task_run_loop(BraseroTask * self,GError ** error)424 brasero_task_run_loop (BraseroTask *self,
425 		       GError **error)
426 {
427 	BraseroTaskPrivate *priv;
428 
429 	priv = BRASERO_TASK_PRIVATE (self);
430 
431 	brasero_task_ctx_report_progress (BRASERO_TASK_CTX (self));
432 
433 	priv->clock_id = g_timeout_add (500,
434 					brasero_task_clock_tick,
435 					self);
436 
437 	priv->loop = g_main_loop_new (NULL, FALSE);
438 
439 	BRASERO_BURN_LOG ("entering loop");
440 
441 	GDK_THREADS_LEAVE ();
442 	g_main_loop_run (priv->loop);
443 	GDK_THREADS_ENTER ();
444 
445 	BRASERO_BURN_LOG ("got out of loop");
446 	g_main_loop_unref (priv->loop);
447 	priv->loop = NULL;
448 
449 	if (priv->error) {
450 		g_propagate_error (error, priv->error);
451 		priv->error = NULL;
452 	}
453 
454 	/* stop all progress reporting thing */
455 	if (priv->clock_id) {
456 		g_source_remove (priv->clock_id);
457 		priv->clock_id = 0;
458 	}
459 
460 	if (priv->retval == BRASERO_BURN_OK
461 	&&  brasero_task_ctx_get_progress (BRASERO_TASK_CTX (self), NULL) == BRASERO_BURN_OK) {
462 		brasero_task_ctx_set_progress (BRASERO_TASK_CTX (self), 1.0);
463 		brasero_task_ctx_report_progress (BRASERO_TASK_CTX (self));
464 	}
465 
466 	brasero_task_ctx_stop_progress (BRASERO_TASK_CTX (self));
467 	return priv->retval;
468 }
469 
470 static BraseroBurnResult
brasero_task_set_track_output_size_default(BraseroTask * self,GError ** error)471 brasero_task_set_track_output_size_default (BraseroTask *self,
472 					    GError **error)
473 {
474 	BraseroTrack *track = NULL;
475 
476 	BRASERO_BURN_LOG ("Trying to set a default output size");
477 
478 	brasero_task_ctx_get_current_track (BRASERO_TASK_CTX (self), &track);
479 //	BRASERO_BURN_LOG_TYPE (&input, "Track type");
480 
481 	if (BRASERO_IS_TRACK_IMAGE (track)
482 	||  BRASERO_IS_TRACK_STREAM (track)) {
483 		BraseroBurnResult result;
484 		goffset sectors = 0;
485 		goffset bytes = 0;
486 
487 		result = brasero_track_get_size (track,
488 						 &sectors,
489 						 &bytes);
490 		if (result != BRASERO_BURN_OK)
491 			return result;
492 
493 		BRASERO_BURN_LOG ("Got a default image or stream track length %lli", sectors);
494 		brasero_task_ctx_set_output_size_for_current_track (BRASERO_TASK_CTX (self),
495 								    sectors,
496 								    bytes);
497 	}
498 
499 	return BRASERO_BURN_OK;
500 }
501 
502 static BraseroBurnResult
brasero_task_activate_items(BraseroTask * self,GError ** error)503 brasero_task_activate_items (BraseroTask *self,
504 			     GError **error)
505 {
506 	BraseroTaskPrivate *priv;
507 	BraseroBurnResult retval;
508 	BraseroTaskItem *item;
509 
510 	priv = BRASERO_TASK_PRIVATE (self);
511 
512 	retval = BRASERO_BURN_NOT_RUNNING;
513 	for (item = priv->first; item; item = brasero_task_item_next (item)) {
514 		BraseroBurnResult result;
515 
516 		result = brasero_task_activate_item (self, item, error);
517 		if (result == BRASERO_BURN_NOT_RUNNING) {
518 			BRASERO_BURN_LOG ("::start skipped for %s",
519 					  G_OBJECT_TYPE_NAME (item));
520 			continue;
521 		}
522 
523 		if (result != BRASERO_BURN_OK)
524 			return result;
525 
526 		retval = BRASERO_BURN_OK;
527 	}
528 
529 	return retval;
530 }
531 
532 static BraseroBurnResult
brasero_task_start_items(BraseroTask * self,GError ** error)533 brasero_task_start_items (BraseroTask *self,
534 			  GError **error)
535 {
536 	BraseroBurnResult retval;
537 	BraseroTaskPrivate *priv;
538 	BraseroTaskItem *item;
539 
540 	priv = BRASERO_TASK_PRIVATE (self);
541 
542 	/* start from the master down to the slave */
543 	retval = BRASERO_BURN_NOT_SUPPORTED;
544 	for (item = priv->leader; item; item = brasero_task_item_previous (item)) {
545 		BraseroBurnResult result;
546 
547 		if (!brasero_task_item_is_active (item))
548 			continue;
549 
550 		result = brasero_task_start_item (self, item, error);
551 		if (result == BRASERO_BURN_NOT_SUPPORTED) {
552 			BRASERO_BURN_LOG ("%s doesn't support action",
553 					  G_OBJECT_TYPE_NAME (item));
554 
555 			/* "fake mode" to get size. Forgive the jobs that cannot
556 			 * retrieve the size for one track. Just deactivate and
557 			 * go on with the next.
558 			 * NOTE: after this result the job is no longer active */
559 			continue;
560 		}
561 
562 		/* if the following is true don't stop everything */
563 		if (result == BRASERO_BURN_NOT_RUNNING)
564 			return result;
565 
566 		if (result != BRASERO_BURN_OK)
567 			return result;
568 
569 		retval = BRASERO_BURN_OK;
570 	}
571 
572 	if (retval == BRASERO_BURN_NOT_SUPPORTED) {
573 		/* if all jobs did not want/could not run then resort to a
574 		 * default function and return BRASERO_BURN_NOT_RUNNING */
575 		retval = brasero_task_set_track_output_size_default (self, error);
576 		if (retval != BRASERO_BURN_OK)
577 			return retval;
578 
579 		return BRASERO_BURN_NOT_RUNNING;
580 	}
581 
582 	return brasero_task_run_loop (self, error);
583 }
584 
585 static BraseroBurnResult
brasero_task_start(BraseroTask * self,gboolean fake,GError ** error)586 brasero_task_start (BraseroTask *self,
587 		    gboolean fake,
588 		    GError **error)
589 {
590 	BraseroBurnResult result = BRASERO_BURN_OK;
591 	BraseroTaskPrivate *priv;
592 
593 	priv = BRASERO_TASK_PRIVATE (self);
594 
595 	BRASERO_BURN_LOG ("Starting %s task (%i)",
596 			  fake ? "fake":"normal",
597 			  brasero_task_ctx_get_action (BRASERO_TASK_CTX (self)));
598 
599 	/* check the task is not running */
600 	if (brasero_task_is_running (self)) {
601 		BRASERO_BURN_LOG ("task is already running");
602 		return BRASERO_BURN_RUNNING;
603 	}
604 
605 	if (!priv->leader) {
606 		BRASERO_BURN_LOG ("no jobs");
607 		return BRASERO_BURN_RUNNING;
608 	}
609 
610 	brasero_task_ctx_set_fake (BRASERO_TASK_CTX (self), fake);
611 	brasero_task_ctx_reset (BRASERO_TASK_CTX (self));
612 
613 	/* Activate all items that can be. If no item can be then skip */
614 	result = brasero_task_activate_items (self, error);
615 	if (result == BRASERO_BURN_NOT_RUNNING) {
616 		BRASERO_BURN_LOG ("Task skipped");
617 		return BRASERO_BURN_OK;
618 	}
619 
620 	if (result != BRASERO_BURN_OK)
621 		return result;
622 
623 	result = brasero_task_start_items (self, error);
624 	while (result == BRASERO_BURN_NOT_RUNNING) {
625 		BRASERO_BURN_LOG ("current track skipped");
626 
627 		/* this track was skipped without actual loop therefore see if
628 		 * there is another track and, if there is, start again */
629 		result = brasero_task_ctx_next_track (BRASERO_TASK_CTX (self));
630 		if (result != BRASERO_BURN_RETRY) {
631 			brasero_task_send_stop_signal (self, result, NULL);
632 			return result;
633 		}
634 
635 		result = brasero_task_start_items (self, error);
636 	}
637 
638 	if (result != BRASERO_BURN_OK)
639 		brasero_task_send_stop_signal (self, result, NULL);
640 
641 	return result;
642 }
643 
644 BraseroBurnResult
brasero_task_check(BraseroTask * self,GError ** error)645 brasero_task_check (BraseroTask *self,
646 		    GError **error)
647 {
648 	BraseroTaskAction action;
649 
650 	g_return_val_if_fail (BRASERO_IS_TASK (self), BRASERO_BURN_ERR);
651 
652 	/* the task MUST be of a BRASERO_TASK_ACTION_NORMAL type */
653 	action = brasero_task_ctx_get_action (BRASERO_TASK_CTX (self));
654 	if (action != BRASERO_TASK_ACTION_NORMAL)
655 		return BRASERO_BURN_OK;
656 
657 	/* The main purpose of this function is to get the final size of the
658 	 * task output whether it be recorded to disc or stored as a file later.
659 	 * That size will be stored by task-ctx.
660 	 * To do this we run all the task in fake mode that means we don't write
661 	 * anything to disc or hard drive. Only the last running job in the
662 	 * chain will be aware that we're running in fake mode / get-size mode.
663 	 * All others will be told to image. To determine what should be the
664 	 * last job and therefore the one telling the final size of the output,
665 	 * we start to call ::init for each job starting from the leader. we
666 	 * don't skip recording jobs in case they modify the contents (and
667 	 * therefore the output size). When a job returns NOT_RUNNING after
668 	 * ::init then we skip it; this return value will mean that it won't
669 	 * change the output size or that it has already determined the output
670 	 * size. Only the last running job is allowed to set the final size (see
671 	 * burn-jobs.c), all values from other jobs will be ignored. */
672 
673 	return brasero_task_start (self, TRUE, error);
674 }
675 
676 BraseroBurnResult
brasero_task_run(BraseroTask * self,GError ** error)677 brasero_task_run (BraseroTask *self,
678 		  GError **error)
679 {
680 	g_return_val_if_fail (BRASERO_IS_TASK (self), BRASERO_BURN_ERR);
681 
682 	return brasero_task_start (self, FALSE, error);
683 }
684 
685 static void
brasero_task_class_init(BraseroTaskClass * klass)686 brasero_task_class_init (BraseroTaskClass *klass)
687 {
688 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
689 	BraseroTaskCtxClass *ctx_class = BRASERO_TASK_CTX_CLASS (klass);
690 
691 	g_type_class_add_private (klass, sizeof (BraseroTaskPrivate));
692 
693 	parent_class = g_type_class_peek_parent(klass);
694 	object_class->finalize = brasero_task_finalize;
695 
696 	ctx_class->finished = brasero_task_finished;
697 }
698 
699 static void
brasero_task_init(BraseroTask * obj)700 brasero_task_init (BraseroTask *obj)
701 { }
702 
703 static void
brasero_task_finalize(GObject * object)704 brasero_task_finalize (GObject *object)
705 {
706 	BraseroTask *cobj;
707 	BraseroTaskPrivate *priv;
708 
709 	cobj = BRASERO_TASK (object);
710 	priv = BRASERO_TASK_PRIVATE (cobj);
711 
712 	if (priv->leader) {
713 		g_object_unref (priv->leader);
714 		priv->leader = NULL;
715 	}
716 
717 	G_OBJECT_CLASS (parent_class)->finalize (object);
718 }
719 
720 BraseroTask *
brasero_task_new()721 brasero_task_new ()
722 {
723 	BraseroTask *obj;
724 
725 	obj = BRASERO_TASK (g_object_new (BRASERO_TYPE_TASK, NULL));
726 	return obj;
727 }
728