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 <errno.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40
41 #include <glib.h>
42 #include <glib-object.h>
43 #include <glib/gstdio.h>
44 #include <glib/gi18n-lib.h>
45
46 #include "brasero-session.h"
47 #include "brasero-session-helper.h"
48
49 #include "burn-basics.h"
50 #include "burn-debug.h"
51 #include "libbrasero-marshal.h"
52 #include "burn-image-format.h"
53 #include "brasero-track-type-private.h"
54
55 #include "brasero-medium.h"
56 #include "brasero-drive.h"
57 #include "brasero-drive-priv.h"
58 #include "brasero-medium-monitor.h"
59
60 #include "brasero-tags.h"
61 #include "brasero-track.h"
62 #include "brasero-track-disc.h"
63
64 G_DEFINE_TYPE (BraseroBurnSession, brasero_burn_session, G_TYPE_OBJECT);
65 #define BRASERO_BURN_SESSION_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_BURN_SESSION, BraseroBurnSessionPrivate))
66
67 /**
68 * SECTION:brasero-session
69 * @short_description: Store parameters when burning and blanking
70 * @see_also: #BraseroBurn, #BraseroSessionCfg
71 * @include: brasero-session.h
72 *
73 * This object stores all parameters for all operations performed by #BraseroBurn such as
74 * burning, blanking and checksuming. To have this object configured automatically see
75 * #BraseroSessionCfg.
76 **/
77
78 struct _BraseroSessionSetting {
79 BraseroDrive *burner;
80
81 /**
82 * Used when outputting an image instead of burning
83 */
84 BraseroImageFormat format;
85 gchar *image;
86 gchar *toc;
87
88 /**
89 * Used when burning
90 */
91 gchar *label;
92 guint64 rate;
93
94 BraseroBurnFlag flags;
95 };
96 typedef struct _BraseroSessionSetting BraseroSessionSetting;
97
98 struct _BraseroBurnSessionPrivate {
99 int session;
100 gchar *session_path;
101
102 gchar *tmpdir;
103 GSList *tmpfiles;
104
105 BraseroSessionSetting settings [1];
106 GSList *pile_settings;
107
108 GHashTable *tags;
109
110 guint dest_added_sig;
111 guint dest_removed_sig;
112
113 GSList *tracks;
114 GSList *pile_tracks;
115
116 guint strict_checks:1;
117 };
118 typedef struct _BraseroBurnSessionPrivate BraseroBurnSessionPrivate;
119
120 #define BRASERO_BURN_SESSION_WRITE_TO_DISC(priv) (priv->settings->burner && \
121 !brasero_drive_is_fake (priv->settings->burner))
122 #define BRASERO_BURN_SESSION_WRITE_TO_FILE(priv) (priv->settings->burner && \
123 brasero_drive_is_fake (priv->settings->burner))
124 #define BRASERO_STR_EQUAL(a, b) ((!(a) && !(b)) || ((a) && (b) && !strcmp ((a), (b))))
125
126 typedef enum {
127 TAG_CHANGED_SIGNAL,
128 TRACK_ADDED_SIGNAL,
129 TRACK_REMOVED_SIGNAL,
130 TRACK_CHANGED_SIGNAL,
131 OUTPUT_CHANGED_SIGNAL,
132 LAST_SIGNAL
133 } BraseroBurnSessionSignalType;
134
135 static guint brasero_burn_session_signals [LAST_SIGNAL] = { 0 };
136
137 enum {
138 PROP_0,
139 PROP_TMPDIR,
140 PROP_RATE,
141 PROP_FLAGS
142 };
143
144 static GObjectClass *parent_class = NULL;
145
146 static void
brasero_session_settings_clean(BraseroSessionSetting * settings)147 brasero_session_settings_clean (BraseroSessionSetting *settings)
148 {
149 if (settings->image)
150 g_free (settings->image);
151
152 if (settings->toc)
153 g_free (settings->toc);
154
155 if (settings->label)
156 g_free (settings->label);
157
158 if (settings->burner)
159 g_object_unref (settings->burner);
160
161 memset (settings, 0, sizeof (BraseroSessionSetting));
162 }
163
164 static void
brasero_session_settings_copy(BraseroSessionSetting * dest,BraseroSessionSetting * original)165 brasero_session_settings_copy (BraseroSessionSetting *dest,
166 BraseroSessionSetting *original)
167 {
168 brasero_session_settings_clean (dest);
169
170 memcpy (dest, original, sizeof (BraseroSessionSetting));
171
172 g_object_ref (dest->burner);
173 dest->image = g_strdup (original->image);
174 dest->toc = g_strdup (original->toc);
175 dest->label = g_strdup (original->label);
176 }
177
178 static void
brasero_session_settings_free(BraseroSessionSetting * settings)179 brasero_session_settings_free (BraseroSessionSetting *settings)
180 {
181 brasero_session_settings_clean (settings);
182 g_free (settings);
183 }
184
185 static void
brasero_burn_session_track_changed(BraseroTrack * track,BraseroBurnSession * self)186 brasero_burn_session_track_changed (BraseroTrack *track,
187 BraseroBurnSession *self)
188 {
189 g_signal_emit (self,
190 brasero_burn_session_signals [TRACK_CHANGED_SIGNAL],
191 0,
192 track);
193 }
194
195 static void
brasero_burn_session_start_track_monitoring(BraseroBurnSession * self,BraseroTrack * track)196 brasero_burn_session_start_track_monitoring (BraseroBurnSession *self,
197 BraseroTrack *track)
198 {
199 g_signal_connect (track,
200 "changed",
201 G_CALLBACK (brasero_burn_session_track_changed),
202 self);
203 }
204
205 static void
brasero_burn_session_stop_tracks_monitoring(BraseroBurnSession * self)206 brasero_burn_session_stop_tracks_monitoring (BraseroBurnSession *self)
207 {
208 BraseroBurnSessionPrivate *priv;
209 GSList *iter;
210
211 priv = BRASERO_BURN_SESSION_PRIVATE (self);
212
213 for (iter = priv->tracks; iter; iter = iter->next) {
214 BraseroTrack *track;
215
216 track = iter->data;
217 g_signal_handlers_disconnect_by_func (track,
218 brasero_burn_session_track_changed,
219 self);
220 }
221 }
222
223 static void
brasero_burn_session_free_tracks(BraseroBurnSession * self)224 brasero_burn_session_free_tracks (BraseroBurnSession *self)
225 {
226 BraseroBurnSessionPrivate *priv;
227 GSList *iter;
228 GSList *next;
229
230 g_return_if_fail (BRASERO_IS_BURN_SESSION (self));
231
232 priv = BRASERO_BURN_SESSION_PRIVATE (self);
233
234 brasero_burn_session_stop_tracks_monitoring (self);
235
236 for (iter = priv->tracks; iter; iter = next) {
237 BraseroTrack *track;
238
239 track = iter->data;
240 next = iter->next;
241 priv->tracks = g_slist_remove (priv->tracks, track);
242 g_signal_emit (self,
243 brasero_burn_session_signals [TRACK_REMOVED_SIGNAL],
244 0,
245 track,
246 0);
247 g_object_unref (track);
248 }
249 }
250
251 /**
252 * brasero_burn_session_set_strict_support:
253 * @session: a #BraseroBurnSession.
254 * @flags: a #BraseroSessionCheckFlags
255 *
256 * For the following functions:
257 * brasero_burn_session_supported ()
258 * brasero_burn_session_input_supported ()
259 * brasero_burn_session_output_supported ()
260 * brasero_burn_session_can_blank ()
261 * this function sets whether these functions will
262 * ignore the plugins with errors (%TRUE).
263 */
264
265 void
brasero_burn_session_set_strict_support(BraseroBurnSession * session,gboolean strict_checks)266 brasero_burn_session_set_strict_support (BraseroBurnSession *session,
267 gboolean strict_checks)
268 {
269 BraseroBurnSessionPrivate *priv;
270
271 g_return_if_fail (BRASERO_IS_BURN_SESSION (session));
272
273 priv = BRASERO_BURN_SESSION_PRIVATE (session);
274 priv->strict_checks = strict_checks;
275 }
276
277 /**
278 * brasero_burn_session_get_strict_support:
279 * @session: a #BraseroBurnSession.
280 *
281 * For the following functions:
282 * brasero_burn_session_can_burn ()
283 * brasero_burn_session_input_supported ()
284 * brasero_burn_session_output_supported ()
285 * brasero_burn_session_can_blank ()
286 * this function gets whether the checks will
287 * ignore the plugins with errors (return %TRUE).
288 *
289 * Returns: #gboolean
290 */
291
292 gboolean
brasero_burn_session_get_strict_support(BraseroBurnSession * session)293 brasero_burn_session_get_strict_support (BraseroBurnSession *session)
294 {
295 BraseroBurnSessionPrivate *priv;
296
297 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (session), FALSE);
298
299 priv = BRASERO_BURN_SESSION_PRIVATE (session);
300 return priv->strict_checks;
301 }
302
303 /**
304 * brasero_burn_session_add_track:
305 * @session: a #BraseroBurnSession.
306 * @new_track: (allow-none): a #BraseroTrack or NULL.
307 * @sibling: (allow-none): a #BraseroTrack or NULL.
308 *
309 * Inserts a new track after @sibling or appended if @sibling is NULL. If @track is NULL then all tracks
310 * already in @session will be removed.
311 * NOTE: if there are already #BraseroTrack objects inserted in the session and if they are not
312 * of the same type as @new_track then they will be removed before the insertion of @new_track.
313 *
314 * Return value: a #BraseroBurnResult. BRASERO_BURN_OK if the track was successfully inserted or BRASERO_BURN_ERR otherwise.
315 **/
316
317 BraseroBurnResult
brasero_burn_session_add_track(BraseroBurnSession * self,BraseroTrack * new_track,BraseroTrack * sibling)318 brasero_burn_session_add_track (BraseroBurnSession *self,
319 BraseroTrack *new_track,
320 BraseroTrack *sibling)
321 {
322 BraseroBurnSessionPrivate *priv;
323
324 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_BURN_ERR);
325
326 priv = BRASERO_BURN_SESSION_PRIVATE (self);
327
328 /* Prevent adding the same tracks several times */
329 if (g_slist_find (priv->tracks, new_track)) {
330 BRASERO_BURN_LOG ("Tried to add the same track multiple times");
331 return BRASERO_BURN_OK;
332 }
333
334 if (!new_track) {
335 if (!priv->tracks)
336 return BRASERO_BURN_OK;
337
338 brasero_burn_session_free_tracks (self);
339 return BRASERO_BURN_OK;
340 }
341
342 g_object_ref (new_track);
343 if (!priv->tracks) {
344 /* we only need to emit the signal here since if there are
345 * multiple tracks they must be exactly of the same type */
346 priv->tracks = g_slist_prepend (NULL, new_track);
347 brasero_burn_session_start_track_monitoring (self, new_track);
348
349 /* if (!brasero_track_type_equal (priv->input, &new_type)) */
350 g_signal_emit (self,
351 brasero_burn_session_signals [TRACK_ADDED_SIGNAL],
352 0,
353 new_track);
354
355 return BRASERO_BURN_OK;
356 }
357
358 /* if there is already a track, then we replace it on condition that it
359 * is not AUDIO (only one type allowed to have several tracks) */
360 if (!BRASERO_IS_TRACK_STREAM (new_track)
361 || !BRASERO_IS_TRACK_STREAM (priv->tracks->data))
362 brasero_burn_session_free_tracks (self);
363
364 brasero_burn_session_start_track_monitoring (self, new_track);
365 if (sibling) {
366 GSList *sibling_node;
367
368 sibling_node = g_slist_find (priv->tracks, sibling);
369 priv->tracks = g_slist_insert_before (priv->tracks,
370 sibling_node,
371 new_track);
372 }
373 else
374 priv->tracks = g_slist_append (priv->tracks, new_track);
375
376 g_signal_emit (self,
377 brasero_burn_session_signals [TRACK_ADDED_SIGNAL],
378 0,
379 new_track);
380
381 return BRASERO_BURN_OK;
382 }
383
384 /**
385 * brasero_burn_session_move_track:
386 * @session: a #BraseroBurnSession.
387 * @track: a #BraseroTrack.
388 * @sibling: (allow-none): a #BraseroTrack or NULL.
389 *
390 * Moves @track after @sibling; if @sibling is NULL then it is appended.
391 *
392 * Return value: a #BraseroBurnResult. BRASERO_BURN_OK if the track was successfully moved or BRASERO_BURN_ERR otherwise.
393 **/
394
395 BraseroBurnResult
brasero_burn_session_move_track(BraseroBurnSession * session,BraseroTrack * track,BraseroTrack * sibling)396 brasero_burn_session_move_track (BraseroBurnSession *session,
397 BraseroTrack *track,
398 BraseroTrack *sibling)
399 {
400 BraseroBurnSessionPrivate *priv;
401 guint former_position;
402
403 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (session), BRASERO_BURN_ERR);
404
405 priv = BRASERO_BURN_SESSION_PRIVATE (session);
406
407 /* Find the track, remove it */
408 former_position = g_slist_index (priv->tracks, track);
409 priv->tracks = g_slist_remove (priv->tracks, track);
410 g_signal_emit (session,
411 brasero_burn_session_signals [TRACK_REMOVED_SIGNAL],
412 0,
413 track,
414 former_position);
415
416 /* Re-add it */
417 if (sibling) {
418 GSList *sibling_node;
419
420 sibling_node = g_slist_find (priv->tracks, sibling);
421 priv->tracks = g_slist_insert_before (priv->tracks,
422 sibling_node,
423 track);
424 }
425 else
426 priv->tracks = g_slist_append (priv->tracks, track);
427
428 g_signal_emit (session,
429 brasero_burn_session_signals [TRACK_ADDED_SIGNAL],
430 0,
431 track);
432
433 return BRASERO_BURN_OK;
434 }
435
436 /**
437 * brasero_burn_session_remove_track:
438 * @session: a #BraseroBurnSession
439 * @track: a #BraseroTrack
440 *
441 * Removes @track from @session.
442 *
443 * Return value: a #BraseroBurnResult. BRASERO_BURN_OK if the track was successfully removed or BRASERO_BURN_ERR otherwise.
444 **/
445
446 BraseroBurnResult
brasero_burn_session_remove_track(BraseroBurnSession * session,BraseroTrack * track)447 brasero_burn_session_remove_track (BraseroBurnSession *session,
448 BraseroTrack *track)
449 {
450 BraseroBurnSessionPrivate *priv;
451 guint former_position;
452
453 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (session), BRASERO_BURN_ERR);
454
455 priv = BRASERO_BURN_SESSION_PRIVATE (session);
456
457 /* Find the track, remove it */
458 former_position = g_slist_index (priv->tracks, track);
459 priv->tracks = g_slist_remove (priv->tracks, track);
460 g_signal_handlers_disconnect_by_func (track,
461 brasero_burn_session_track_changed,
462 session);
463
464 g_signal_emit (session,
465 brasero_burn_session_signals [TRACK_REMOVED_SIGNAL],
466 0,
467 track,
468 former_position);
469
470 g_object_unref (track);
471 return BRASERO_BURN_OK;
472 }
473
474 /**
475 * brasero_burn_session_get_tracks:
476 * @session: a #BraseroBurnSession
477 *
478 * Returns the list of #BraseroTrack added to @session.
479 *
480 * Return value: (element-type BraseroBurn.Track) (transfer none): a #GSList or #BraseroTrack object. Do not unref the objects in the list nor destroy the list.
481 *
482 **/
483
484 GSList *
brasero_burn_session_get_tracks(BraseroBurnSession * self)485 brasero_burn_session_get_tracks (BraseroBurnSession *self)
486 {
487 BraseroBurnSessionPrivate *priv;
488
489 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), NULL);
490
491 priv = BRASERO_BURN_SESSION_PRIVATE (self);
492
493 return priv->tracks;
494 }
495
496 /**
497 * brasero_burn_session_get_status:
498 * @session: a #BraseroBurnSession
499 * @status: a #BraseroTrackStatus
500 *
501 * Sets @status to reflect whether @session is ready to be used.
502 *
503 * Return value: a #BraseroBurnResult.
504 * BRASERO_BURN_OK if it was successful
505 * BRASERO_BURN_NOT_READY if @track needs more time for processing
506 * BRASERO_BURN_ERR if something is wrong or if it is empty
507 **/
508
509 BraseroBurnResult
brasero_burn_session_get_status(BraseroBurnSession * session,BraseroStatus * status)510 brasero_burn_session_get_status (BraseroBurnSession *session,
511 BraseroStatus *status)
512 {
513 BraseroBurnSessionPrivate *priv;
514 BraseroStatus *track_status;
515 gdouble num_tracks = 0.0;
516 guint not_ready = 0;
517 gdouble done = -1.0;
518 GSList *iter;
519
520 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (session), BRASERO_TRACK_TYPE_NONE);
521
522 priv = BRASERO_BURN_SESSION_PRIVATE (session);
523 if (!priv->tracks)
524 return BRASERO_BURN_ERR;
525
526 track_status = brasero_status_new ();
527
528 if (priv->settings->burner && brasero_drive_probing (priv->settings->burner)) {
529 BRASERO_BURN_LOG ("Drive not ready yet");
530 brasero_status_set_not_ready (status, -1, NULL);
531 return BRASERO_BURN_NOT_READY;
532 }
533
534 for (iter = priv->tracks; iter; iter = iter->next) {
535 BraseroTrack *track;
536 BraseroBurnResult result;
537
538 track = iter->data;
539 result = brasero_track_get_status (track, track_status);
540 num_tracks ++;
541
542 if (result == BRASERO_BURN_NOT_READY || result == BRASERO_BURN_RUNNING)
543 not_ready ++;
544 else if (result != BRASERO_BURN_OK) {
545 g_object_unref (track_status);
546 return brasero_track_get_status (track, status);
547 }
548
549 if (brasero_status_get_progress (track_status) != -1.0)
550 done += brasero_status_get_progress (track_status);
551 }
552 g_object_unref (track_status);
553
554 if (not_ready > 0) {
555 if (status) {
556 if (done != -1.0)
557 brasero_status_set_not_ready (status,
558 (gdouble) ((gdouble) (done) / (gdouble) (num_tracks)),
559 NULL);
560 else
561 brasero_status_set_not_ready (status, -1.0, NULL);
562 }
563 return BRASERO_BURN_NOT_READY;
564 }
565
566 if (status)
567 brasero_status_set_completed (status);
568
569 return BRASERO_BURN_OK;
570 }
571
572 /**
573 * brasero_burn_session_get_size:
574 * @session: a #BraseroBurnSession
575 * @blocks: a #goffset or NULL
576 * @bytes: a #goffset or NULL
577 *
578 * Returns the size of the data contained by @session in bytes or in sectors
579 *
580 * Return value: a #BraseroBurnResult.
581 * BRASERO_BURN_OK if it was successful
582 * BRASERO_BURN_NOT_READY if @track needs more time for processing the size
583 * BRASERO_BURN_ERR if something is wrong or if it is empty
584 **/
585
586 BraseroBurnResult
brasero_burn_session_get_size(BraseroBurnSession * session,goffset * blocks,goffset * bytes)587 brasero_burn_session_get_size (BraseroBurnSession *session,
588 goffset *blocks,
589 goffset *bytes)
590 {
591 BraseroBurnSessionPrivate *priv;
592 gsize session_blocks = 0;
593 gsize session_bytes = 0;
594 GSList *iter;
595
596 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (session), BRASERO_TRACK_TYPE_NONE);
597
598 priv = BRASERO_BURN_SESSION_PRIVATE (session);
599 if (!priv->tracks)
600 return BRASERO_BURN_ERR;
601
602 for (iter = priv->tracks; iter; iter = iter->next) {
603 BraseroBurnResult res;
604 BraseroTrack *track;
605 goffset track_blocks;
606 goffset track_bytes;
607
608 track = iter->data;
609 track_blocks = 0;
610 track_bytes = 0;
611
612 res = brasero_track_get_size (track, &track_blocks, &track_bytes);
613
614 /* That way we get the size even if the track has not completed
615 * what's it's doing which allows to show progress */
616 if (res != BRASERO_BURN_OK && res != BRASERO_BURN_NOT_READY)
617 continue;
618
619 session_blocks += track_blocks;
620 session_bytes += track_bytes;
621 }
622
623 if (blocks)
624 *blocks = session_blocks;
625 if (bytes)
626 *bytes = session_bytes;
627
628 return BRASERO_BURN_OK;
629 }
630
631 /**
632 * brasero_burn_session_get_input_type:
633 * @session: a #BraseroBurnSession
634 * @type: a #BraseroTrackType or NULL
635 *
636 * Sets @type to reflect the type of data contained in @session
637 *
638 * Return value: a #BraseroBurnResult.
639 * BRASERO_BURN_OK if it was successful
640 **/
641
642 BraseroBurnResult
brasero_burn_session_get_input_type(BraseroBurnSession * self,BraseroTrackType * type)643 brasero_burn_session_get_input_type (BraseroBurnSession *self,
644 BraseroTrackType *type)
645 {
646 GSList *iter;
647 BraseroStreamFormat format;
648 BraseroBurnSessionPrivate *priv;
649
650 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_BURN_ERR);
651
652 priv = BRASERO_BURN_SESSION_PRIVATE (self);
653
654 /* there can be many tracks (in case of audio) but they must be
655 * all of the same kind for the moment. Yet their subtypes may
656 * be different. */
657 format = BRASERO_AUDIO_FORMAT_NONE;
658 for (iter = priv->tracks; iter; iter = iter->next) {
659 BraseroTrack *track;
660
661 track = iter->data;
662 brasero_track_get_track_type (track, type);
663 if (brasero_track_type_get_has_stream (type))
664 format |= brasero_track_type_get_stream_format (type);
665 }
666
667 if (brasero_track_type_get_has_stream (type))
668 brasero_track_type_set_image_format (type, format);
669
670 return BRASERO_BURN_OK;
671 }
672
673 static void
brasero_burn_session_dest_media_added(BraseroDrive * drive,BraseroMedium * medium,BraseroBurnSession * self)674 brasero_burn_session_dest_media_added (BraseroDrive *drive,
675 BraseroMedium *medium,
676 BraseroBurnSession *self)
677 {
678 /* No medium before */
679 g_signal_emit (self,
680 brasero_burn_session_signals [OUTPUT_CHANGED_SIGNAL],
681 0,
682 NULL);
683 }
684
685 static void
brasero_burn_session_dest_media_removed(BraseroDrive * drive,BraseroMedium * medium,BraseroBurnSession * self)686 brasero_burn_session_dest_media_removed (BraseroDrive *drive,
687 BraseroMedium *medium,
688 BraseroBurnSession *self)
689 {
690 g_signal_emit (self,
691 brasero_burn_session_signals [OUTPUT_CHANGED_SIGNAL],
692 0,
693 medium);
694 }
695
696 /**
697 * brasero_burn_session_set_burner:
698 * @session: a #BraseroBurnSession
699 * @drive: a #BraseroDrive
700 *
701 * Sets the #BraseroDrive that should be used to burn the session contents.
702 *
703 **/
704
705 void
brasero_burn_session_set_burner(BraseroBurnSession * self,BraseroDrive * drive)706 brasero_burn_session_set_burner (BraseroBurnSession *self,
707 BraseroDrive *drive)
708 {
709 BraseroBurnSessionPrivate *priv;
710 BraseroMedium *former;
711
712 g_return_if_fail (BRASERO_IS_BURN_SESSION (self));
713
714 priv = BRASERO_BURN_SESSION_PRIVATE (self);
715
716 if (drive == priv->settings->burner)
717 return;
718
719 former = brasero_drive_get_medium (priv->settings->burner);
720 if (former)
721 g_object_ref (former);
722
723 /* If there was no drive before no need for a changing signal */
724 if (priv->settings->burner) {
725 if (priv->dest_added_sig) {
726 g_signal_handler_disconnect (priv->settings->burner,
727 priv->dest_added_sig);
728 priv->dest_added_sig = 0;
729 }
730
731 if (priv->dest_removed_sig) {
732 g_signal_handler_disconnect (priv->settings->burner,
733 priv->dest_removed_sig);
734 priv->dest_removed_sig = 0;
735 }
736
737 g_object_unref (priv->settings->burner);
738 }
739
740 if (drive) {
741 priv->dest_added_sig = g_signal_connect (drive,
742 "medium-added",
743 G_CALLBACK (brasero_burn_session_dest_media_added),
744 self);
745 priv->dest_removed_sig = g_signal_connect (drive,
746 "medium-removed",
747 G_CALLBACK (brasero_burn_session_dest_media_removed),
748 self);
749 g_object_ref (drive);
750 }
751
752 priv->settings->burner = drive;
753
754 g_signal_emit (self,
755 brasero_burn_session_signals [OUTPUT_CHANGED_SIGNAL],
756 0,
757 former);
758
759 if (former)
760 g_object_unref (former);
761 }
762
763 /**
764 * brasero_burn_session_get_burner:
765 * @session: a #BraseroBurnSession
766 *
767 * Returns the #BraseroDrive that should be used to burn the session contents.
768 *
769 * Return value: (transfer none) (allow-none): a #BraseroDrive or NULL. Do not unref after use.
770 **/
771
772 BraseroDrive *
brasero_burn_session_get_burner(BraseroBurnSession * self)773 brasero_burn_session_get_burner (BraseroBurnSession *self)
774 {
775 BraseroBurnSessionPrivate *priv;
776
777 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), NULL);
778
779 priv = BRASERO_BURN_SESSION_PRIVATE (self);
780 return priv->settings->burner;
781 }
782
783 /**
784 * brasero_burn_session_set_rate:
785 * @session: a #BraseroBurnSession
786 * @rate: a #guint64
787 *
788 * Sets the speed at which the medium should be burnt.
789 * NOTE: before using this function a #BraseroDrive should have been
790 * set with brasero_burn_session_set_burner ().
791 *
792 * Return value: a #BraseroBurnResult.
793 * BRASERO_BURN_OK if it was successful; BRASERO_BURN_ERR otherwise.
794 **/
795
796 BraseroBurnResult
brasero_burn_session_set_rate(BraseroBurnSession * self,guint64 rate)797 brasero_burn_session_set_rate (BraseroBurnSession *self,
798 guint64 rate)
799 {
800 BraseroBurnSessionPrivate *priv;
801
802 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_BURN_ERR);
803
804 priv = BRASERO_BURN_SESSION_PRIVATE (self);
805
806 if (!BRASERO_BURN_SESSION_WRITE_TO_DISC (priv))
807 return BRASERO_BURN_ERR;
808
809 priv->settings->rate = rate;
810 g_object_notify (G_OBJECT (self), "speed");
811 return BRASERO_BURN_OK;
812 }
813
814 /**
815 * brasero_burn_session_get_rate:
816 * @session: a #BraseroBurnSession
817 *
818 * Returns the speed at which the medium should be burnt.
819 * NOTE: before using this function a #BraseroDrive should have been
820 * set with brasero_burn_session_set_burner ().
821 *
822 * Return value: a #guint64 or 0.
823 **/
824
825 guint64
brasero_burn_session_get_rate(BraseroBurnSession * self)826 brasero_burn_session_get_rate (BraseroBurnSession *self)
827 {
828 BraseroBurnSessionPrivate *priv;
829 BraseroMedium *medium;
830 gint64 max_rate;
831
832 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), 0);
833
834 priv = BRASERO_BURN_SESSION_PRIVATE (self);
835
836 if (!BRASERO_BURN_SESSION_WRITE_TO_DISC (priv))
837 return 0;
838
839 medium = brasero_drive_get_medium (priv->settings->burner);
840 if (!medium)
841 return 0;
842
843 max_rate = brasero_medium_get_max_write_speed (medium);
844 if (priv->settings->rate <= 0)
845 return max_rate;
846 else
847 return MIN (max_rate, priv->settings->rate);
848 }
849
850 /**
851 * brasero_burn_session_get_output_type:
852 * @session: a #BraseroBurnSession
853 * @output: a #BraseroTrackType or NULL
854 *
855 * This function returns the type of output set for the session.
856 *
857 * Return value: a #BraseroBurnResult.
858 * BRASERO_BURN_OK if it was successful; BRASERO_BURN_NOT_READY if no setting has been set; BRASERO_BURN_ERR otherwise.
859 **/
860 BraseroBurnResult
brasero_burn_session_get_output_type(BraseroBurnSession * self,BraseroTrackType * output)861 brasero_burn_session_get_output_type (BraseroBurnSession *self,
862 BraseroTrackType *output)
863 {
864 BraseroBurnSessionPrivate *priv;
865
866 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_BURN_ERR);
867
868 priv = BRASERO_BURN_SESSION_PRIVATE (self);
869 if (!priv->settings->burner)
870 return BRASERO_BURN_NOT_READY;
871
872 if (brasero_drive_is_fake (priv->settings->burner)) {
873 brasero_track_type_set_has_image (output);
874 brasero_track_type_set_image_format (output, brasero_burn_session_get_output_format (self));
875 }
876 else {
877 brasero_track_type_set_has_medium (output);
878 brasero_track_type_set_medium_type (output, brasero_medium_get_status (brasero_drive_get_medium (priv->settings->burner)));
879 }
880
881 return BRASERO_BURN_OK;
882 }
883
884 /**
885 * brasero_burn_session_get_output:
886 * @session: a #BraseroBurnSession.
887 * @image: (allow-none) (out): a #gchar to store the image path or NULL.
888 * @toc: (allow-none) (out): a #gchar to store the toc path or NULL.
889 *
890 * When the contents of @session should be written to a
891 * file then this function returns the image path (and if
892 * necessary a toc path).
893 * @image and @toc should be freed if not used anymore.
894 *
895 * NOTE: before using this function a #BraseroDrive should have been
896 * set with brasero_burn_session_set_burner () and it should be the
897 * fake drive (see brasero_drive_is_fake ()).
898 *
899 * Return value: a #BraseroBurnResult.
900 * BRASERO_BURN_OK if it was successful; BRASERO_BURN_ERR otherwise.
901 **/
902
903 BraseroBurnResult
brasero_burn_session_get_output(BraseroBurnSession * self,gchar ** image,gchar ** toc)904 brasero_burn_session_get_output (BraseroBurnSession *self,
905 gchar **image,
906 gchar **toc)
907 {
908 BraseroBurnSessionClass *klass;
909 BraseroBurnSessionPrivate *priv;
910
911 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_IMAGE_FORMAT_NONE);
912
913 priv = BRASERO_BURN_SESSION_PRIVATE (self);
914 if (!BRASERO_BURN_SESSION_WRITE_TO_FILE (priv)) {
915 BRASERO_BURN_LOG ("no file disc");
916 return BRASERO_BURN_ERR;
917 }
918
919 klass = BRASERO_BURN_SESSION_GET_CLASS (self);
920 return klass->get_output_path (self, image, toc);
921 }
922
923
924 static BraseroBurnResult
brasero_burn_session_get_output_path_real(BraseroBurnSession * self,gchar ** image_ret,gchar ** toc_ret)925 brasero_burn_session_get_output_path_real (BraseroBurnSession *self,
926 gchar **image_ret,
927 gchar **toc_ret)
928 {
929 gchar *toc = NULL;
930 gchar *image = NULL;
931 BraseroBurnSessionPrivate *priv;
932
933 priv = BRASERO_BURN_SESSION_PRIVATE (self);
934
935 image = g_strdup (priv->settings->image);
936 toc = g_strdup (priv->settings->toc);
937 if (!image && !toc)
938 return BRASERO_BURN_ERR;
939
940 if (image_ret) {
941 /* output paths were set so test them and returns them if OK */
942 if (!image && toc) {
943 gchar *complement;
944 BraseroImageFormat format;
945
946 /* get the cuesheet complement */
947 format = brasero_burn_session_get_output_format (self);
948 complement = brasero_image_format_get_complement (format, toc);
949 if (!complement) {
950 BRASERO_BURN_LOG ("no output specified");
951 g_free (toc);
952 return BRASERO_BURN_ERR;
953 }
954
955 *image_ret = complement;
956 }
957 else if (image)
958 *image_ret = image;
959 else {
960 BRASERO_BURN_LOG ("no output specified");
961 return BRASERO_BURN_ERR;
962 }
963 }
964 else
965 g_free (image);
966
967 if (toc_ret)
968 *toc_ret = toc;
969 else
970 g_free (toc);
971
972 return BRASERO_BURN_OK;
973 }
974
975 /**
976 * brasero_burn_session_get_output_format:
977 * @session: a #BraseroBurnSession
978 *
979 * When the contents of @session should be written to a
980 * file then this function returns the format of the image to write.
981 *
982 * NOTE: before using this function a #BraseroDrive should have been
983 * set with brasero_burn_session_set_burner () and it should be the
984 * fake drive (see brasero_drive_is_fake ()).
985 *
986 * Return value: a #BraseroImageFormat. The format of the image to be written.
987 **/
988
989 BraseroImageFormat
brasero_burn_session_get_output_format(BraseroBurnSession * self)990 brasero_burn_session_get_output_format (BraseroBurnSession *self)
991 {
992 BraseroBurnSessionClass *klass;
993 BraseroBurnSessionPrivate *priv;
994
995 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_IMAGE_FORMAT_NONE);
996
997 priv = BRASERO_BURN_SESSION_PRIVATE (self);
998 if (!BRASERO_BURN_SESSION_WRITE_TO_FILE (priv))
999 return BRASERO_IMAGE_FORMAT_NONE;
1000
1001 klass = BRASERO_BURN_SESSION_GET_CLASS (self);
1002 return klass->get_output_format (self);
1003 }
1004
1005 static BraseroImageFormat
brasero_burn_session_get_output_format_real(BraseroBurnSession * self)1006 brasero_burn_session_get_output_format_real (BraseroBurnSession *self)
1007 {
1008 BraseroBurnSessionPrivate *priv;
1009
1010 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1011 return priv->settings->format;
1012 }
1013
1014 /**
1015 * This function allows to tell where we should write the image. Depending on
1016 * the type of image it can be a toc (cue) or the path of the image (all others)
1017 */
1018
1019 static void
brasero_burn_session_set_image_output_real(BraseroBurnSession * self,BraseroImageFormat format,const gchar * image,const gchar * toc)1020 brasero_burn_session_set_image_output_real (BraseroBurnSession *self,
1021 BraseroImageFormat format,
1022 const gchar *image,
1023 const gchar *toc)
1024 {
1025 BraseroBurnSessionPrivate *priv;
1026
1027 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1028
1029 if (priv->settings->image)
1030 g_free (priv->settings->image);
1031
1032 if (image)
1033 priv->settings->image = g_strdup (image);
1034 else
1035 priv->settings->image = NULL;
1036
1037 if (priv->settings->toc)
1038 g_free (priv->settings->toc);
1039
1040 if (toc)
1041 priv->settings->toc = g_strdup (toc);
1042 else
1043 priv->settings->toc = NULL;
1044
1045 priv->settings->format = format;
1046 }
1047
1048 static void
brasero_burn_session_set_fake_drive(BraseroBurnSession * self)1049 brasero_burn_session_set_fake_drive (BraseroBurnSession *self)
1050 {
1051 BraseroMediumMonitor *monitor;
1052 BraseroDrive *drive;
1053 GSList *list;
1054
1055 /* NOTE: changing/changed signals are handled in
1056 * set_burner (). */
1057 monitor = brasero_medium_monitor_get_default ();
1058 list = brasero_medium_monitor_get_media (monitor, BRASERO_MEDIA_TYPE_FILE);
1059 drive = brasero_medium_get_drive (list->data);
1060 brasero_burn_session_set_burner (self, drive);
1061 g_object_unref (monitor);
1062 g_slist_free (list);
1063 }
1064
1065 static BraseroBurnResult
brasero_burn_session_set_output_image_real(BraseroBurnSession * self,BraseroImageFormat format,const gchar * image,const gchar * toc)1066 brasero_burn_session_set_output_image_real (BraseroBurnSession *self,
1067 BraseroImageFormat format,
1068 const gchar *image,
1069 const gchar *toc)
1070 {
1071 BraseroBurnSessionPrivate *priv;
1072
1073 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1074
1075 if (priv->settings->format == format
1076 && BRASERO_STR_EQUAL (image, priv->settings->image)
1077 && BRASERO_STR_EQUAL (toc, priv->settings->toc)) {
1078 if (!BRASERO_BURN_SESSION_WRITE_TO_FILE (priv))
1079 brasero_burn_session_set_fake_drive (self);
1080
1081 return BRASERO_BURN_OK;
1082 }
1083
1084 brasero_burn_session_set_image_output_real (self, format, image, toc);
1085 if (BRASERO_BURN_SESSION_WRITE_TO_FILE (priv))
1086 g_signal_emit (self,
1087 brasero_burn_session_signals [OUTPUT_CHANGED_SIGNAL],
1088 0,
1089 brasero_drive_get_medium (priv->settings->burner));
1090 else
1091 brasero_burn_session_set_fake_drive (self);
1092
1093 return BRASERO_BURN_OK;
1094 }
1095
1096 /**
1097 * brasero_burn_session_set_image_output_format:
1098 * @session: a #BraseroBurnSession
1099 * @format: a #BraseroImageFormat
1100 *
1101 * When the contents of @session should be written to a
1102 * file, this function sets format of the image that will be
1103 * created.
1104 *
1105 * NOTE: after a call to this function the #BraseroDrive for
1106 * @session will be the fake #BraseroDrive.
1107 *
1108 * Since 2.29.0
1109 *
1110 * Return value: a #BraseroBurnResult. BRASERO_BURN_OK if it was successfully set;
1111 * BRASERO_BURN_ERR otherwise.
1112 **/
1113
1114 BraseroBurnResult
brasero_burn_session_set_image_output_format(BraseroBurnSession * self,BraseroImageFormat format)1115 brasero_burn_session_set_image_output_format (BraseroBurnSession *self,
1116 BraseroImageFormat format)
1117 {
1118 BraseroBurnSessionClass *klass;
1119 BraseroBurnSessionPrivate *priv;
1120 BraseroBurnResult res;
1121 gchar *image;
1122 gchar *toc;
1123
1124 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_BURN_ERR);
1125
1126 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1127 klass = BRASERO_BURN_SESSION_GET_CLASS (self);
1128
1129 image = g_strdup (priv->settings->image);
1130 toc = g_strdup (priv->settings->toc);
1131 res = klass->set_output_image (self, format, image, toc);
1132 g_free (image);
1133 g_free (toc);
1134
1135 return res;
1136 }
1137
1138 /**
1139 * brasero_burn_session_set_image_output_full:
1140 * @session: a #BraseroBurnSession.
1141 * @format: a #BraseroImageFormat.
1142 * @image: (allow-none): a #gchar or NULL.
1143 * @toc: (allow-none): a #gchar or NULL.
1144 *
1145 * When the contents of @session should be written to a
1146 * file, this function sets the different parameters of this
1147 * image like its path (and the one of the associated toc if
1148 * necessary) and its format.
1149 *
1150 * NOTE: after a call to this function the #BraseroDrive for
1151 * @session will be the fake #BraseroDrive.
1152 *
1153 * Return value: a #BraseroBurnResult. BRASERO_BURN_OK if it was successfully set;
1154 * BRASERO_BURN_ERR otherwise.
1155 **/
1156
1157 BraseroBurnResult
brasero_burn_session_set_image_output_full(BraseroBurnSession * self,BraseroImageFormat format,const gchar * image,const gchar * toc)1158 brasero_burn_session_set_image_output_full (BraseroBurnSession *self,
1159 BraseroImageFormat format,
1160 const gchar *image,
1161 const gchar *toc)
1162 {
1163 BraseroBurnSessionClass *klass;
1164
1165 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_BURN_ERR);
1166
1167 klass = BRASERO_BURN_SESSION_GET_CLASS (self);
1168 return klass->set_output_image (self, format, image, toc);
1169 }
1170
1171 /**
1172 * brasero_burn_session_set_tmpdir:
1173 * @session: a #BraseroBurnSession
1174 * @path: a #gchar or NULL
1175 *
1176 * Sets the path of the directory in which to write temporary directories and files.
1177 * If set to NULL then the result of g_get_tmp_dir () will be used.
1178 *
1179 * Return value: a #BraseroBurnResult. BRASERO_BURN_OK if it was successfully set;
1180 * BRASERO_BURN_ERR otherwise.
1181 **/
1182
1183 BraseroBurnResult
brasero_burn_session_set_tmpdir(BraseroBurnSession * self,const gchar * path)1184 brasero_burn_session_set_tmpdir (BraseroBurnSession *self,
1185 const gchar *path)
1186 {
1187 BraseroBurnSessionPrivate *priv;
1188
1189 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_BURN_ERR);
1190
1191 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1192
1193 if (!g_strcmp0 (priv->tmpdir, path))
1194 return BRASERO_BURN_OK;
1195
1196 if (!path) {
1197 g_free (priv->tmpdir);
1198 priv->tmpdir = NULL;
1199 g_object_notify (G_OBJECT (self), "tmpdir");
1200 return BRASERO_BURN_OK;
1201 }
1202
1203 if (!g_str_has_prefix (path, G_DIR_SEPARATOR_S))
1204 return BRASERO_BURN_ERR;
1205
1206 g_free (priv->tmpdir);
1207 priv->tmpdir = g_strdup (path);
1208 g_object_notify (G_OBJECT (self), "tmpdir");
1209
1210 return BRASERO_BURN_OK;
1211 }
1212
1213 /**
1214 * brasero_burn_session_get_tmpdir:
1215 * @session: a #BraseroBurnSession
1216 *
1217 * Returns the path of the directory in which to write temporary directories and files.
1218 *
1219 * Return value: a #gchar. The path to the temporary directory.
1220 **/
1221
1222 const gchar *
brasero_burn_session_get_tmpdir(BraseroBurnSession * self)1223 brasero_burn_session_get_tmpdir (BraseroBurnSession *self)
1224 {
1225 BraseroBurnSessionPrivate *priv;
1226
1227 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), NULL);
1228
1229 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1230 return priv->tmpdir? priv->tmpdir:g_get_tmp_dir ();
1231 }
1232
1233 /**
1234 * brasero_burn_session_get_tmp_dir:
1235 * @session: a #BraseroBurnSession
1236 * @path: a #gchar or NULL
1237 * @error: a #GError
1238 *
1239 * Creates then returns (in @path) a temporary directory at the proper location.
1240 * On error, @error is set appropriately.
1241 * See brasero_burn_session_set_tmpdir ().
1242 * This function is used internally and is not public API.
1243 *
1244 * Return value: a #BraseroBurnResult. BRASERO_BURN_OK if it was successfully set;
1245 * BRASERO_BURN_ERR otherwise.
1246 **/
1247
1248 BraseroBurnResult
brasero_burn_session_get_tmp_dir(BraseroBurnSession * self,gchar ** path,GError ** error)1249 brasero_burn_session_get_tmp_dir (BraseroBurnSession *self,
1250 gchar **path,
1251 GError **error)
1252 {
1253 gchar *tmp;
1254 const gchar *tmpdir;
1255 BraseroBurnSessionPrivate *priv;
1256
1257 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_BURN_ERR);
1258
1259 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1260
1261 /* create a working directory in tmp */
1262 tmpdir = priv->tmpdir ?
1263 priv->tmpdir :
1264 g_get_tmp_dir ();
1265
1266 tmp = g_build_path (G_DIR_SEPARATOR_S,
1267 tmpdir,
1268 BRASERO_BURN_TMP_FILE_NAME,
1269 NULL);
1270
1271 *path = g_mkdtemp (tmp);
1272 if (*path == NULL) {
1273 int errsv = errno;
1274
1275 BRASERO_BURN_LOG ("Impossible to create tmp directory");
1276 g_free (tmp);
1277 if (errsv != EACCES)
1278 g_set_error (error,
1279 BRASERO_BURN_ERROR,
1280 BRASERO_BURN_ERROR_TMP_DIRECTORY,
1281 "%s",
1282 g_strerror (errsv));
1283 else
1284 g_set_error (error,
1285 BRASERO_BURN_ERROR,
1286 BRASERO_BURN_ERROR_TMP_DIRECTORY,
1287 _("You do not have the required permission to write at this location"));
1288 return BRASERO_BURN_ERR;
1289 }
1290
1291 /* this must be removed when session is completly unreffed */
1292 priv->tmpfiles = g_slist_prepend (priv->tmpfiles, g_strdup (tmp));
1293
1294 return BRASERO_BURN_OK;
1295 }
1296
1297 /**
1298 * brasero_burn_session_get_tmp_file:
1299 * @session: a #BraseroBurnSession
1300 * @suffix: a #gchar
1301 * @path: a #gchar or NULL
1302 * @error: a #GError
1303 *
1304 * Creates then returns (in @path) a temporary file at the proper location. Its name
1305 * will be appended with suffix.
1306 * On error, @error is set appropriately.
1307 * See brasero_burn_session_set_tmpdir ().
1308 * This function is used internally and is not public API.
1309 *
1310 * Return value: a #BraseroBurnResult. BRASERO_BURN_OK if it was successfully set;
1311 * BRASERO_BURN_ERR otherwise.
1312 **/
1313
1314 BraseroBurnResult
brasero_burn_session_get_tmp_file(BraseroBurnSession * self,const gchar * suffix,gchar ** path,GError ** error)1315 brasero_burn_session_get_tmp_file (BraseroBurnSession *self,
1316 const gchar *suffix,
1317 gchar **path,
1318 GError **error)
1319 {
1320 BraseroBurnSessionPrivate *priv;
1321 const gchar *tmpdir;
1322 gchar *name;
1323 gchar *tmp;
1324 int fd;
1325
1326 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_BURN_ERR);
1327
1328 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1329
1330 if (!path)
1331 return BRASERO_BURN_OK;
1332
1333 /* takes care of the output file */
1334 tmpdir = priv->tmpdir ?
1335 priv->tmpdir :
1336 g_get_tmp_dir ();
1337
1338 name = g_strconcat (BRASERO_BURN_TMP_FILE_NAME, suffix, NULL);
1339 tmp = g_build_path (G_DIR_SEPARATOR_S,
1340 tmpdir,
1341 name,
1342 NULL);
1343 g_free (name);
1344
1345 fd = g_mkstemp (tmp);
1346 if (fd == -1) {
1347 int errsv = errno;
1348
1349 BRASERO_BURN_LOG ("Impossible to create tmp file %s", tmp);
1350
1351 g_free (tmp);
1352 if (errsv != EACCES)
1353 g_set_error (error,
1354 BRASERO_BURN_ERROR,
1355 BRASERO_BURN_ERROR_TMP_DIRECTORY,
1356 "%s",
1357 g_strerror (errsv));
1358 else
1359 g_set_error (error,
1360 BRASERO_BURN_ERROR,
1361 BRASERO_BURN_ERROR_TMP_DIRECTORY,
1362 _("You do not have the required permission to write at this location"));
1363
1364 return BRASERO_BURN_ERR;
1365 }
1366
1367 /* this must be removed when session is completly unreffed */
1368 priv->tmpfiles = g_slist_prepend (priv->tmpfiles,
1369 g_strdup (tmp));
1370
1371 close (fd);
1372 *path = tmp;
1373 return BRASERO_BURN_OK;
1374 }
1375
1376 static gchar *
brasero_burn_session_get_image_complement(BraseroBurnSession * self,BraseroImageFormat format,const gchar * path)1377 brasero_burn_session_get_image_complement (BraseroBurnSession *self,
1378 BraseroImageFormat format,
1379 const gchar *path)
1380 {
1381 gchar *retval = NULL;
1382
1383 if (format == BRASERO_IMAGE_FORMAT_CLONE)
1384 retval = g_strdup_printf ("%s.toc", path);
1385 else if (format == BRASERO_IMAGE_FORMAT_CUE) {
1386 if (g_str_has_suffix (path, ".bin"))
1387 retval = g_strdup_printf ("%.*scue",
1388 (int) strlen (path) - 3,
1389 path);
1390 else
1391 retval = g_strdup_printf ("%s.cue", path);
1392 }
1393 else if (format == BRASERO_IMAGE_FORMAT_CDRDAO) {
1394 if (g_str_has_suffix (path, ".bin"))
1395 retval = g_strdup_printf ("%.*stoc",
1396 (int) strlen (path) - 3,
1397 path);
1398 else
1399 retval = g_strdup_printf ("%s.toc", path);
1400 }
1401 else
1402 retval = NULL;
1403
1404 return retval;
1405 }
1406
1407 /**
1408 * This function is used internally and is not public API
1409 */
1410
1411 BraseroBurnResult
brasero_burn_session_get_tmp_image(BraseroBurnSession * self,BraseroImageFormat format,gchar ** image,gchar ** toc,GError ** error)1412 brasero_burn_session_get_tmp_image (BraseroBurnSession *self,
1413 BraseroImageFormat format,
1414 gchar **image,
1415 gchar **toc,
1416 GError **error)
1417 {
1418 BraseroBurnSessionPrivate *priv;
1419 BraseroBurnResult result;
1420 gchar *complement = NULL;
1421 gchar *path = NULL;
1422
1423 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_BURN_ERR);
1424
1425 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1426
1427 /* Image tmp file */
1428 result = brasero_burn_session_get_tmp_file (self,
1429 (format == BRASERO_IMAGE_FORMAT_CLONE)? NULL:".bin",
1430 &path,
1431 error);
1432 if (result != BRASERO_BURN_OK)
1433 return result;
1434
1435 if (format != BRASERO_IMAGE_FORMAT_BIN) {
1436 /* toc tmp file */
1437 complement = brasero_burn_session_get_image_complement (self, format, path);
1438 if (complement) {
1439 /* That shouldn't happen ... */
1440 if (g_file_test (complement, G_FILE_TEST_EXISTS)) {
1441 g_free (complement);
1442 return BRASERO_BURN_ERR;
1443 }
1444 }
1445 }
1446
1447 if (complement)
1448 priv->tmpfiles = g_slist_prepend (priv->tmpfiles,
1449 g_strdup (complement));
1450
1451 if (image)
1452 *image = path;
1453 else
1454 g_free (path);
1455
1456 if (toc)
1457 *toc = complement;
1458 else
1459 g_free (complement);
1460
1461 return BRASERO_BURN_OK;
1462 }
1463
1464 /**
1465 * used to modify session flags.
1466 */
1467
1468 /**
1469 * brasero_burn_session_set_flags:
1470 * @session: a #BraseroBurnSession
1471 * @flags: a #BraseroBurnFlag
1472 *
1473 * Replaces the current flags set in @session with @flags.
1474 *
1475 **/
1476
1477 void
brasero_burn_session_set_flags(BraseroBurnSession * self,BraseroBurnFlag flags)1478 brasero_burn_session_set_flags (BraseroBurnSession *self,
1479 BraseroBurnFlag flags)
1480 {
1481 BraseroBurnSessionPrivate *priv;
1482
1483 g_return_if_fail (BRASERO_IS_BURN_SESSION (self));
1484
1485 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1486 if (priv->settings->flags == flags)
1487 return;
1488
1489 priv->settings->flags = flags;
1490 g_object_notify (G_OBJECT (self), "flags");
1491 }
1492
1493 /**
1494 * brasero_burn_session_add_flag:
1495 * @session: a #BraseroBurnSession
1496 * @flags: a #BraseroBurnFlag
1497 *
1498 * Merges the current flags set in @session with @flags.
1499 *
1500 **/
1501
1502 void
brasero_burn_session_add_flag(BraseroBurnSession * self,BraseroBurnFlag flag)1503 brasero_burn_session_add_flag (BraseroBurnSession *self,
1504 BraseroBurnFlag flag)
1505 {
1506 BraseroBurnSessionPrivate *priv;
1507
1508 g_return_if_fail (BRASERO_IS_BURN_SESSION (self));
1509
1510 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1511 if ((priv->settings->flags & flag) == flag)
1512 return;
1513
1514 priv->settings->flags |= flag;
1515 g_object_notify (G_OBJECT (self), "flags");
1516 }
1517
1518 /**
1519 * brasero_burn_session_remove_flag:
1520 * @session: a #BraseroBurnSession
1521 * @flags: a #BraseroBurnFlag
1522 *
1523 * Removes @flags from the current flags set for @session.
1524 *
1525 **/
1526
1527 void
brasero_burn_session_remove_flag(BraseroBurnSession * self,BraseroBurnFlag flag)1528 brasero_burn_session_remove_flag (BraseroBurnSession *self,
1529 BraseroBurnFlag flag)
1530 {
1531 BraseroBurnSessionPrivate *priv;
1532
1533 g_return_if_fail (BRASERO_IS_BURN_SESSION (self));
1534
1535 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1536 if ((priv->settings->flags & flag) == 0)
1537 return;
1538
1539 priv->settings->flags &= ~flag;
1540 g_object_notify (G_OBJECT (self), "flags");
1541 }
1542
1543 /**
1544 * brasero_burn_session_get_flags:
1545 * @session: a #BraseroBurnSession
1546 *
1547 * Returns the current flags set for @session.
1548 *
1549 * Return value: a #BraseroBurnFlag.
1550 **/
1551
1552 BraseroBurnFlag
brasero_burn_session_get_flags(BraseroBurnSession * self)1553 brasero_burn_session_get_flags (BraseroBurnSession *self)
1554 {
1555 BraseroBurnSessionPrivate *priv;
1556
1557 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_BURN_ERR);
1558
1559 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1560 return priv->settings->flags;
1561 }
1562
1563 /**
1564 * Used to set the label or the title of an album.
1565 */
1566
1567 /**
1568 * brasero_burn_session_set_label:
1569 * @session: a #BraseroBurnSession
1570 * @label: (allow-none): a #gchar or %NULL
1571 *
1572 * Sets the label for @session.
1573 *
1574 **/
1575
1576 void
brasero_burn_session_set_label(BraseroBurnSession * self,const gchar * label)1577 brasero_burn_session_set_label (BraseroBurnSession *self,
1578 const gchar *label)
1579 {
1580 BraseroBurnSessionPrivate *priv;
1581
1582 g_return_if_fail (BRASERO_IS_BURN_SESSION (self));
1583
1584 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1585 if (priv->settings->label)
1586 g_free (priv->settings->label);
1587
1588 priv->settings->label = NULL;
1589
1590 if (label) {
1591 if (strlen (label) > 32) {
1592 const gchar *delim;
1593 gchar *next_char;
1594
1595 /* find last possible character. We can't just do a tmp
1596 * + 32 since we don't know if we are at the start of a
1597 * character */
1598 delim = label;
1599 while ((next_char = g_utf8_find_next_char (delim, NULL))) {
1600 if (next_char - label > 32)
1601 break;
1602
1603 delim = next_char;
1604 }
1605
1606 priv->settings->label = g_strndup (label, delim - label);
1607 }
1608 else
1609 priv->settings->label = g_strdup (label);
1610 }
1611 }
1612
1613 /**
1614 * brasero_burn_session_get_label:
1615 * @session: a #BraseroBurnSession
1616 *
1617 * Returns the label (a string) set for @session.
1618 *
1619 * Return value: a #gchar or NULL. Do not free after use.
1620 **/
1621
1622 const gchar *
brasero_burn_session_get_label(BraseroBurnSession * self)1623 brasero_burn_session_get_label (BraseroBurnSession *self)
1624 {
1625 BraseroBurnSessionPrivate *priv;
1626
1627 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), NULL);
1628
1629 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1630 return priv->settings->label;
1631 }
1632
1633 static void
brasero_burn_session_tag_value_free(gpointer user_data)1634 brasero_burn_session_tag_value_free (gpointer user_data)
1635 {
1636 GValue *value = user_data;
1637
1638 g_value_reset (value);
1639 g_free (value);
1640 }
1641
1642 /**
1643 * brasero_burn_session_tag_remove:
1644 * @session: a #BraseroBurnSession
1645 * @tag: a #gchar *
1646 *
1647 * Removes a value associated with @session through
1648 * brasero_session_tag_add ().
1649 *
1650 * Return value: a #BraseroBurnResult.
1651 * BRASERO_BURN_OK if the retrieval was successful
1652 * BRASERO_BURN_ERR otherwise
1653 **/
1654
1655 BraseroBurnResult
brasero_burn_session_tag_remove(BraseroBurnSession * self,const gchar * tag)1656 brasero_burn_session_tag_remove (BraseroBurnSession *self,
1657 const gchar *tag)
1658 {
1659 BraseroBurnSessionPrivate *priv;
1660
1661 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_BURN_ERR);
1662 g_return_val_if_fail (tag != NULL, BRASERO_BURN_ERR);
1663
1664 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1665 if (!priv->tags)
1666 return BRASERO_BURN_ERR;
1667
1668 g_hash_table_remove (priv->tags, tag);
1669
1670 g_signal_emit (self,
1671 brasero_burn_session_signals [TAG_CHANGED_SIGNAL],
1672 0,
1673 tag);
1674 return BRASERO_BURN_OK;
1675 }
1676
1677 /**
1678 * brasero_burn_session_tag_add:
1679 * @session: a #BraseroBurnSession
1680 * @tag: a #gchar *
1681 * @value: a #GValue *
1682 *
1683 * Associates a new @tag with @session. This can be used
1684 * to pass arbitrary information for plugins, like parameters
1685 * for video discs, ...
1686 * NOTE: the #BraseroBurnSession object takes ownership of @value.
1687 * See brasero-tags.h for a list of knowns tags.
1688 *
1689 * Return value: a #BraseroBurnResult.
1690 * BRASERO_BURN_OK if it was successful,
1691 * BRASERO_BURN_ERR otherwise.
1692 **/
1693
1694 BraseroBurnResult
brasero_burn_session_tag_add(BraseroBurnSession * self,const gchar * tag,GValue * value)1695 brasero_burn_session_tag_add (BraseroBurnSession *self,
1696 const gchar *tag,
1697 GValue *value)
1698 {
1699 BraseroBurnSessionPrivate *priv;
1700
1701 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_BURN_ERR);
1702 g_return_val_if_fail (tag != NULL, BRASERO_BURN_ERR);
1703
1704 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1705 if (!priv->tags)
1706 priv->tags = g_hash_table_new_full (g_str_hash,
1707 g_str_equal,
1708 g_free,
1709 brasero_burn_session_tag_value_free);
1710 g_hash_table_insert (priv->tags, g_strdup (tag), value);
1711 g_signal_emit (self,
1712 brasero_burn_session_signals [TAG_CHANGED_SIGNAL],
1713 0,
1714 tag);
1715
1716 return BRASERO_BURN_OK;
1717 }
1718
1719 /**
1720 * brasero_burn_session_tag_add_int:
1721 * @session: a #BraseroBurnSession
1722 * @tag: a #gchar *
1723 * @value: a #gint
1724 *
1725 * Associates a new @tag with @session. This can be used
1726 * to pass arbitrary information for plugins, like parameters
1727 * for video discs, ...
1728 * See brasero-tags.h for a list of knowns tags.
1729 *
1730 * Since 2.29.0
1731 *
1732 * Return value: a #BraseroBurnResult.
1733 * BRASERO_BURN_OK if it was successful,
1734 * BRASERO_BURN_ERR otherwise.
1735 **/
1736
1737 BraseroBurnResult
brasero_burn_session_tag_add_int(BraseroBurnSession * self,const gchar * tag,gint value)1738 brasero_burn_session_tag_add_int (BraseroBurnSession *self,
1739 const gchar *tag,
1740 gint value)
1741 {
1742 GValue *gvalue;
1743
1744 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_BURN_ERR);
1745 g_return_val_if_fail (tag != NULL, BRASERO_BURN_ERR);
1746
1747 gvalue = g_new0 (GValue, 1);
1748 g_value_init (gvalue, G_TYPE_INT);
1749 g_value_set_int (gvalue, value);
1750
1751 return brasero_burn_session_tag_add (self, tag, gvalue);
1752 }
1753
1754 /**
1755 * brasero_burn_session_tag_lookup:
1756 * @session: a #BraseroBurnSession
1757 * @tag: a #gchar *
1758 * @value: a #GValue
1759 *
1760 * Retrieves a value associated with @session through
1761 * brasero_session_tag_add () and stores it in @value. Do
1762 * not destroy @value afterwards as it is not a copy.
1763 *
1764 * Return value: a #BraseroBurnResult.
1765 * BRASERO_BURN_OK if the retrieval was successful
1766 * BRASERO_BURN_ERR otherwise
1767 **/
1768
1769 BraseroBurnResult
brasero_burn_session_tag_lookup(BraseroBurnSession * self,const gchar * tag,GValue ** value)1770 brasero_burn_session_tag_lookup (BraseroBurnSession *self,
1771 const gchar *tag,
1772 GValue **value)
1773 {
1774 BraseroBurnSessionPrivate *priv;
1775 gpointer data;
1776
1777 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_BURN_ERR);
1778 g_return_val_if_fail (tag != NULL, BRASERO_BURN_ERR);
1779
1780 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1781 if (!value)
1782 return BRASERO_BURN_ERR;
1783
1784 if (!priv->tags)
1785 return BRASERO_BURN_ERR;
1786
1787 data = g_hash_table_lookup (priv->tags, tag);
1788 if (!data)
1789 return BRASERO_BURN_ERR;
1790
1791 /* value can be NULL if the function was just called
1792 * to check whether a tag was set. */
1793 if (value)
1794 *value = data;
1795 return BRASERO_BURN_OK;
1796 }
1797
1798 /**
1799 * brasero_burn_session_tag_lookup_int:
1800 * @session: a #BraseroBurnSession
1801 * @tag: a #gchar
1802 *
1803 * Retrieves an int value associated with @session through
1804 * brasero_session_tag_add () and returns it.
1805 *
1806 * Since 2.29.0
1807 *
1808 * Return value: a #gint.
1809 **/
1810
1811 gint
brasero_burn_session_tag_lookup_int(BraseroBurnSession * self,const gchar * tag)1812 brasero_burn_session_tag_lookup_int (BraseroBurnSession *self,
1813 const gchar *tag)
1814 {
1815 GValue *value = NULL;
1816
1817 brasero_burn_session_tag_lookup (self, tag, &value);
1818 if (!value || !G_VALUE_HOLDS_INT (value))
1819 return 0;
1820
1821 return g_value_get_int (value);
1822 }
1823
1824 /**
1825 * Used to save and restore settings/sources
1826 */
1827
1828 void
brasero_burn_session_push_settings(BraseroBurnSession * self)1829 brasero_burn_session_push_settings (BraseroBurnSession *self)
1830 {
1831 BraseroSessionSetting *settings;
1832 BraseroBurnSessionPrivate *priv;
1833
1834 g_return_if_fail (BRASERO_IS_BURN_SESSION (self));
1835
1836 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1837
1838 /* NOTE: don't clean the settings so no need to issue a signal */
1839 settings = g_new0 (BraseroSessionSetting, 1);
1840 brasero_session_settings_copy (settings, priv->settings);
1841 priv->pile_settings = g_slist_prepend (priv->pile_settings, settings);
1842 }
1843
1844 void
brasero_burn_session_pop_settings(BraseroBurnSession * self)1845 brasero_burn_session_pop_settings (BraseroBurnSession *self)
1846 {
1847 BraseroSessionSetting *settings;
1848 BraseroBurnSessionPrivate *priv;
1849 BraseroMedium *former;
1850
1851 g_return_if_fail (BRASERO_IS_BURN_SESSION (self));
1852
1853 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1854
1855 if (!priv->pile_settings)
1856 return;
1857
1858 if (priv->dest_added_sig) {
1859 g_signal_handler_disconnect (priv->settings->burner,
1860 priv->dest_added_sig);
1861 priv->dest_added_sig = 0;
1862 }
1863
1864 if (priv->dest_removed_sig) {
1865 g_signal_handler_disconnect (priv->settings->burner,
1866 priv->dest_removed_sig);
1867 priv->dest_removed_sig = 0;
1868 }
1869
1870 former = brasero_drive_get_medium (priv->settings->burner);
1871 if (former)
1872 former = g_object_ref (former);
1873
1874 brasero_session_settings_clean (priv->settings);
1875
1876 settings = priv->pile_settings->data;
1877 priv->pile_settings = g_slist_remove (priv->pile_settings, settings);
1878 brasero_session_settings_copy (priv->settings, settings);
1879
1880 brasero_session_settings_free (settings);
1881 if (priv->settings->burner) {
1882 priv->dest_added_sig = g_signal_connect (priv->settings->burner,
1883 "medium-added",
1884 G_CALLBACK (brasero_burn_session_dest_media_added),
1885 self);
1886 priv->dest_removed_sig = g_signal_connect (priv->settings->burner,
1887 "medium-removed",
1888 G_CALLBACK (brasero_burn_session_dest_media_removed),
1889 self);
1890 }
1891
1892 g_signal_emit (self,
1893 brasero_burn_session_signals [OUTPUT_CHANGED_SIGNAL],
1894 0,
1895 former);
1896
1897 if (former)
1898 g_object_unref (former);
1899 }
1900
1901 void
brasero_burn_session_push_tracks(BraseroBurnSession * self)1902 brasero_burn_session_push_tracks (BraseroBurnSession *self)
1903 {
1904 BraseroBurnSessionPrivate *priv;
1905 GSList *iter;
1906
1907 g_return_if_fail (BRASERO_IS_BURN_SESSION (self));
1908
1909 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1910
1911 brasero_burn_session_stop_tracks_monitoring (self);
1912
1913 priv->pile_tracks = g_slist_prepend (priv->pile_tracks, priv->tracks);
1914 iter = priv->tracks;
1915 priv->tracks = NULL;
1916
1917 for (; iter; iter = iter->next) {
1918 BraseroTrack *track;
1919
1920 track = iter->data;
1921 g_signal_emit (self,
1922 brasero_burn_session_signals [TRACK_REMOVED_SIGNAL],
1923 0,
1924 track,
1925 0);
1926 }
1927 }
1928
1929 BraseroBurnResult
brasero_burn_session_pop_tracks(BraseroBurnSession * self)1930 brasero_burn_session_pop_tracks (BraseroBurnSession *self)
1931 {
1932 GSList *sources;
1933 BraseroBurnSessionPrivate *priv;
1934
1935 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), FALSE);
1936
1937 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1938
1939 /* Don't go further if there is no list of tracks on the pile */
1940 if (!priv->pile_tracks)
1941 return BRASERO_BURN_OK;
1942
1943 if (priv->tracks)
1944 brasero_burn_session_free_tracks (self);
1945
1946 sources = priv->pile_tracks->data;
1947 priv->pile_tracks = g_slist_remove (priv->pile_tracks, sources);
1948 priv->tracks = sources;
1949
1950 for (; sources; sources = sources->next) {
1951 BraseroTrack *track;
1952
1953 track = sources->data;
1954 brasero_burn_session_start_track_monitoring (self, track);
1955 g_signal_emit (self,
1956 brasero_burn_session_signals [TRACK_ADDED_SIGNAL],
1957 0,
1958 track);
1959 }
1960
1961 return BRASERO_BURN_RETRY;
1962 }
1963
1964 gboolean
brasero_burn_session_is_dest_file(BraseroBurnSession * self)1965 brasero_burn_session_is_dest_file (BraseroBurnSession *self)
1966 {
1967 BraseroBurnSessionPrivate *priv;
1968
1969 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), FALSE);
1970
1971 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1972 return BRASERO_BURN_SESSION_WRITE_TO_FILE (priv);
1973 }
1974
1975 BraseroMedia
brasero_burn_session_get_dest_media(BraseroBurnSession * self)1976 brasero_burn_session_get_dest_media (BraseroBurnSession *self)
1977 {
1978 BraseroBurnSessionPrivate *priv;
1979 BraseroMedium *medium;
1980
1981 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), BRASERO_MEDIUM_NONE);
1982
1983 priv = BRASERO_BURN_SESSION_PRIVATE (self);
1984
1985 if (BRASERO_BURN_SESSION_WRITE_TO_FILE (priv))
1986 return BRASERO_MEDIUM_FILE;
1987
1988 medium = brasero_drive_get_medium (priv->settings->burner);
1989
1990 return brasero_medium_get_status (medium);
1991 }
1992
1993 /**
1994 * brasero_burn_session_get_available_medium_space:
1995 * @session: a #BraseroBurnSession
1996 *
1997 * Returns the maximum space available for the
1998 * medium currently inserted in the #BraseroDrive
1999 * set as burner with brasero_burn_session_set_burner ().
2000 * This takes into account flags.
2001 *
2002 * Return value: a #goffset.
2003 **/
2004
2005 goffset
brasero_burn_session_get_available_medium_space(BraseroBurnSession * session)2006 brasero_burn_session_get_available_medium_space (BraseroBurnSession *session)
2007 {
2008 BraseroDrive *burner;
2009 BraseroBurnFlag flags;
2010 BraseroMedium *medium;
2011 goffset available_blocks = 0;
2012
2013 /* Retrieve the size available for burning */
2014 burner = brasero_burn_session_get_burner (session);
2015 if (!burner)
2016 return 0;
2017
2018 medium = brasero_drive_get_medium (burner);
2019 if (!medium)
2020 return 0;
2021
2022 flags = brasero_burn_session_get_flags (session);
2023 if (flags & (BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_APPEND))
2024 brasero_medium_get_free_space (medium, NULL, &available_blocks);
2025 else if (brasero_burn_session_can_blank (session) == BRASERO_BURN_OK)
2026 brasero_medium_get_capacity (medium, NULL, &available_blocks);
2027 else
2028 brasero_medium_get_free_space (medium, NULL, &available_blocks);
2029
2030 BRASERO_BURN_LOG ("Available space on medium %" G_GINT64_FORMAT, available_blocks);
2031 return available_blocks;
2032 }
2033
2034 BraseroMedium *
brasero_burn_session_get_src_medium(BraseroBurnSession * self)2035 brasero_burn_session_get_src_medium (BraseroBurnSession *self)
2036 {
2037 BraseroTrack *track;
2038 BraseroDrive *drive;
2039 BraseroBurnSessionPrivate *priv;
2040
2041 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), NULL);
2042
2043 priv = BRASERO_BURN_SESSION_PRIVATE (self);
2044
2045 /* to be able to burn to a DVD we must:
2046 * - have only one track
2047 * - not have any audio track */
2048
2049 if (!priv->tracks)
2050 return NULL;
2051
2052 if (g_slist_length (priv->tracks) != 1)
2053 return NULL;
2054
2055 track = priv->tracks->data;
2056 if (!BRASERO_IS_TRACK_DISC (track))
2057 return NULL;
2058
2059 drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
2060 return brasero_drive_get_medium (drive);
2061 }
2062
2063 BraseroDrive *
brasero_burn_session_get_src_drive(BraseroBurnSession * self)2064 brasero_burn_session_get_src_drive (BraseroBurnSession *self)
2065 {
2066 BraseroTrack *track;
2067 BraseroBurnSessionPrivate *priv;
2068
2069 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), NULL);
2070
2071 priv = BRASERO_BURN_SESSION_PRIVATE (self);
2072
2073 /* to be able to burn to a DVD we must:
2074 * - have only one track
2075 * - not have any audio track */
2076
2077 if (!priv->tracks)
2078 return NULL;
2079
2080 if (g_slist_length (priv->tracks) != 1)
2081 return NULL;
2082
2083 track = priv->tracks->data;
2084 if (!BRASERO_IS_TRACK_DISC (track))
2085 return NULL;
2086
2087 return brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
2088 }
2089
2090 gboolean
brasero_burn_session_same_src_dest_drive(BraseroBurnSession * self)2091 brasero_burn_session_same_src_dest_drive (BraseroBurnSession *self)
2092 {
2093 BraseroTrack *track;
2094 BraseroDrive *drive;
2095 BraseroBurnSessionPrivate *priv;
2096
2097 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), FALSE);
2098
2099 priv = BRASERO_BURN_SESSION_PRIVATE (self);
2100
2101 /* to be able to burn to a DVD we must:
2102 * - have only one track
2103 * - not have any audio track
2104 */
2105
2106 if (!priv->tracks)
2107 return FALSE;
2108
2109 if (g_slist_length (priv->tracks) > 1)
2110 return FALSE;
2111
2112 track = priv->tracks->data;
2113 if (!BRASERO_IS_TRACK_DISC (track))
2114 return FALSE;
2115
2116 drive = brasero_track_disc_get_drive (BRASERO_TRACK_DISC (track));
2117 if (!drive)
2118 return FALSE;
2119
2120 return (priv->settings->burner == drive);
2121 }
2122
2123
2124 /****************************** this part is for log ***************************/
2125 void
brasero_burn_session_logv(BraseroBurnSession * self,const gchar * format,va_list arg_list)2126 brasero_burn_session_logv (BraseroBurnSession *self,
2127 const gchar *format,
2128 va_list arg_list)
2129 {
2130 int len;
2131 int wlen;
2132 gchar *message;
2133 gchar *offending;
2134 BraseroBurnSessionPrivate *priv;
2135
2136 g_return_if_fail (BRASERO_IS_BURN_SESSION (self));
2137
2138 priv = BRASERO_BURN_SESSION_PRIVATE (self);
2139
2140 if (!format)
2141 return;
2142
2143 if (!priv->session)
2144 return;
2145
2146 message = g_strdup_vprintf (format, arg_list);
2147
2148 /* we also need to validate the messages to be in UTF-8 */
2149 if (!g_utf8_validate (message, -1, (const gchar**) &offending))
2150 *offending = '\0';
2151
2152 len = strlen (message);
2153 wlen = write (priv->session, message, len);
2154 if (wlen != len) {
2155 int errnum = errno;
2156
2157 g_warning ("Some log data couldn't be written: %s (%i out of %i) (%s)\n",
2158 message, wlen, len,
2159 strerror (errnum));
2160 }
2161
2162 g_free (message);
2163
2164 if (write (priv->session, "\n", 1) != 1)
2165 g_warning ("Some log data could not be written");
2166 }
2167
2168 void
brasero_burn_session_log(BraseroBurnSession * self,const gchar * format,...)2169 brasero_burn_session_log (BraseroBurnSession *self,
2170 const gchar *format,
2171 ...)
2172 {
2173 va_list args;
2174
2175 g_return_if_fail (BRASERO_IS_BURN_SESSION (self));
2176
2177 va_start (args, format);
2178 brasero_burn_session_logv (self, format, args);
2179 va_end (args);
2180 }
2181
2182 const gchar *
brasero_burn_session_get_log_path(BraseroBurnSession * self)2183 brasero_burn_session_get_log_path (BraseroBurnSession *self)
2184 {
2185 BraseroBurnSessionPrivate *priv;
2186
2187 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), NULL);
2188
2189 priv = BRASERO_BURN_SESSION_PRIVATE (self);
2190 return priv->session_path;
2191 }
2192
2193 gboolean
brasero_burn_session_start(BraseroBurnSession * self)2194 brasero_burn_session_start (BraseroBurnSession *self)
2195 {
2196 BraseroTrackType *type = NULL;
2197 BraseroBurnSessionPrivate *priv;
2198
2199 g_return_val_if_fail (BRASERO_IS_BURN_SESSION (self), FALSE);
2200
2201 priv = BRASERO_BURN_SESSION_PRIVATE (self);
2202
2203 /* This must obey the path of the temporary directory if possible */
2204 priv->session_path = g_build_path (G_DIR_SEPARATOR_S,
2205 priv->tmpdir,
2206 BRASERO_BURN_TMP_FILE_NAME,
2207 NULL);
2208 priv->session = g_mkstemp_full (priv->session_path,
2209 O_CREAT|O_WRONLY,
2210 S_IRWXU);
2211
2212 if (priv->session < 0) {
2213 g_free (priv->session_path);
2214
2215 priv->session_path = g_build_path (G_DIR_SEPARATOR_S,
2216 g_get_tmp_dir (),
2217 BRASERO_BURN_TMP_FILE_NAME,
2218 NULL);
2219 priv->session = g_mkstemp_full (priv->session_path,
2220 O_CREAT|O_WRONLY,
2221 S_IRWXU);
2222 }
2223
2224 if (priv->session < 0) {
2225 g_free (priv->session_path);
2226 priv->session_path = NULL;
2227
2228 g_warning ("Impossible to open a session file\n");
2229 return FALSE;
2230 }
2231
2232 BRASERO_BURN_LOG ("Session starting:");
2233
2234 type = brasero_track_type_new ();
2235 brasero_burn_session_get_input_type (self, type);
2236
2237 BRASERO_BURN_LOG_TYPE (type, "Input\t=");
2238 BRASERO_BURN_LOG_FLAGS (priv->settings->flags, "flags\t=");
2239
2240 /* also try all known tags */
2241 if (brasero_track_type_get_has_stream (type)
2242 && BRASERO_STREAM_FORMAT_HAS_VIDEO (brasero_track_type_get_stream_format (type))) {
2243 GValue *value;
2244
2245 BRASERO_BURN_LOG ("Tags set:");
2246
2247 value = NULL;
2248 brasero_burn_session_tag_lookup (self,
2249 BRASERO_DVD_STREAM_FORMAT,
2250 &value);
2251 if (value)
2252 BRASERO_BURN_LOG ("Stream format %i", g_value_get_int (value));
2253
2254 value = NULL;
2255 brasero_burn_session_tag_lookup (self,
2256 BRASERO_VCD_TYPE,
2257 &value);
2258 if (value)
2259 BRASERO_BURN_LOG ("(S)VCD type %i", g_value_get_int (value));
2260
2261 value = NULL;
2262 brasero_burn_session_tag_lookup (self,
2263 BRASERO_VIDEO_OUTPUT_FRAMERATE,
2264 &value);
2265 if (value)
2266 BRASERO_BURN_LOG ("Framerate %i", g_value_get_int (value));
2267
2268 value = NULL;
2269 brasero_burn_session_tag_lookup (self,
2270 BRASERO_VIDEO_OUTPUT_ASPECT,
2271 &value);
2272 if (value)
2273 BRASERO_BURN_LOG ("Aspect %i", g_value_get_int (value));
2274 }
2275
2276 if (!brasero_burn_session_is_dest_file (self)) {
2277 BraseroMedium *medium;
2278
2279 medium = brasero_drive_get_medium (priv->settings->burner);
2280 BRASERO_BURN_LOG_DISC_TYPE (brasero_medium_get_status (medium), "media type\t=");
2281 BRASERO_BURN_LOG ("speed\t= %i", priv->settings->rate);
2282 }
2283 else {
2284 brasero_track_type_set_has_image (type);
2285 brasero_track_type_set_image_format (type, brasero_burn_session_get_output_format (self));
2286 BRASERO_BURN_LOG_TYPE (type, "output format\t=");
2287 }
2288
2289 brasero_track_type_free (type);
2290
2291 return TRUE;
2292 }
2293
2294 void
brasero_burn_session_stop(BraseroBurnSession * self)2295 brasero_burn_session_stop (BraseroBurnSession *self)
2296 {
2297 BraseroBurnSessionPrivate *priv;
2298
2299 g_return_if_fail (BRASERO_IS_BURN_SESSION (self));
2300
2301 priv = BRASERO_BURN_SESSION_PRIVATE (self);
2302 if (priv->session > 0) {
2303 close (priv->session);
2304 priv->session = -1;
2305 }
2306
2307 if (priv->session_path) {
2308 g_free (priv->session_path);
2309 priv->session_path = NULL;
2310 }
2311 }
2312
2313 static void
brasero_burn_session_track_list_free(GSList * list)2314 brasero_burn_session_track_list_free (GSList *list)
2315 {
2316 g_slist_foreach (list, (GFunc) g_object_unref, NULL);
2317 g_slist_free (list);
2318 }
2319
2320 /**
2321 * Utility to clean tmp files
2322 */
2323
2324 static gboolean
2325 brasero_burn_session_clean (const gchar *path);
2326
2327 static gboolean
brasero_burn_session_clean_directory(const gchar * path)2328 brasero_burn_session_clean_directory (const gchar *path)
2329 {
2330 GDir *dir;
2331 const gchar *name;
2332
2333 dir = g_dir_open (path, 0, NULL);
2334 if (!dir)
2335 return FALSE;
2336
2337 while ((name = g_dir_read_name (dir))) {
2338 gchar *tmp;
2339
2340 tmp = g_build_filename (G_DIR_SEPARATOR_S,
2341 path,
2342 name,
2343 NULL);
2344
2345 if (!brasero_burn_session_clean (tmp)) {
2346 g_dir_close (dir);
2347 g_free (tmp);
2348 return FALSE;
2349 }
2350
2351 g_free (tmp);
2352 }
2353
2354 g_dir_close (dir);
2355 return TRUE;
2356 }
2357
2358 static gboolean
brasero_burn_session_clean(const gchar * path)2359 brasero_burn_session_clean (const gchar *path)
2360 {
2361 gboolean result = TRUE;
2362
2363 if (!path)
2364 return TRUE;
2365
2366 BRASERO_BURN_LOG ("Cleaning %s", path);
2367
2368 /* NOTE: g_file_test follows symbolic links */
2369 if (g_file_test (path, G_FILE_TEST_IS_DIR)
2370 && !g_file_test (path, G_FILE_TEST_IS_SYMLINK))
2371 brasero_burn_session_clean_directory (path);
2372
2373 /* NOTE : we don't follow paths as certain files are simply linked */
2374 if (g_remove (path)) {
2375 BRASERO_BURN_LOG ("Cannot remove file %s (%s)", path, g_strerror (errno));
2376 result = FALSE;
2377 }
2378
2379 return result;
2380 }
2381
2382 static void
brasero_burn_session_finalize(GObject * object)2383 brasero_burn_session_finalize (GObject *object)
2384 {
2385 BraseroBurnSessionPrivate *priv;
2386 GSList *iter;
2387
2388 BRASERO_BURN_LOG ("Cleaning session");
2389
2390 priv = BRASERO_BURN_SESSION_PRIVATE (object);
2391
2392 if (priv->tags) {
2393 g_hash_table_destroy (priv->tags);
2394 priv->tags = NULL;
2395 }
2396
2397 if (priv->dest_added_sig) {
2398 g_signal_handler_disconnect (priv->settings->burner,
2399 priv->dest_added_sig);
2400 priv->dest_added_sig = 0;
2401 }
2402
2403 if (priv->dest_removed_sig) {
2404 g_signal_handler_disconnect (priv->settings->burner,
2405 priv->dest_removed_sig);
2406 priv->dest_removed_sig = 0;
2407 }
2408
2409 brasero_burn_session_stop_tracks_monitoring (BRASERO_BURN_SESSION (object));
2410
2411 if (priv->pile_tracks) {
2412 g_slist_foreach (priv->pile_tracks,
2413 (GFunc) brasero_burn_session_track_list_free,
2414 NULL);
2415
2416 g_slist_free (priv->pile_tracks);
2417 priv->pile_tracks = NULL;
2418 }
2419
2420 if (priv->tracks) {
2421 g_slist_foreach (priv->tracks,
2422 (GFunc) g_object_unref,
2423 NULL);
2424 g_slist_free (priv->tracks);
2425 priv->tracks = NULL;
2426 }
2427
2428 if (priv->pile_settings) {
2429 g_slist_foreach (priv->pile_settings,
2430 (GFunc) brasero_session_settings_free,
2431 NULL);
2432 g_slist_free (priv->pile_settings);
2433 priv->pile_settings = NULL;
2434 }
2435
2436 if (priv->tmpdir) {
2437 g_free (priv->tmpdir);
2438 priv->tmpdir = NULL;
2439 }
2440
2441 /* clean tmpfiles */
2442 for (iter = priv->tmpfiles; iter; iter = iter->next) {
2443 gchar *tmpfile;
2444
2445 tmpfile = iter->data;
2446
2447 brasero_burn_session_clean (tmpfile);
2448 g_free (tmpfile);
2449 }
2450 g_slist_free (priv->tmpfiles);
2451
2452 if (priv->session > 0) {
2453 close (priv->session);
2454 priv->session = -1;
2455 }
2456
2457 if (priv->session_path) {
2458 g_remove (priv->session_path);
2459 g_free (priv->session_path);
2460 priv->session_path = NULL;
2461 }
2462
2463 brasero_session_settings_clean (priv->settings);
2464
2465 G_OBJECT_CLASS (parent_class)->finalize (object);
2466 }
2467
2468 static void
brasero_burn_session_init(BraseroBurnSession * obj)2469 brasero_burn_session_init (BraseroBurnSession *obj)
2470 {
2471 BraseroBurnSessionPrivate *priv;
2472
2473 priv = BRASERO_BURN_SESSION_PRIVATE (obj);
2474 priv->session = -1;
2475 }
2476
2477 static void
brasero_burn_session_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)2478 brasero_burn_session_set_property (GObject *object,
2479 guint prop_id,
2480 const GValue *value,
2481 GParamSpec *pspec)
2482 {
2483 g_return_if_fail (BRASERO_IS_BURN_SESSION (object));
2484
2485 switch (prop_id)
2486 {
2487 case PROP_TMPDIR:
2488 brasero_burn_session_set_tmpdir (BRASERO_BURN_SESSION (object),
2489 g_value_get_string (value));
2490 break;
2491 case PROP_RATE:
2492 brasero_burn_session_set_rate (BRASERO_BURN_SESSION (object),
2493 g_value_get_int64 (value));
2494 break;
2495 case PROP_FLAGS:
2496 brasero_burn_session_set_flags (BRASERO_BURN_SESSION (object),
2497 g_value_get_int (value));
2498 break;
2499 default:
2500 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2501 break;
2502 }
2503 }
2504
2505 static void
brasero_burn_session_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)2506 brasero_burn_session_get_property (GObject *object,
2507 guint prop_id,
2508 GValue *value,
2509 GParamSpec *pspec)
2510 {
2511 BraseroBurnSessionPrivate *priv;
2512
2513 g_return_if_fail (BRASERO_IS_BURN_SESSION (object));
2514
2515 priv = BRASERO_BURN_SESSION_PRIVATE (object);
2516
2517 /* Here we do not call the accessors functions to honour the 0/NULL value
2518 * which means use system default. */
2519 switch (prop_id)
2520 {
2521 case PROP_TMPDIR:
2522 g_value_set_string (value, priv->tmpdir);
2523 break;
2524 case PROP_RATE:
2525 g_value_set_int64 (value, priv->settings->rate);
2526 break;
2527 case PROP_FLAGS:
2528 g_value_set_int (value, priv->settings->flags);
2529 break;
2530 default:
2531 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2532 break;
2533 }
2534 }
2535
2536 static void
brasero_burn_session_class_init(BraseroBurnSessionClass * klass)2537 brasero_burn_session_class_init (BraseroBurnSessionClass *klass)
2538 {
2539 GObjectClass *object_class = G_OBJECT_CLASS (klass);
2540
2541 g_type_class_add_private (klass, sizeof (BraseroBurnSessionPrivate));
2542
2543 parent_class = g_type_class_peek_parent(klass);
2544
2545 object_class->finalize = brasero_burn_session_finalize;
2546 object_class->set_property = brasero_burn_session_set_property;
2547 object_class->get_property = brasero_burn_session_get_property;
2548
2549 klass->get_output_path = brasero_burn_session_get_output_path_real;
2550 klass->get_output_format = brasero_burn_session_get_output_format_real;
2551 klass->set_output_image = brasero_burn_session_set_output_image_real;
2552
2553 /**
2554 * BraseroBurnSession::output-changed:
2555 * @session: the object which received the signal
2556 * @former_medium: the medium which was previously set
2557 *
2558 * This signal gets emitted when the medium to burn to changed.
2559 *
2560 */
2561 brasero_burn_session_signals [OUTPUT_CHANGED_SIGNAL] =
2562 g_signal_new ("output_changed",
2563 BRASERO_TYPE_BURN_SESSION,
2564 G_SIGNAL_RUN_LAST,
2565 G_STRUCT_OFFSET (BraseroBurnSessionClass, output_changed),
2566 NULL,
2567 NULL,
2568 g_cclosure_marshal_VOID__OBJECT,
2569 G_TYPE_NONE,
2570 1,
2571 BRASERO_TYPE_MEDIUM);
2572
2573 /**
2574 * BraseroBurnSession::track-added:
2575 * @session: the object which received the signal
2576 * @track: the track that was added
2577 *
2578 * This signal gets emitted when a track is added to @session.
2579 *
2580 */
2581 brasero_burn_session_signals [TRACK_ADDED_SIGNAL] =
2582 g_signal_new ("track_added",
2583 BRASERO_TYPE_BURN_SESSION,
2584 G_SIGNAL_RUN_LAST,
2585 G_STRUCT_OFFSET (BraseroBurnSessionClass, track_added),
2586 NULL,
2587 NULL,
2588 g_cclosure_marshal_VOID__OBJECT,
2589 G_TYPE_NONE,
2590 1,
2591 BRASERO_TYPE_TRACK);
2592
2593 /**
2594 * BraseroBurnSession::track-removed:
2595 * @session: the object which received the signal
2596 * @track: the track that was removed
2597 * @former_position: the former position of @track
2598 *
2599 * This signal gets emitted when a track is removed from @session.
2600 *
2601 */
2602 brasero_burn_session_signals [TRACK_REMOVED_SIGNAL] =
2603 g_signal_new ("track_removed",
2604 BRASERO_TYPE_BURN_SESSION,
2605 G_SIGNAL_RUN_LAST,
2606 G_STRUCT_OFFSET (BraseroBurnSessionClass, track_removed),
2607 NULL,
2608 NULL,
2609 brasero_marshal_VOID__OBJECT_UINT,
2610 G_TYPE_NONE,
2611 2,
2612 BRASERO_TYPE_TRACK,
2613 G_TYPE_UINT);
2614
2615 /**
2616 * BraseroBurnSession::track-changed:
2617 * @session: the object which received the signal
2618 * @track: the track that changed
2619 *
2620 * This signal gets emitted when the contents of a track changed.
2621 *
2622 */
2623 brasero_burn_session_signals [TRACK_CHANGED_SIGNAL] =
2624 g_signal_new ("track_changed",
2625 BRASERO_TYPE_BURN_SESSION,
2626 G_SIGNAL_RUN_LAST,
2627 G_STRUCT_OFFSET (BraseroBurnSessionClass, track_changed),
2628 NULL,
2629 NULL,
2630 g_cclosure_marshal_VOID__OBJECT,
2631 G_TYPE_NONE,
2632 1,
2633 BRASERO_TYPE_TRACK);
2634
2635 /**
2636 * BraseroBurnSession::tag-changed:
2637 * @session: the object which received the signal
2638 *
2639 * This signal gets emitted when a tag changed for @session (whether it
2640 * was removed, added, or it changed).
2641 *
2642 */
2643 brasero_burn_session_signals [TAG_CHANGED_SIGNAL] =
2644 g_signal_new ("tag_changed",
2645 BRASERO_TYPE_BURN_SESSION,
2646 G_SIGNAL_RUN_FIRST,
2647 0,
2648 NULL,
2649 NULL,
2650 g_cclosure_marshal_VOID__STRING,
2651 G_TYPE_NONE,
2652 1,
2653 G_TYPE_STRING);
2654
2655 g_object_class_install_property (object_class,
2656 PROP_TMPDIR,
2657 g_param_spec_string ("tmpdir",
2658 "Temporary directory",
2659 "The path to the temporary directory",
2660 NULL,
2661 G_PARAM_READABLE|G_PARAM_WRITABLE));
2662 g_object_class_install_property (object_class,
2663 PROP_RATE,
2664 g_param_spec_int64 ("speed",
2665 "Burning speed",
2666 "The speed at which a disc should be burned",
2667 0,
2668 G_MAXINT64,
2669 0,
2670 G_PARAM_READABLE|G_PARAM_WRITABLE));
2671 g_object_class_install_property (object_class,
2672 PROP_FLAGS,
2673 g_param_spec_int ("flags",
2674 "Burning flags",
2675 "The flags that will be used to burn",
2676 0,
2677 G_MAXINT,
2678 0,
2679 G_PARAM_READABLE|G_PARAM_WRITABLE));
2680 }
2681
2682 /**
2683 * brasero_burn_session_new:
2684 *
2685 * Returns a new #BraseroBurnSession object.
2686 *
2687 * Return value: a #BraseroBurnSession.
2688 **/
2689
2690 BraseroBurnSession *
brasero_burn_session_new()2691 brasero_burn_session_new ()
2692 {
2693 BraseroBurnSession *obj;
2694
2695 obj = BRASERO_BURN_SESSION (g_object_new (BRASERO_TYPE_BURN_SESSION, NULL));
2696
2697 return obj;
2698 }
2699
2700