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 <string.h>
36 #include <sys/resource.h>
37
38 #include <glib.h>
39 #include <glib-object.h>
40 #include <glib/gi18n-lib.h>
41
42 #include "brasero-volume.h"
43
44 #include "burn-basics.h"
45 #include "burn-debug.h"
46 #include "burn-plugin-manager.h"
47 #include "brasero-session.h"
48 #include "burn-plugin-manager.h"
49 #include "burn-image-format.h"
50 #include "libbrasero-marshal.h"
51
52 #include "brasero-tags.h"
53 #include "brasero-track-image.h"
54 #include "brasero-track-data-cfg.h"
55 #include "brasero-session-cfg.h"
56 #include "brasero-burn-lib.h"
57 #include "brasero-session-helper.h"
58
59
60 /**
61 * SECTION:brasero-session-cfg
62 * @short_description: Configure automatically a #BraseroBurnSession object
63 * @see_also: #BraseroBurn, #BraseroBurnSession
64 * @include: brasero-session-cfg.h
65 *
66 * This object configures automatically a session reacting to any change
67 * made to the various parameters.
68 **/
69
70 typedef struct _BraseroSessionCfgPrivate BraseroSessionCfgPrivate;
71 struct _BraseroSessionCfgPrivate
72 {
73 BraseroBurnFlag supported;
74 BraseroBurnFlag compulsory;
75
76 /* Do some caching to improve performances */
77 BraseroImageFormat output_format;
78 gchar *output;
79
80 BraseroTrackType *source;
81 goffset disc_size;
82 goffset session_blocks;
83 goffset session_size;
84
85 BraseroSessionError is_valid;
86
87 guint CD_TEXT_modified:1;
88 guint configuring:1;
89 guint disabled:1;
90
91 guint output_msdos:1;
92 };
93
94 #define BRASERO_SESSION_CFG_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_SESSION_CFG, BraseroSessionCfgPrivate))
95
96 enum
97 {
98 IS_VALID_SIGNAL,
99 WRONG_EXTENSION_SIGNAL,
100 LAST_SIGNAL
101 };
102
103
104 static guint session_cfg_signals [LAST_SIGNAL] = { 0 };
105
106 G_DEFINE_TYPE (BraseroSessionCfg, brasero_session_cfg, BRASERO_TYPE_SESSION_SPAN);
107
108 /**
109 * This is to handle tags (and more particularly video ones)
110 */
111
112 static void
brasero_session_cfg_tag_changed(BraseroBurnSession * session,const gchar * tag)113 brasero_session_cfg_tag_changed (BraseroBurnSession *session,
114 const gchar *tag)
115 {
116 if (!strcmp (tag, BRASERO_VCD_TYPE)) {
117 int svcd_type;
118
119 svcd_type = brasero_burn_session_tag_lookup_int (session, BRASERO_VCD_TYPE);
120 if (svcd_type != BRASERO_SVCD)
121 brasero_burn_session_tag_add_int (session,
122 BRASERO_VIDEO_OUTPUT_ASPECT,
123 BRASERO_VIDEO_ASPECT_4_3);
124 }
125 }
126
127 /**
128 * brasero_session_cfg_has_default_output_path:
129 * @session: a #BraseroSessionCfg
130 *
131 * This function returns whether the path returned
132 * by brasero_burn_session_get_output () is an
133 * automatically created one.
134 *
135 * Return value: a #gboolean. TRUE if the path(s)
136 * creation is handled by @session, FALSE if it was
137 * set.
138 **/
139
140 gboolean
brasero_session_cfg_has_default_output_path(BraseroSessionCfg * session)141 brasero_session_cfg_has_default_output_path (BraseroSessionCfg *session)
142 {
143 BraseroBurnSessionClass *klass;
144 BraseroBurnResult result;
145
146 klass = BRASERO_BURN_SESSION_CLASS (brasero_session_cfg_parent_class);
147 result = klass->get_output_path (BRASERO_BURN_SESSION (session), NULL, NULL);
148 return (result == BRASERO_BURN_OK);
149 }
150
151 static gboolean
brasero_session_cfg_wrong_extension_signal(BraseroSessionCfg * session)152 brasero_session_cfg_wrong_extension_signal (BraseroSessionCfg *session)
153 {
154 GValue instance_and_params [1];
155 GValue return_value;
156
157 instance_and_params [0].g_type = 0;
158 g_value_init (instance_and_params, G_TYPE_FROM_INSTANCE (session));
159 g_value_set_instance (instance_and_params, session);
160
161 return_value.g_type = 0;
162 g_value_init (&return_value, G_TYPE_BOOLEAN);
163 g_value_set_boolean (&return_value, FALSE);
164
165 g_signal_emitv (instance_and_params,
166 session_cfg_signals [WRONG_EXTENSION_SIGNAL],
167 0,
168 &return_value);
169
170 g_value_unset (instance_and_params);
171
172 return g_value_get_boolean (&return_value);
173 }
174
175 static BraseroBurnResult
brasero_session_cfg_set_output_image(BraseroBurnSession * session,BraseroImageFormat format,const gchar * image,const gchar * toc)176 brasero_session_cfg_set_output_image (BraseroBurnSession *session,
177 BraseroImageFormat format,
178 const gchar *image,
179 const gchar *toc)
180 {
181 gchar *dot;
182 gchar *set_toc = NULL;
183 gchar * set_image = NULL;
184 BraseroBurnResult result;
185 BraseroBurnSessionClass *klass;
186 const gchar *suffixes [] = {".iso",
187 ".toc",
188 ".cue",
189 ".toc",
190 NULL };
191
192 /* Make sure something actually changed */
193 klass = BRASERO_BURN_SESSION_CLASS (brasero_session_cfg_parent_class);
194 klass->get_output_path (BRASERO_BURN_SESSION (session),
195 &set_image,
196 &set_toc);
197
198 if (!set_image && !set_toc) {
199 /* see if image and toc set paths differ */
200 brasero_burn_session_get_output (BRASERO_BURN_SESSION (session),
201 &set_image,
202 &set_toc);
203 if (set_image && image && !strcmp (set_image, image)) {
204 /* It's the same default path so no
205 * need to carry on and actually set
206 * the path of image. */
207 image = NULL;
208 }
209
210 if (set_toc && toc && !strcmp (set_toc, toc)) {
211 /* It's the same default path so no
212 * need to carry on and actually set
213 * the path of image. */
214 toc = NULL;
215 }
216 }
217
218 if (set_image)
219 g_free (set_image);
220
221 if (set_toc)
222 g_free (set_toc);
223
224 /* First set all information */
225 result = klass->set_output_image (session,
226 format,
227 image,
228 toc);
229
230 if (!image && !toc)
231 return result;
232
233 if (format == BRASERO_IMAGE_FORMAT_NONE)
234 format = brasero_burn_session_get_output_format (session);
235
236 if (format == BRASERO_IMAGE_FORMAT_NONE)
237 return result;
238
239 if (format & BRASERO_IMAGE_FORMAT_BIN) {
240 dot = g_utf8_strrchr (image, -1, '.');
241 if (!dot || strcmp (suffixes [0], dot)) {
242 gboolean res;
243
244 res = brasero_session_cfg_wrong_extension_signal (BRASERO_SESSION_CFG (session));
245 if (res) {
246 gchar *fixed_path;
247
248 fixed_path = brasero_image_format_fix_path_extension (format, FALSE, image);
249 /* NOTE: call ourselves with the fixed path as this way,
250 * in case the path is the same as the default one after
251 * fixing the extension we'll keep on using default path */
252 result = brasero_burn_session_set_image_output_full (session,
253 format,
254 fixed_path,
255 toc);
256 g_free (fixed_path);
257 }
258 }
259 }
260 else {
261 dot = g_utf8_strrchr (toc, -1, '.');
262
263 if (format & BRASERO_IMAGE_FORMAT_CLONE
264 && (!dot || strcmp (suffixes [1], dot))) {
265 gboolean res;
266
267 res = brasero_session_cfg_wrong_extension_signal (BRASERO_SESSION_CFG (session));
268 if (res) {
269 gchar *fixed_path;
270
271 fixed_path = brasero_image_format_fix_path_extension (format, FALSE, toc);
272 result = brasero_burn_session_set_image_output_full (session,
273 format,
274 image,
275 fixed_path);
276 g_free (fixed_path);
277 }
278 }
279 else if (format & BRASERO_IMAGE_FORMAT_CUE
280 && (!dot || strcmp (suffixes [2], dot))) {
281 gboolean res;
282
283 res = brasero_session_cfg_wrong_extension_signal (BRASERO_SESSION_CFG (session));
284 if (res) {
285 gchar *fixed_path;
286
287 fixed_path = brasero_image_format_fix_path_extension (format, FALSE, toc);
288 result = brasero_burn_session_set_image_output_full (session,
289 format,
290 image,
291 fixed_path);
292 g_free (fixed_path);
293 }
294 }
295 else if (format & BRASERO_IMAGE_FORMAT_CDRDAO
296 && (!dot || strcmp (suffixes [3], dot))) {
297 gboolean res;
298
299 res = brasero_session_cfg_wrong_extension_signal (BRASERO_SESSION_CFG (session));
300 if (res) {
301 gchar *fixed_path;
302
303 fixed_path = brasero_image_format_fix_path_extension (format, FALSE, toc);
304 result = brasero_burn_session_set_image_output_full (session,
305 format,
306 image,
307 fixed_path);
308 g_free (fixed_path);
309 }
310 }
311 }
312
313 return result;
314 }
315
316 static BraseroBurnResult
brasero_session_cfg_get_output_path(BraseroBurnSession * session,gchar ** image,gchar ** toc)317 brasero_session_cfg_get_output_path (BraseroBurnSession *session,
318 gchar **image,
319 gchar **toc)
320 {
321 gchar *path = NULL;
322 BraseroBurnResult result;
323 BraseroImageFormat format;
324 BraseroBurnSessionClass *klass;
325 BraseroSessionCfgPrivate *priv;
326
327 klass = BRASERO_BURN_SESSION_CLASS (brasero_session_cfg_parent_class);
328 priv = BRASERO_SESSION_CFG_PRIVATE (session);
329
330 result = klass->get_output_path (session,
331 image,
332 toc);
333 if (result == BRASERO_BURN_OK)
334 return result;
335
336 if (priv->output_format == BRASERO_IMAGE_FORMAT_NONE)
337 return BRASERO_BURN_ERR;
338
339 /* Note: path and format are determined earlier in fact, in the function
340 * that check the free space on the hard drive. */
341 path = g_strdup (priv->output);
342 format = priv->output_format;
343
344 switch (format) {
345 case BRASERO_IMAGE_FORMAT_BIN:
346 if (image)
347 *image = path;
348 break;
349
350 case BRASERO_IMAGE_FORMAT_CDRDAO:
351 case BRASERO_IMAGE_FORMAT_CLONE:
352 case BRASERO_IMAGE_FORMAT_CUE:
353 if (toc)
354 *toc = path;
355
356 if (image)
357 *image = brasero_image_format_get_complement (format, path);
358 break;
359
360 default:
361 g_free (path);
362 g_free (priv->output);
363 priv->output = NULL;
364 return BRASERO_BURN_ERR;
365 }
366
367 return BRASERO_BURN_OK;
368 }
369
370 static BraseroImageFormat
brasero_session_cfg_get_output_format(BraseroBurnSession * session)371 brasero_session_cfg_get_output_format (BraseroBurnSession *session)
372 {
373 BraseroBurnSessionClass *klass;
374 BraseroSessionCfgPrivate *priv;
375 BraseroImageFormat format;
376
377 klass = BRASERO_BURN_SESSION_CLASS (brasero_session_cfg_parent_class);
378 format = klass->get_output_format (session);
379
380 if (format != BRASERO_IMAGE_FORMAT_NONE)
381 return format;
382
383 priv = BRASERO_SESSION_CFG_PRIVATE (session);
384
385 if (priv->output_format)
386 return priv->output_format;
387
388 /* Cache the path for later use */
389 priv->output_format = brasero_burn_session_get_default_output_format (session);
390 return priv->output_format;
391 }
392
393 /**
394 * brasero_session_cfg_get_error:
395 * @session: a #BraseroSessionCfg
396 *
397 * This function returns the current status and if
398 * autoconfiguration is/was successful.
399 *
400 * Return value: a #BraseroSessionError.
401 **/
402
403 BraseroSessionError
brasero_session_cfg_get_error(BraseroSessionCfg * session)404 brasero_session_cfg_get_error (BraseroSessionCfg *session)
405 {
406 BraseroSessionCfgPrivate *priv;
407
408 priv = BRASERO_SESSION_CFG_PRIVATE (session);
409
410 if (priv->is_valid == BRASERO_SESSION_VALID
411 && priv->CD_TEXT_modified)
412 return BRASERO_SESSION_NO_CD_TEXT;
413
414 return priv->is_valid;
415 }
416
417 /**
418 * brasero_session_cfg_disable:
419 * @session: a #BraseroSessionCfg
420 *
421 * This function disables autoconfiguration
422 *
423 **/
424
425 void
brasero_session_cfg_disable(BraseroSessionCfg * session)426 brasero_session_cfg_disable (BraseroSessionCfg *session)
427 {
428 BraseroSessionCfgPrivate *priv;
429
430 priv = BRASERO_SESSION_CFG_PRIVATE (session);
431 priv->disabled = TRUE;
432 }
433
434 /**
435 * brasero_session_cfg_enable:
436 * @session: a #BraseroSessionCfg
437 *
438 * This function (re)-enables autoconfiguration
439 *
440 **/
441
442 void
brasero_session_cfg_enable(BraseroSessionCfg * session)443 brasero_session_cfg_enable (BraseroSessionCfg *session)
444 {
445 BraseroSessionCfgPrivate *priv;
446
447 priv = BRASERO_SESSION_CFG_PRIVATE (session);
448 priv->disabled = FALSE;
449 }
450
451 static void
brasero_session_cfg_set_drive_properties_default_flags(BraseroSessionCfg * self)452 brasero_session_cfg_set_drive_properties_default_flags (BraseroSessionCfg *self)
453 {
454 BraseroMedia media;
455 BraseroSessionCfgPrivate *priv;
456
457 priv = BRASERO_SESSION_CFG_PRIVATE (self);
458
459 media = brasero_burn_session_get_dest_media (BRASERO_BURN_SESSION (self));
460
461 if (BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_PLUS)
462 || BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_RESTRICTED)
463 || BRASERO_MEDIUM_IS (media, BRASERO_MEDIUM_DVDRW_PLUS_DL)) {
464 /* This is a special case to favour libburn/growisofs
465 * wodim/cdrecord for these types of media. */
466 if (priv->supported & BRASERO_BURN_FLAG_MULTI) {
467 brasero_burn_session_add_flag (BRASERO_BURN_SESSION (self),
468 BRASERO_BURN_FLAG_MULTI);
469
470 priv->supported = BRASERO_BURN_FLAG_NONE;
471 priv->compulsory = BRASERO_BURN_FLAG_NONE;
472 brasero_burn_session_get_burn_flags (BRASERO_BURN_SESSION (self),
473 &priv->supported,
474 &priv->compulsory);
475 }
476 }
477
478 /* Always set this flag whenever possible */
479 if (priv->supported & BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE) {
480 brasero_burn_session_add_flag (BRASERO_BURN_SESSION (self),
481 BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE);
482
483 if (priv->supported & BRASERO_BURN_FLAG_FAST_BLANK
484 && (media & BRASERO_MEDIUM_UNFORMATTED) == 0)
485 brasero_burn_session_add_flag (BRASERO_BURN_SESSION (self),
486 BRASERO_BURN_FLAG_FAST_BLANK);
487
488 priv->supported = BRASERO_BURN_FLAG_NONE;
489 priv->compulsory = BRASERO_BURN_FLAG_NONE;
490 brasero_burn_session_get_burn_flags (BRASERO_BURN_SESSION (self),
491 &priv->supported,
492 &priv->compulsory);
493 }
494
495 #if 0
496
497 /* NOTE: Stop setting DAO here except if it
498 * is declared compulsory (but that's handled
499 * somewhere else) or if it was explicity set.
500 * If we set it just by default when it's
501 * supported but not compulsory, MULTI
502 * becomes not supported anymore.
503 * For data the only way it'd be really useful
504 * is if we wanted to fit a selection on the disc.
505 * The problem here is that we don't know
506 * what the size of the final image is going
507 * to be.
508 * For images there are cases when after
509 * writing an image the user may want to
510 * add some more data to it later. As in the
511 * case of data the only way this flag would
512 * be useful would be to help fit the image
513 * on the disc. But I doubt it would really
514 * help a lot.
515 * For audio we need it to write things like
516 * CD-TEXT but in this case the backend
517 * will return it as compulsory. */
518
519 /* Another case when this flag is needed is
520 * for DVD-RW quick blanked as they only
521 * support DAO. But there again this should
522 * be covered by the backend that should
523 * return DAO as compulsory. */
524
525 /* Leave the code as a reminder. */
526 /* When copying with same drive don't set write mode, it'll be set later */
527 if (!brasero_burn_session_same_src_dest_drive (BRASERO_BURN_SESSION (self))
528 && !(media & BRASERO_MEDIUM_DVD)) {
529 /* use DAO whenever it's possible except for DVDs otherwise
530 * wodime which claims to support it will be used by default
531 * instead of say growisofs. */
532 if (priv->supported & BRASERO_BURN_FLAG_DAO) {
533 brasero_burn_session_add_flag (BRASERO_BURN_SESSION (self), BRASERO_BURN_FLAG_DAO);
534
535 priv->supported = BRASERO_BURN_FLAG_NONE;
536 priv->compulsory = BRASERO_BURN_FLAG_NONE;
537 brasero_burn_session_get_burn_flags (BRASERO_BURN_SESSION (self),
538 &priv->supported,
539 &priv->compulsory);
540
541 /* NOTE: after setting DAO, some flags may become
542 * compulsory like MULTI. */
543 }
544 }
545 #endif
546 }
547
548 static void
brasero_session_cfg_set_drive_properties_flags(BraseroSessionCfg * self,BraseroBurnFlag flags)549 brasero_session_cfg_set_drive_properties_flags (BraseroSessionCfg *self,
550 BraseroBurnFlag flags)
551 {
552 BraseroDrive *drive;
553 BraseroBurnFlag flag;
554 BraseroMedium *medium;
555 BraseroBurnResult result;
556 BraseroBurnFlag original_flags;
557 BraseroSessionCfgPrivate *priv;
558
559 priv = BRASERO_SESSION_CFG_PRIVATE (self);
560
561 original_flags = brasero_burn_session_get_flags (BRASERO_BURN_SESSION (self));
562
563 /* If the session is invalid no need to check the flags: just add them.
564 * The correct flags will be re-computed anyway when the session becomes
565 * valid again. */
566 if (priv->is_valid != BRASERO_SESSION_VALID) {
567 BRASERO_BURN_LOG ("Session currently not ready for flag computation: adding flags (will update later)");
568 brasero_burn_session_set_flags (BRASERO_BURN_SESSION (self), flags);
569 return;
570 }
571
572 BRASERO_BURN_LOG ("Resetting all flags");
573 BRASERO_BURN_LOG_FLAGS (original_flags, "Current are");
574 BRASERO_BURN_LOG_FLAGS (flags, "New should be");
575
576 drive = brasero_burn_session_get_burner (BRASERO_BURN_SESSION (self));
577 if (!drive) {
578 BRASERO_BURN_LOG ("No drive");
579 return;
580 }
581
582 medium = brasero_drive_get_medium (drive);
583 if (!medium) {
584 BRASERO_BURN_LOG ("No medium");
585 return;
586 }
587
588 /* This prevents signals to be emitted while (re-) adding them one by one */
589 g_object_freeze_notify (G_OBJECT (self));
590
591 brasero_burn_session_set_flags (BRASERO_BURN_SESSION (self), BRASERO_BURN_FLAG_NONE);
592
593 priv->supported = BRASERO_BURN_FLAG_NONE;
594 priv->compulsory = BRASERO_BURN_FLAG_NONE;
595 result = brasero_burn_session_get_burn_flags (BRASERO_BURN_SESSION (self),
596 &priv->supported,
597 &priv->compulsory);
598
599 if (result != BRASERO_BURN_OK) {
600 brasero_burn_session_set_flags (BRASERO_BURN_SESSION (self), original_flags | flags);
601 g_object_thaw_notify (G_OBJECT (self));
602 return;
603 }
604
605 for (flag = BRASERO_BURN_FLAG_EJECT; flag < BRASERO_BURN_FLAG_LAST; flag <<= 1) {
606 /* see if this flag was originally set */
607 if ((flags & flag) == 0)
608 continue;
609
610 /* Don't set write modes now in this case */
611 if (brasero_burn_session_same_src_dest_drive (BRASERO_BURN_SESSION (self))
612 && (flag & (BRASERO_BURN_FLAG_DAO|BRASERO_BURN_FLAG_RAW)))
613 continue;
614
615 if (priv->compulsory
616 && (priv->compulsory & brasero_burn_session_get_flags (BRASERO_BURN_SESSION (self))) != priv->compulsory) {
617 brasero_burn_session_add_flag (BRASERO_BURN_SESSION (self), priv->compulsory);
618
619 priv->supported = BRASERO_BURN_FLAG_NONE;
620 priv->compulsory = BRASERO_BURN_FLAG_NONE;
621 brasero_burn_session_get_burn_flags (BRASERO_BURN_SESSION (self),
622 &priv->supported,
623 &priv->compulsory);
624 }
625
626 if (priv->supported & flag) {
627 brasero_burn_session_add_flag (BRASERO_BURN_SESSION (self), flag);
628
629 priv->supported = BRASERO_BURN_FLAG_NONE;
630 priv->compulsory = BRASERO_BURN_FLAG_NONE;
631 brasero_burn_session_get_burn_flags (BRASERO_BURN_SESSION (self),
632 &priv->supported,
633 &priv->compulsory);
634 }
635 }
636
637 if (original_flags & BRASERO_BURN_FLAG_DAO
638 && priv->supported & BRASERO_BURN_FLAG_DAO) {
639 /* Only set DAO if it was explicitely requested */
640 brasero_burn_session_add_flag (BRASERO_BURN_SESSION (self), BRASERO_BURN_FLAG_DAO);
641
642 priv->supported = BRASERO_BURN_FLAG_NONE;
643 priv->compulsory = BRASERO_BURN_FLAG_NONE;
644 brasero_burn_session_get_burn_flags (BRASERO_BURN_SESSION (self),
645 &priv->supported,
646 &priv->compulsory);
647
648 /* NOTE: after setting DAO, some flags may become
649 * compulsory like MULTI. */
650 }
651
652 brasero_session_cfg_set_drive_properties_default_flags (self);
653
654 /* These are always supported and better be set. */
655 brasero_burn_session_add_flag (BRASERO_BURN_SESSION (self),
656 BRASERO_BURN_FLAG_CHECK_SIZE|
657 BRASERO_BURN_FLAG_NOGRACE);
658
659 /* This one is only supported when we are
660 * burning to a disc or copying a disc but it
661 * would better be set. */
662 if (priv->supported & BRASERO_BURN_FLAG_EJECT)
663 brasero_burn_session_add_flag (BRASERO_BURN_SESSION (self),
664 BRASERO_BURN_FLAG_EJECT);
665
666 /* allow notify::flags signal again */
667 g_object_thaw_notify (G_OBJECT (self));
668 }
669
670 static void
brasero_session_cfg_add_drive_properties_flags(BraseroSessionCfg * self,BraseroBurnFlag flags)671 brasero_session_cfg_add_drive_properties_flags (BraseroSessionCfg *self,
672 BraseroBurnFlag flags)
673 {
674 /* add flags then wipe out flags from session to check them one by one */
675 flags |= brasero_burn_session_get_flags (BRASERO_BURN_SESSION (self));
676 brasero_session_cfg_set_drive_properties_flags (self, flags);
677 }
678
679 static void
brasero_session_cfg_rm_drive_properties_flags(BraseroSessionCfg * self,BraseroBurnFlag flags)680 brasero_session_cfg_rm_drive_properties_flags (BraseroSessionCfg *self,
681 BraseroBurnFlag flags)
682 {
683 /* add flags then wipe out flags from session to check them one by one */
684 flags = brasero_burn_session_get_flags (BRASERO_BURN_SESSION (self)) & (~flags);
685 brasero_session_cfg_set_drive_properties_flags (self, flags);
686 }
687
688 static void
brasero_session_cfg_check_drive_settings(BraseroSessionCfg * self)689 brasero_session_cfg_check_drive_settings (BraseroSessionCfg *self)
690 {
691 BraseroBurnFlag flags;
692
693 /* Try to properly update the flags for the current drive */
694 flags = brasero_burn_session_get_flags (BRASERO_BURN_SESSION (self));
695 if (brasero_burn_session_same_src_dest_drive (BRASERO_BURN_SESSION (self))) {
696 flags |= BRASERO_BURN_FLAG_BLANK_BEFORE_WRITE|
697 BRASERO_BURN_FLAG_FAST_BLANK;
698 }
699
700 /* check each flag before re-adding it */
701 brasero_session_cfg_add_drive_properties_flags (self, flags);
702 }
703
704 static BraseroSessionError
brasero_session_cfg_check_volume_size(BraseroSessionCfg * self)705 brasero_session_cfg_check_volume_size (BraseroSessionCfg *self)
706 {
707 struct rlimit limit;
708 BraseroSessionCfgPrivate *priv;
709
710 priv = BRASERO_SESSION_CFG_PRIVATE (self);
711 if (!priv->disc_size) {
712 GFileInfo *info;
713 gchar *directory;
714 GFile *file = NULL;
715 const gchar *filesystem;
716
717 /* Cache the path for later use */
718 if (priv->output_format == BRASERO_IMAGE_FORMAT_NONE)
719 priv->output_format = brasero_burn_session_get_output_format (BRASERO_BURN_SESSION (self));
720
721 if (!priv->output) {
722 gchar *name = NULL;
723
724 /* If we try to copy a volume get (and use) its name */
725 if (brasero_track_type_get_has_medium (priv->source)) {
726 BraseroMedium *medium;
727
728 medium = brasero_burn_session_get_src_medium (BRASERO_BURN_SESSION (self));
729 if (medium)
730 name = brasero_volume_get_name (BRASERO_VOLUME (medium));
731 }
732
733 priv->output = brasero_image_format_get_default_path (priv->output_format, name);
734 g_free (name);
735 }
736
737 directory = g_path_get_dirname (priv->output);
738 file = g_file_new_for_path (directory);
739 g_free (directory);
740
741 if (file == NULL)
742 goto error;
743
744 /* Check permissions first */
745 info = g_file_query_info (file,
746 G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
747 G_FILE_QUERY_INFO_NONE,
748 NULL,
749 NULL);
750 if (!info) {
751 g_object_unref (file);
752 goto error;
753 }
754
755 if (!g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE)) {
756 g_object_unref (info);
757 g_object_unref (file);
758 goto error;
759 }
760 g_object_unref (info);
761
762 /* Now size left */
763 info = g_file_query_filesystem_info (file,
764 G_FILE_ATTRIBUTE_FILESYSTEM_FREE ","
765 G_FILE_ATTRIBUTE_FILESYSTEM_TYPE,
766 NULL,
767 NULL);
768 g_object_unref (file);
769
770 if (!info)
771 goto error;
772
773 /* Now check the filesystem type: the problem here is that some
774 * filesystems have a maximum file size limit of 4 GiB and more than
775 * often we need a temporary file size of 4 GiB or more. */
776 filesystem = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE);
777 if (!g_strcmp0 (filesystem, "msdos"))
778 priv->output_msdos = TRUE;
779 else
780 priv->output_msdos = FALSE;
781
782 priv->disc_size = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
783 g_object_unref (info);
784 }
785
786 BRASERO_BURN_LOG ("Session size %lli/Hard drive size %lli",
787 priv->session_size,
788 priv->disc_size);
789
790 if (priv->output_msdos && priv->session_size >= 2147483648ULL)
791 goto error;
792
793 if (priv->session_size > priv->disc_size)
794 goto error;
795
796 /* Last but not least, use getrlimit () to check that we are allowed to
797 * write a file of such length and that quotas won't get in our way */
798 if (getrlimit (RLIMIT_FSIZE, &limit))
799 goto error;
800
801 if (limit.rlim_cur < priv->session_size)
802 goto error;
803
804 priv->is_valid = BRASERO_SESSION_VALID;
805 return BRASERO_SESSION_VALID;
806
807 error:
808
809 priv->is_valid = BRASERO_SESSION_INSUFFICIENT_SPACE;
810 return BRASERO_SESSION_INSUFFICIENT_SPACE;
811 }
812
813 static BraseroSessionError
brasero_session_cfg_check_size(BraseroSessionCfg * self)814 brasero_session_cfg_check_size (BraseroSessionCfg *self)
815 {
816 BraseroSessionCfgPrivate *priv;
817 BraseroBurnFlag flags;
818 BraseroMedium *medium;
819 BraseroDrive *burner;
820 GValue *value = NULL;
821 /* in sectors */
822 goffset max_sectors;
823
824 priv = BRASERO_SESSION_CFG_PRIVATE (self);
825
826 /* Get the session size if need be */
827 if (!priv->session_blocks) {
828 if (brasero_burn_session_tag_lookup (BRASERO_BURN_SESSION (self),
829 BRASERO_DATA_TRACK_SIZE_TAG,
830 &value) == BRASERO_BURN_OK) {
831 priv->session_blocks = g_value_get_int64 (value);
832 priv->session_size = priv->session_blocks * 2048;
833 }
834 else if (brasero_burn_session_tag_lookup (BRASERO_BURN_SESSION (self),
835 BRASERO_STREAM_TRACK_SIZE_TAG,
836 &value) == BRASERO_BURN_OK) {
837 priv->session_blocks = g_value_get_int64 (value);
838 priv->session_size = priv->session_blocks * 2352;
839 }
840 else
841 brasero_burn_session_get_size (BRASERO_BURN_SESSION (self),
842 &priv->session_blocks,
843 &priv->session_size);
844 }
845
846 /* Get the disc and its size if need be */
847 burner = brasero_burn_session_get_burner (BRASERO_BURN_SESSION (self));
848 if (!burner) {
849 priv->is_valid = BRASERO_SESSION_NO_OUTPUT;
850 return BRASERO_SESSION_NO_OUTPUT;
851 }
852
853 if (brasero_drive_is_fake (burner))
854 return brasero_session_cfg_check_volume_size (self);
855
856 medium = brasero_drive_get_medium (burner);
857 if (!medium) {
858 priv->is_valid = BRASERO_SESSION_NO_OUTPUT;
859 return BRASERO_SESSION_NO_OUTPUT;
860 }
861
862 /* Get both sizes if need be */
863 if (!priv->disc_size) {
864 priv->disc_size = brasero_burn_session_get_available_medium_space (BRASERO_BURN_SESSION (self));
865 if (priv->disc_size < 0)
866 priv->disc_size = 0;
867 }
868
869 BRASERO_BURN_LOG ("Session size %lli/Disc size %lli",
870 priv->session_blocks,
871 priv->disc_size);
872
873 if (priv->session_blocks < priv->disc_size) {
874 priv->is_valid = BRASERO_SESSION_VALID;
875 return BRASERO_SESSION_VALID;
876 }
877
878 /* Overburn is only for CDs */
879 if ((brasero_medium_get_status (medium) & BRASERO_MEDIUM_CD) == 0) {
880 priv->is_valid = BRASERO_SESSION_INSUFFICIENT_SPACE;
881 return BRASERO_SESSION_INSUFFICIENT_SPACE;
882 }
883
884 /* The idea would be to test write the disc with cdrecord from /dev/null
885 * until there is an error and see how much we were able to write. So,
886 * when we propose overburning to the user, we could ask if he wants
887 * us to determine how much data can be written to a particular disc
888 * provided he has chosen a real disc. */
889 max_sectors = priv->disc_size * 103 / 100;
890 if (max_sectors < priv->session_blocks) {
891 priv->is_valid = BRASERO_SESSION_INSUFFICIENT_SPACE;
892 return BRASERO_SESSION_INSUFFICIENT_SPACE;
893 }
894
895 flags = brasero_burn_session_get_flags (BRASERO_BURN_SESSION (self));
896 if (!(flags & BRASERO_BURN_FLAG_OVERBURN)) {
897 BraseroSessionCfgPrivate *priv;
898
899 priv = BRASERO_SESSION_CFG_PRIVATE (self);
900
901 if (!(priv->supported & BRASERO_BURN_FLAG_OVERBURN)) {
902 priv->is_valid = BRASERO_SESSION_INSUFFICIENT_SPACE;
903 return BRASERO_SESSION_INSUFFICIENT_SPACE;
904 }
905
906 priv->is_valid = BRASERO_SESSION_OVERBURN_NECESSARY;
907 return BRASERO_SESSION_OVERBURN_NECESSARY;
908 }
909
910 priv->is_valid = BRASERO_SESSION_VALID;
911 return BRASERO_SESSION_VALID;
912 }
913
914 static void
brasero_session_cfg_set_tracks_audio_format(BraseroBurnSession * session,BraseroStreamFormat format)915 brasero_session_cfg_set_tracks_audio_format (BraseroBurnSession *session,
916 BraseroStreamFormat format)
917 {
918 GSList *tracks;
919 GSList *iter;
920
921 tracks = brasero_burn_session_get_tracks (session);
922 for (iter = tracks; iter; iter = iter->next) {
923 BraseroTrack *track;
924
925 track = iter->data;
926 if (!BRASERO_IS_TRACK_STREAM (track))
927 continue;
928
929 brasero_track_stream_set_format (BRASERO_TRACK_STREAM (track), format);
930 }
931 }
932
933 static gboolean
brasero_session_cfg_can_update(BraseroSessionCfg * self)934 brasero_session_cfg_can_update (BraseroSessionCfg *self)
935 {
936 BraseroSessionCfgPrivate *priv;
937 BraseroBurnResult result;
938 BraseroStatus *status;
939
940 priv = BRASERO_SESSION_CFG_PRIVATE (self);
941
942 if (priv->disabled)
943 return FALSE;
944
945 if (priv->configuring)
946 return FALSE;
947
948 /* Make sure the session is ready */
949 status = brasero_status_new ();
950 result = brasero_burn_session_get_status (BRASERO_BURN_SESSION (self), status);
951 if (result == BRASERO_BURN_NOT_READY || result == BRASERO_BURN_RUNNING) {
952 g_object_unref (status);
953
954 priv->is_valid = BRASERO_SESSION_NOT_READY;
955 g_signal_emit (self,
956 session_cfg_signals [IS_VALID_SIGNAL],
957 0);
958 return FALSE;
959 }
960
961 if (result == BRASERO_BURN_ERR) {
962 GError *error;
963
964 error = brasero_status_get_error (status);
965 if (error) {
966 if (error->code == BRASERO_BURN_ERROR_EMPTY) {
967 g_object_unref (status);
968 g_error_free (error);
969
970 priv->is_valid = BRASERO_SESSION_EMPTY;
971 g_signal_emit (self,
972 session_cfg_signals [IS_VALID_SIGNAL],
973 0);
974 return FALSE;
975 }
976
977 g_error_free (error);
978 }
979 }
980 g_object_unref (status);
981 return TRUE;
982 }
983
984 static void
brasero_session_cfg_update(BraseroSessionCfg * self)985 brasero_session_cfg_update (BraseroSessionCfg *self)
986 {
987 BraseroSessionCfgPrivate *priv;
988 BraseroBurnResult result;
989 BraseroDrive *burner;
990
991 priv = BRASERO_SESSION_CFG_PRIVATE (self);
992
993 /* Make sure there is a source */
994 if (priv->source) {
995 brasero_track_type_free (priv->source);
996 priv->source = NULL;
997 }
998
999 priv->source = brasero_track_type_new ();
1000 brasero_burn_session_get_input_type (BRASERO_BURN_SESSION (self), priv->source);
1001
1002 if (brasero_track_type_is_empty (priv->source)) {
1003 priv->is_valid = BRASERO_SESSION_EMPTY;
1004 g_signal_emit (self,
1005 session_cfg_signals [IS_VALID_SIGNAL],
1006 0);
1007 return;
1008 }
1009
1010 /* it can be empty with just an empty track */
1011 if (brasero_track_type_get_has_medium (priv->source)
1012 && brasero_track_type_get_medium_type (priv->source) == BRASERO_MEDIUM_NONE) {
1013 priv->is_valid = BRASERO_SESSION_NO_INPUT_MEDIUM;
1014 g_signal_emit (self,
1015 session_cfg_signals [IS_VALID_SIGNAL],
1016 0);
1017 return;
1018 }
1019
1020 if (brasero_track_type_get_has_image (priv->source)
1021 && brasero_track_type_get_image_format (priv->source) == BRASERO_IMAGE_FORMAT_NONE) {
1022 gchar *uri;
1023 GSList *tracks;
1024
1025 tracks = brasero_burn_session_get_tracks (BRASERO_BURN_SESSION (self));
1026
1027 /* It can be two cases:
1028 * - no image set
1029 * - image format cannot be detected */
1030 if (tracks) {
1031 BraseroTrack *track;
1032
1033 track = tracks->data;
1034 uri = brasero_track_image_get_source (BRASERO_TRACK_IMAGE (track), TRUE);
1035 if (uri) {
1036 priv->is_valid = BRASERO_SESSION_UNKNOWN_IMAGE;
1037 g_free (uri);
1038 }
1039 else
1040 priv->is_valid = BRASERO_SESSION_NO_INPUT_IMAGE;
1041 }
1042 else
1043 priv->is_valid = BRASERO_SESSION_NO_INPUT_IMAGE;
1044
1045 g_signal_emit (self,
1046 session_cfg_signals [IS_VALID_SIGNAL],
1047 0);
1048 return;
1049 }
1050
1051 /* make sure there is an output set */
1052 burner = brasero_burn_session_get_burner (BRASERO_BURN_SESSION (self));
1053 if (!burner) {
1054 priv->is_valid = BRASERO_SESSION_NO_OUTPUT;
1055 g_signal_emit (self,
1056 session_cfg_signals [IS_VALID_SIGNAL],
1057 0);
1058 return;
1059 }
1060
1061 /* In case the output was an image remove the path cache. It will be
1062 * re-computed on demand. */
1063 if (priv->output) {
1064 g_free (priv->output);
1065 priv->output = NULL;
1066 }
1067
1068 if (priv->output_format)
1069 priv->output_format = BRASERO_IMAGE_FORMAT_NONE;
1070
1071 /* Check that current input and output work */
1072 if (brasero_track_type_get_has_stream (priv->source)) {
1073 if (priv->CD_TEXT_modified) {
1074 /* Try to redo what we undid (after all a new plugin
1075 * could have been activated in the mean time ...) and
1076 * see what happens */
1077 brasero_track_type_set_stream_format (priv->source,
1078 BRASERO_METADATA_INFO|
1079 brasero_track_type_get_stream_format (priv->source));
1080 result = brasero_burn_session_input_supported (BRASERO_BURN_SESSION (self), priv->source, FALSE);
1081 if (result == BRASERO_BURN_OK) {
1082 priv->CD_TEXT_modified = FALSE;
1083
1084 priv->configuring = TRUE;
1085 brasero_session_cfg_set_tracks_audio_format (BRASERO_BURN_SESSION (self),
1086 brasero_track_type_get_stream_format (priv->source));
1087 priv->configuring = FALSE;
1088 }
1089 else {
1090 /* No, nothing's changed */
1091 brasero_track_type_set_stream_format (priv->source,
1092 (~BRASERO_METADATA_INFO) &
1093 brasero_track_type_get_stream_format (priv->source));
1094 result = brasero_burn_session_input_supported (BRASERO_BURN_SESSION (self), priv->source, FALSE);
1095 }
1096 }
1097 else {
1098 result = brasero_burn_session_can_burn (BRASERO_BURN_SESSION (self), FALSE);
1099
1100 if (result != BRASERO_BURN_OK
1101 && (brasero_track_type_get_stream_format (priv->source) & BRASERO_METADATA_INFO)) {
1102 /* Another special case in case some burning backends
1103 * don't support CD-TEXT for audio (libburn). If no
1104 * other backend is available remove CD-TEXT option but
1105 * tell user... */
1106 brasero_track_type_set_stream_format (priv->source,
1107 (~BRASERO_METADATA_INFO) &
1108 brasero_track_type_get_stream_format (priv->source));
1109
1110 result = brasero_burn_session_input_supported (BRASERO_BURN_SESSION (self), priv->source, FALSE);
1111
1112 BRASERO_BURN_LOG ("Tested support without Metadata information (result %d)", result);
1113 if (result == BRASERO_BURN_OK) {
1114 priv->CD_TEXT_modified = TRUE;
1115
1116 priv->configuring = TRUE;
1117 brasero_session_cfg_set_tracks_audio_format (BRASERO_BURN_SESSION (self),
1118 brasero_track_type_get_has_stream (priv->source));
1119 priv->configuring = FALSE;
1120 }
1121 }
1122 }
1123 }
1124 else if (brasero_track_type_get_has_medium (priv->source)
1125 && (brasero_track_type_get_medium_type (priv->source) & BRASERO_MEDIUM_HAS_AUDIO)) {
1126 BraseroImageFormat format = BRASERO_IMAGE_FORMAT_NONE;
1127
1128 /* If we copy an audio disc check the image
1129 * type we're writing to as it may mean that
1130 * CD-TEXT cannot be copied.
1131 * Make sure that the writing backend
1132 * supports writing CD-TEXT?
1133 * no, if a backend reports it supports an
1134 * image type it should be able to burn all
1135 * its data. */
1136 if (!brasero_burn_session_is_dest_file (BRASERO_BURN_SESSION (self))) {
1137 BraseroTrackType *tmp_type;
1138
1139 tmp_type = brasero_track_type_new ();
1140
1141 /* NOTE: this is the same as brasero_burn_session_supported () */
1142 result = brasero_burn_session_get_tmp_image_type_same_src_dest (BRASERO_BURN_SESSION (self), tmp_type);
1143 if (result == BRASERO_BURN_OK) {
1144 if (brasero_track_type_get_has_image (tmp_type)) {
1145 format = brasero_track_type_get_image_format (tmp_type);
1146 priv->CD_TEXT_modified = (format & (BRASERO_IMAGE_FORMAT_CDRDAO|BRASERO_IMAGE_FORMAT_CUE)) == 0;
1147 }
1148 else if (brasero_track_type_get_has_stream (tmp_type)) {
1149 /* FIXME: for the moment
1150 * we consider that this
1151 * type will always allow
1152 * to copy CD-TEXT */
1153 priv->CD_TEXT_modified = FALSE;
1154 }
1155 else
1156 priv->CD_TEXT_modified = TRUE;
1157 }
1158 else
1159 priv->CD_TEXT_modified = TRUE;
1160
1161 brasero_track_type_free (tmp_type);
1162
1163 BRASERO_BURN_LOG ("Temporary image type %i", format);
1164 }
1165 else {
1166 result = brasero_burn_session_can_burn (BRASERO_BURN_SESSION (self), FALSE);
1167 format = brasero_burn_session_get_output_format (BRASERO_BURN_SESSION (self));
1168 priv->CD_TEXT_modified = (format & (BRASERO_IMAGE_FORMAT_CDRDAO|BRASERO_IMAGE_FORMAT_CUE)) == 0;
1169 }
1170 }
1171 else {
1172 /* Don't use flags as they'll be adapted later. */
1173 priv->CD_TEXT_modified = FALSE;
1174 result = brasero_burn_session_can_burn (BRASERO_BURN_SESSION (self), FALSE);
1175 }
1176
1177 if (result != BRASERO_BURN_OK) {
1178 if (brasero_track_type_get_has_medium (priv->source)
1179 && (brasero_track_type_get_medium_type (priv->source) & BRASERO_MEDIUM_PROTECTED)
1180 && brasero_burn_library_input_supported (priv->source) != BRASERO_BURN_OK) {
1181 /* This is a special case to display a helpful message */
1182 priv->is_valid = BRASERO_SESSION_DISC_PROTECTED;
1183 g_signal_emit (self,
1184 session_cfg_signals [IS_VALID_SIGNAL],
1185 0);
1186 }
1187 else {
1188 priv->is_valid = BRASERO_SESSION_NOT_SUPPORTED;
1189 g_signal_emit (self,
1190 session_cfg_signals [IS_VALID_SIGNAL],
1191 0);
1192 }
1193
1194 return;
1195 }
1196
1197 /* Special case for video projects */
1198 if (brasero_track_type_get_has_stream (priv->source)
1199 && BRASERO_STREAM_FORMAT_HAS_VIDEO (brasero_track_type_get_stream_format (priv->source))) {
1200 /* Only set if it was not already set */
1201 if (brasero_burn_session_tag_lookup (BRASERO_BURN_SESSION (self), BRASERO_VCD_TYPE, NULL) != BRASERO_BURN_OK)
1202 brasero_burn_session_tag_add_int (BRASERO_BURN_SESSION (self),
1203 BRASERO_VCD_TYPE,
1204 BRASERO_SVCD);
1205 }
1206
1207 /* Configure flags */
1208 priv->configuring = TRUE;
1209
1210 if (brasero_drive_is_fake (burner))
1211 /* Remove some impossible flags */
1212 brasero_burn_session_remove_flag (BRASERO_BURN_SESSION (self),
1213 BRASERO_BURN_FLAG_DUMMY|
1214 BRASERO_BURN_FLAG_NO_TMP_FILES);
1215
1216 priv->configuring = FALSE;
1217
1218 /* Finally check size */
1219 if (brasero_burn_session_same_src_dest_drive (BRASERO_BURN_SESSION (self))) {
1220 priv->is_valid = BRASERO_SESSION_VALID;
1221 g_signal_emit (self,
1222 session_cfg_signals [IS_VALID_SIGNAL],
1223 0);
1224 }
1225 else {
1226 brasero_session_cfg_check_size (self);
1227 g_signal_emit (self,
1228 session_cfg_signals [IS_VALID_SIGNAL],
1229 0);
1230 }
1231 }
1232
1233 static void
brasero_session_cfg_session_loaded(BraseroTrackDataCfg * track,BraseroMedium * medium,gboolean is_loaded,BraseroSessionCfg * session)1234 brasero_session_cfg_session_loaded (BraseroTrackDataCfg *track,
1235 BraseroMedium *medium,
1236 gboolean is_loaded,
1237 BraseroSessionCfg *session)
1238 {
1239 BraseroBurnFlag session_flags;
1240 BraseroSessionCfgPrivate *priv;
1241
1242 priv = BRASERO_SESSION_CFG_PRIVATE (session);
1243 if (priv->disabled)
1244 return;
1245
1246 priv->session_blocks = 0;
1247 priv->session_size = 0;
1248
1249 session_flags = brasero_burn_session_get_flags (BRASERO_BURN_SESSION (session));
1250 if (is_loaded) {
1251 /* Set the correct medium and add the flag */
1252 brasero_burn_session_set_burner (BRASERO_BURN_SESSION (session),
1253 brasero_medium_get_drive (medium));
1254
1255 if ((session_flags & BRASERO_BURN_FLAG_MERGE) == 0)
1256 brasero_session_cfg_add_drive_properties_flags (session, BRASERO_BURN_FLAG_MERGE);
1257 }
1258 else if ((session_flags & BRASERO_BURN_FLAG_MERGE) != 0)
1259 brasero_session_cfg_rm_drive_properties_flags (session, BRASERO_BURN_FLAG_MERGE);
1260 }
1261
1262 static void
brasero_session_cfg_track_added(BraseroBurnSession * session,BraseroTrack * track)1263 brasero_session_cfg_track_added (BraseroBurnSession *session,
1264 BraseroTrack *track)
1265 {
1266 BraseroSessionCfgPrivate *priv;
1267
1268 if (!brasero_session_cfg_can_update (BRASERO_SESSION_CFG (session)))
1269 return;
1270
1271 priv = BRASERO_SESSION_CFG_PRIVATE (session);
1272 priv->session_blocks = 0;
1273 priv->session_size = 0;
1274
1275 if (BRASERO_IS_TRACK_DATA_CFG (track))
1276 g_signal_connect (track,
1277 "session-loaded",
1278 G_CALLBACK (brasero_session_cfg_session_loaded),
1279 session);
1280
1281 /* A track was added:
1282 * - check if all flags are supported
1283 * - check available formats for path
1284 * - set one path */
1285 brasero_session_cfg_update (BRASERO_SESSION_CFG (session));
1286 brasero_session_cfg_check_drive_settings (BRASERO_SESSION_CFG (session));
1287 }
1288
1289 static void
brasero_session_cfg_track_removed(BraseroBurnSession * session,BraseroTrack * track,guint former_position)1290 brasero_session_cfg_track_removed (BraseroBurnSession *session,
1291 BraseroTrack *track,
1292 guint former_position)
1293 {
1294 BraseroSessionCfgPrivate *priv;
1295
1296 if (!brasero_session_cfg_can_update (BRASERO_SESSION_CFG (session)))
1297 return;
1298
1299 priv = BRASERO_SESSION_CFG_PRIVATE (session);
1300 priv->session_blocks = 0;
1301 priv->session_size = 0;
1302
1303 /* Just in case */
1304 g_signal_handlers_disconnect_by_func (track,
1305 brasero_session_cfg_session_loaded,
1306 session);
1307
1308 /* If there were several tracks and at least one remained there is no
1309 * use checking flags since the source type has not changed anyway.
1310 * If there is no more track, there is no use checking flags anyway. */
1311 brasero_session_cfg_update (BRASERO_SESSION_CFG (session));
1312 }
1313
1314 static void
brasero_session_cfg_track_changed(BraseroBurnSession * session,BraseroTrack * track)1315 brasero_session_cfg_track_changed (BraseroBurnSession *session,
1316 BraseroTrack *track)
1317 {
1318 BraseroSessionCfgPrivate *priv;
1319 BraseroTrackType *current;
1320
1321 if (!brasero_session_cfg_can_update (BRASERO_SESSION_CFG (session)))
1322 return;
1323
1324 priv = BRASERO_SESSION_CFG_PRIVATE (session);
1325 priv->session_blocks = 0;
1326 priv->session_size = 0;
1327
1328 current = brasero_track_type_new ();
1329 brasero_burn_session_get_input_type (session, current);
1330 if (brasero_track_type_equal (current, priv->source)) {
1331 /* This is a shortcut if the source type has not changed */
1332 brasero_track_type_free (current);
1333 brasero_session_cfg_check_size (BRASERO_SESSION_CFG (session));
1334 g_signal_emit (session,
1335 session_cfg_signals [IS_VALID_SIGNAL],
1336 0);
1337 return;
1338 }
1339 brasero_track_type_free (current);
1340
1341 /* when that happens it's mostly because a medium source changed, or
1342 * a new image was set.
1343 * - check if all flags are supported
1344 * - check available formats for path
1345 * - set one path if need be */
1346 brasero_session_cfg_update (BRASERO_SESSION_CFG (session));
1347 brasero_session_cfg_check_drive_settings (BRASERO_SESSION_CFG (session));
1348 }
1349
1350 static void
brasero_session_cfg_output_changed(BraseroBurnSession * session,BraseroMedium * former)1351 brasero_session_cfg_output_changed (BraseroBurnSession *session,
1352 BraseroMedium *former)
1353 {
1354 BraseroSessionCfgPrivate *priv;
1355
1356 if (!brasero_session_cfg_can_update (BRASERO_SESSION_CFG (session)))
1357 return;
1358
1359 priv = BRASERO_SESSION_CFG_PRIVATE (session);
1360 priv->disc_size = 0;
1361
1362 /* Case for video project */
1363 if (priv->source
1364 && brasero_track_type_get_has_stream (priv->source)
1365 && BRASERO_STREAM_FORMAT_HAS_VIDEO (brasero_track_type_get_stream_format (priv->source))) {
1366 BraseroMedia media;
1367
1368 media = brasero_burn_session_get_dest_media (session);
1369 if (media & BRASERO_MEDIUM_DVD)
1370 brasero_burn_session_tag_add_int (session,
1371 BRASERO_DVD_STREAM_FORMAT,
1372 BRASERO_AUDIO_FORMAT_AC3);
1373 else if (media & BRASERO_MEDIUM_CD)
1374 brasero_burn_session_tag_add_int (session,
1375 BRASERO_DVD_STREAM_FORMAT,
1376 BRASERO_AUDIO_FORMAT_MP2);
1377 else {
1378 BraseroImageFormat format;
1379
1380 format = brasero_burn_session_get_output_format (session);
1381 if (format == BRASERO_IMAGE_FORMAT_CUE)
1382 brasero_burn_session_tag_add_int (session,
1383 BRASERO_DVD_STREAM_FORMAT,
1384 BRASERO_AUDIO_FORMAT_MP2);
1385 else
1386 brasero_burn_session_tag_add_int (session,
1387 BRASERO_DVD_STREAM_FORMAT,
1388 BRASERO_AUDIO_FORMAT_AC3);
1389 }
1390 }
1391
1392 /* In this case need to :
1393 * - check if all flags are supported
1394 * - for images, set a path if it wasn't already set */
1395 brasero_session_cfg_update (BRASERO_SESSION_CFG (session));
1396 brasero_session_cfg_check_drive_settings (BRASERO_SESSION_CFG (session));
1397 }
1398
1399 static void
brasero_session_cfg_caps_changed(BraseroPluginManager * manager,BraseroSessionCfg * self)1400 brasero_session_cfg_caps_changed (BraseroPluginManager *manager,
1401 BraseroSessionCfg *self)
1402 {
1403 BraseroSessionCfgPrivate *priv;
1404
1405 if (!brasero_session_cfg_can_update (self))
1406 return;
1407
1408 priv = BRASERO_SESSION_CFG_PRIVATE (self);
1409 priv->disc_size = 0;
1410 priv->session_blocks = 0;
1411 priv->session_size = 0;
1412
1413 /* In this case we need to check if:
1414 * - flags are supported or not supported anymore
1415 * - image types as input/output are supported
1416 * - if the current set of input/output still works */
1417 brasero_session_cfg_update (self);
1418 brasero_session_cfg_check_drive_settings (self);
1419 }
1420
1421 /**
1422 * brasero_session_cfg_add_flags:
1423 * @session: a #BraseroSessionCfg
1424 * @flags: a #BraseroBurnFlag
1425 *
1426 * Adds all flags from @flags that are supported.
1427 *
1428 **/
1429
1430 void
brasero_session_cfg_add_flags(BraseroSessionCfg * session,BraseroBurnFlag flags)1431 brasero_session_cfg_add_flags (BraseroSessionCfg *session,
1432 BraseroBurnFlag flags)
1433 {
1434 BraseroSessionCfgPrivate *priv;
1435
1436 priv = BRASERO_SESSION_CFG_PRIVATE (session);
1437
1438 if ((priv->supported & flags) != flags)
1439 return;
1440
1441 if ((brasero_burn_session_get_flags (BRASERO_BURN_SESSION (session)) & flags) == flags)
1442 return;
1443
1444 brasero_session_cfg_add_drive_properties_flags (session, flags);
1445
1446 if (brasero_session_cfg_can_update (session))
1447 brasero_session_cfg_update (session);
1448 }
1449
1450 /**
1451 * brasero_session_cfg_remove_flags:
1452 * @session: a #BraseroSessionCfg
1453 * @flags: a #BraseroBurnFlag
1454 *
1455 * Removes all flags that are not compulsory.
1456 *
1457 **/
1458
1459 void
brasero_session_cfg_remove_flags(BraseroSessionCfg * session,BraseroBurnFlag flags)1460 brasero_session_cfg_remove_flags (BraseroSessionCfg *session,
1461 BraseroBurnFlag flags)
1462 {
1463 brasero_burn_session_remove_flag (BRASERO_BURN_SESSION (session), flags);
1464
1465 /* For this case reset all flags as some flags could
1466 * be made available after the removal of one flag
1467 * Example: After the removal of MULTI, FAST_BLANK
1468 * becomes available again for DVDRW sequential */
1469 brasero_session_cfg_set_drive_properties_default_flags (session);
1470
1471 if (brasero_session_cfg_can_update (session))
1472 brasero_session_cfg_update (session);
1473 }
1474
1475 /**
1476 * brasero_session_cfg_is_supported:
1477 * @session: a #BraseroSessionCfg
1478 * @flag: a #BraseroBurnFlag
1479 *
1480 * Checks whether a particular flag is supported.
1481 *
1482 * Return value: a #gboolean. TRUE if it is supported;
1483 * FALSE otherwise.
1484 **/
1485
1486 gboolean
brasero_session_cfg_is_supported(BraseroSessionCfg * session,BraseroBurnFlag flag)1487 brasero_session_cfg_is_supported (BraseroSessionCfg *session,
1488 BraseroBurnFlag flag)
1489 {
1490 BraseroSessionCfgPrivate *priv;
1491
1492 priv = BRASERO_SESSION_CFG_PRIVATE (session);
1493 return (priv->supported & flag) == flag;
1494 }
1495
1496 /**
1497 * brasero_session_cfg_is_compulsory:
1498 * @session: a #BraseroSessionCfg
1499 * @flag: a #BraseroBurnFlag
1500 *
1501 * Checks whether a particular flag is compulsory.
1502 *
1503 * Return value: a #gboolean. TRUE if it is compulsory;
1504 * FALSE otherwise.
1505 **/
1506
1507 gboolean
brasero_session_cfg_is_compulsory(BraseroSessionCfg * session,BraseroBurnFlag flag)1508 brasero_session_cfg_is_compulsory (BraseroSessionCfg *session,
1509 BraseroBurnFlag flag)
1510 {
1511 BraseroSessionCfgPrivate *priv;
1512
1513 priv = BRASERO_SESSION_CFG_PRIVATE (session);
1514 return (priv->compulsory & flag) == flag;
1515 }
1516
1517 static void
brasero_session_cfg_init(BraseroSessionCfg * object)1518 brasero_session_cfg_init (BraseroSessionCfg *object)
1519 {
1520 BraseroSessionCfgPrivate *priv;
1521 BraseroPluginManager *manager;
1522
1523 priv = BRASERO_SESSION_CFG_PRIVATE (object);
1524
1525 priv->is_valid = BRASERO_SESSION_EMPTY;
1526 manager = brasero_plugin_manager_get_default ();
1527 g_signal_connect (manager,
1528 "caps-changed",
1529 G_CALLBACK (brasero_session_cfg_caps_changed),
1530 object);
1531 }
1532
1533 static void
brasero_session_cfg_finalize(GObject * object)1534 brasero_session_cfg_finalize (GObject *object)
1535 {
1536 BraseroPluginManager *manager;
1537 BraseroSessionCfgPrivate *priv;
1538 GSList *tracks;
1539
1540 priv = BRASERO_SESSION_CFG_PRIVATE (object);
1541
1542 tracks = brasero_burn_session_get_tracks (BRASERO_BURN_SESSION (object));
1543 for (; tracks; tracks = tracks->next) {
1544 BraseroTrack *track;
1545
1546 track = tracks->data;
1547 g_signal_handlers_disconnect_by_func (track,
1548 brasero_session_cfg_session_loaded,
1549 object);
1550 }
1551
1552 manager = brasero_plugin_manager_get_default ();
1553 g_signal_handlers_disconnect_by_func (manager,
1554 brasero_session_cfg_caps_changed,
1555 object);
1556
1557 if (priv->source) {
1558 brasero_track_type_free (priv->source);
1559 priv->source = NULL;
1560 }
1561
1562 if (priv->output) {
1563 g_free (priv->output);
1564 priv->output = NULL;
1565 }
1566
1567 G_OBJECT_CLASS (brasero_session_cfg_parent_class)->finalize (object);
1568 }
1569
1570 static void
brasero_session_cfg_class_init(BraseroSessionCfgClass * klass)1571 brasero_session_cfg_class_init (BraseroSessionCfgClass *klass)
1572 {
1573 GObjectClass* object_class = G_OBJECT_CLASS (klass);
1574 BraseroBurnSessionClass *session_class = BRASERO_BURN_SESSION_CLASS (klass);
1575
1576 g_type_class_add_private (klass, sizeof (BraseroSessionCfgPrivate));
1577
1578 object_class->finalize = brasero_session_cfg_finalize;
1579
1580 session_class->get_output_path = brasero_session_cfg_get_output_path;
1581 session_class->get_output_format = brasero_session_cfg_get_output_format;
1582 session_class->set_output_image = brasero_session_cfg_set_output_image;
1583
1584 session_class->track_added = brasero_session_cfg_track_added;
1585 session_class->track_removed = brasero_session_cfg_track_removed;
1586 session_class->track_changed = brasero_session_cfg_track_changed;
1587 session_class->output_changed = brasero_session_cfg_output_changed;
1588 session_class->tag_changed = brasero_session_cfg_tag_changed;
1589
1590 session_cfg_signals [WRONG_EXTENSION_SIGNAL] =
1591 g_signal_new ("wrong_extension",
1592 G_OBJECT_CLASS_TYPE (klass),
1593 G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP | G_SIGNAL_ACTION,
1594 0,
1595 NULL, NULL,
1596 brasero_marshal_BOOLEAN__VOID,
1597 G_TYPE_BOOLEAN,
1598 0,
1599 G_TYPE_NONE);
1600 session_cfg_signals [IS_VALID_SIGNAL] =
1601 g_signal_new ("is_valid",
1602 G_OBJECT_CLASS_TYPE (klass),
1603 G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP | G_SIGNAL_ACTION,
1604 0,
1605 NULL, NULL,
1606 g_cclosure_marshal_VOID__VOID,
1607 G_TYPE_NONE,
1608 0,
1609 G_TYPE_NONE);
1610 }
1611
1612 /**
1613 * brasero_session_cfg_new:
1614 *
1615 * Creates a new #BraseroSessionCfg object.
1616 *
1617 * Return value: a #BraseroSessionCfg object.
1618 **/
1619
1620 BraseroSessionCfg *
brasero_session_cfg_new(void)1621 brasero_session_cfg_new (void)
1622 {
1623 return g_object_new (BRASERO_TYPE_SESSION_CFG, NULL);
1624 }
1625