[brasero] Integrated previous changes so that now a data or an audio project can be written across several med



commit 5f9ac14a6723049cfeca8a9ae314ca413d0e25f2
Author: Philippe Rouquier <bonfire-app wanadoo fr>
Date:   Sat May 16 20:45:07 2009 +0200

    Integrated previous changes so that now a data or an audio project can be written across several media
---
 libbrasero-burn/brasero-burn-dialog.c    |  231 ++++++++++++++-------
 libbrasero-burn/brasero-burn-options.c   |   49 ++++-
 libbrasero-burn/brasero-data-project.c   |   77 +++++++-
 libbrasero-burn/brasero-data-project.h   |    8 +-
 libbrasero-burn/brasero-session-span.c   |  328 ++++++++++++++++++++++++++++++
 libbrasero-burn/brasero-session-span.h   |   82 ++++++++
 libbrasero-burn/brasero-session.c        |   10 +-
 libbrasero-burn/brasero-track-data-cfg.c |   34 +++
 libbrasero-burn/brasero-track-data-cfg.h |    9 +
 9 files changed, 742 insertions(+), 86 deletions(-)

diff --git a/libbrasero-burn/brasero-burn-dialog.c b/libbrasero-burn/brasero-burn-dialog.c
index 7ef6dfa..a81775c 100644
--- a/libbrasero-burn/brasero-burn-dialog.c
+++ b/libbrasero-burn/brasero-burn-dialog.c
@@ -397,6 +397,85 @@ brasero_burn_dialog_update_info (BraseroBurnDialog *dialog,
 	gtk_window_set_icon_name (GTK_WINDOW (dialog), "brasero");
 }
 
+static void
+brasero_burn_dialog_wait_for_insertion_cb (BraseroDrive *drive,
+					   BraseroMedium *medium,
+					   GtkDialog *message)
+{
+	/* we might have a dialog waiting for the 
+	 * insertion of a disc if so close it */
+	gtk_dialog_response (GTK_DIALOG (message), GTK_RESPONSE_OK);
+}
+
+static gint
+brasero_burn_dialog_wait_for_insertion (BraseroBurnDialog *dialog,
+					BraseroDrive *drive,
+					const gchar *main_message,
+					const gchar *secondary_message)
+{
+	gint result;
+	gint added_id;
+	GtkWindow *window;
+	GtkWidget *message;
+	gboolean hide = FALSE;
+	BraseroBurnDialogPrivate *priv;
+
+	priv = BRASERO_BURN_DIALOG_PRIVATE (dialog);
+	window = GTK_WINDOW (dialog);
+
+	if (!GTK_WIDGET_VISIBLE (dialog)) {
+		gtk_widget_show (GTK_WIDGET (dialog));
+		hide = TRUE;
+	}
+
+	g_timer_stop (priv->total_time);
+
+	if (secondary_message) {
+		message = gtk_message_dialog_new (window,
+						  GTK_DIALOG_DESTROY_WITH_PARENT|
+						  GTK_DIALOG_MODAL,
+						  GTK_MESSAGE_WARNING,
+						  GTK_BUTTONS_CANCEL,
+						  "%s", main_message);
+
+		if (secondary_message)
+			gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (message),
+								  "%s", secondary_message);
+	}
+	else {
+		gchar *string;
+
+		message = gtk_message_dialog_new_with_markup (window,
+							      GTK_DIALOG_DESTROY_WITH_PARENT|
+							      GTK_DIALOG_MODAL,
+							      GTK_MESSAGE_WARNING,
+							      GTK_BUTTONS_CANCEL,
+							      NULL);
+
+		string = g_strdup_printf ("<b><big>%s</big></b>", main_message);
+		gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (message), string);
+		g_free (string);
+	}
+
+	/* connect to signals to be warned when media is inserted */
+	added_id = g_signal_connect_after (drive,
+					   "medium-added",
+					   G_CALLBACK (brasero_burn_dialog_wait_for_insertion_cb),
+					   message);
+
+	result = gtk_dialog_run (GTK_DIALOG (message));
+
+	g_signal_handler_disconnect (drive, added_id);
+	gtk_widget_destroy (message);
+
+	if (hide)
+		gtk_widget_hide (GTK_WIDGET (dialog));
+
+	g_timer_start (priv->total_time);
+
+	return result;
+}
+
 static gchar *
 brasero_burn_dialog_get_media_type_string (BraseroBurn *burn,
 					   BraseroMedia type,
@@ -478,16 +557,6 @@ brasero_burn_dialog_get_media_type_string (BraseroBurn *burn,
 	return message;
 }
 
-static void
-brasero_burn_dialog_wait_for_insertion (BraseroDrive *drive,
-					BraseroMedium *medium,
-					GtkDialog *message)
-{
-	/* we might have a dialog waiting for the 
-	 * insertion of a disc if so close it */
-	gtk_dialog_response (GTK_DIALOG (message), GTK_RESPONSE_OK);
-}
-
 static BraseroBurnResult
 brasero_burn_dialog_insert_disc_cb (BraseroBurn *burn,
 				    BraseroDrive *drive,
@@ -496,23 +565,12 @@ brasero_burn_dialog_insert_disc_cb (BraseroBurn *burn,
 				    BraseroBurnDialog *dialog)
 {
 	gint result;
-	gint added_id;
 	gchar *drive_name;
-	GtkWindow *window;
-	GtkWidget *message;
-	gboolean hide = FALSE;
 	BraseroBurnDialogPrivate *priv;
 	gchar *main_message = NULL, *secondary_message = NULL;
 
 	priv = BRASERO_BURN_DIALOG_PRIVATE (dialog);
 
-	if (!GTK_WIDGET_VISIBLE (dialog)) {
-		gtk_widget_show (GTK_WIDGET (dialog));
-		hide = TRUE;
-	}
-
-	g_timer_stop (priv->total_time);
-
 	if (drive)
 		drive_name = brasero_drive_get_display_name (drive);
 	else
@@ -567,60 +625,15 @@ brasero_burn_dialog_insert_disc_cb (BraseroBurn *burn,
 
 	g_free (drive_name);
 
-	window = GTK_WINDOW (dialog);
-
-	if (secondary_message) {
-		message = gtk_message_dialog_new (window,
-						  GTK_DIALOG_DESTROY_WITH_PARENT|
-						  GTK_DIALOG_MODAL,
-						  GTK_MESSAGE_WARNING,
-						  GTK_BUTTONS_CANCEL,
-						  "%s", main_message);
-
-		if (secondary_message) {
-			gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (message),
-								  "%s", secondary_message);
-			g_free (secondary_message);
-		}
-	}
-	else {
-		gchar *string;
-
-		message = gtk_message_dialog_new_with_markup (window,
-							      GTK_DIALOG_DESTROY_WITH_PARENT|
-							      GTK_DIALOG_MODAL,
-							      GTK_MESSAGE_WARNING,
-							      GTK_BUTTONS_CANCEL,
-							      NULL);
-
-		string = g_strdup_printf ("<b><big>%s</big></b>", main_message);
-		gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (message), string);
-		g_free (string);
-	}
-
+	result = brasero_burn_dialog_wait_for_insertion (dialog, drive, main_message, secondary_message);
 	g_free (main_message);
+	g_free (secondary_message);
 
-	/* connect to signals to be warned when media is inserted */
-	added_id = g_signal_connect_after (drive,
-					   "medium-added",
-					   G_CALLBACK (brasero_burn_dialog_wait_for_insertion),
-					   message);
-
-	result = gtk_dialog_run (GTK_DIALOG (message));
-
-	g_signal_handler_disconnect (drive, added_id);
-	gtk_widget_destroy (message);
-
-	/* see if we should update the infos */
+	/* update the infos */
 	brasero_burn_dialog_update_info (dialog,
 					 &priv->input, 
 					 brasero_burn_session_get_dest_media (priv->session));
 
-	if (hide)
-		gtk_widget_hide (GTK_WIDGET (dialog));
-
-	g_timer_start (priv->total_time);
-
 	if (result != GTK_RESPONSE_OK)
 		return BRASERO_BURN_CANCEL;
 
@@ -2042,6 +2055,76 @@ brasero_burn_dialog_end_session (BraseroBurnDialog *dialog,
 }
 
 static BraseroBurnResult
+brasero_burn_dialog_record_spanned_session (BraseroBurnDialog *dialog,
+					    GError **error)
+{
+	BraseroDrive *burner;
+	BraseroTrackType *type;
+	BraseroBurnResult result;
+	BraseroBurnDialogPrivate *priv;
+	gchar *secondary_message = NULL;
+
+	priv = BRASERO_BURN_DIALOG_PRIVATE (dialog);
+	burner = brasero_burn_session_get_burner (priv->session);
+
+	type = brasero_track_type_new ();
+	if (brasero_track_type_get_has_data (type))
+		secondary_message = g_strdup (_("There are some files left to burn."));
+	else if (brasero_track_type_get_has_stream (type)) {
+		if (BRASERO_STREAM_FORMAT_HAS_VIDEO (brasero_track_type_get_stream_format (type)))
+			secondary_message = g_strdup (_("There are some more videos left to burn."));
+		else
+			secondary_message = g_strdup (_("There are some more songs left to burn."));
+	}
+	brasero_track_type_free (type);
+
+	do {
+		gint res;
+
+		result = brasero_burn_record (priv->burn,
+					      priv->session,
+					      error);
+		if (result != BRASERO_BURN_OK) {
+			g_free (secondary_message);
+			return result;
+		}
+
+		/* See if we have more data to burn and ask for a new medium */
+		result = brasero_session_span_again (BRASERO_SESSION_SPAN (priv->session));
+		if (result == BRASERO_BURN_OK) {
+			g_free (secondary_message);
+			return BRASERO_BURN_OK;
+		}
+
+		res = brasero_burn_dialog_wait_for_insertion (dialog,
+							      burner,
+							      _("Please insert a recordable CD or DVD."),
+							      secondary_message);
+		if (res != GTK_RESPONSE_OK) {
+			g_free (secondary_message);
+			return BRASERO_BURN_CANCEL;
+		}
+
+		result = brasero_session_span_next (BRASERO_SESSION_SPAN (priv->session));
+		while (result == BRASERO_BURN_ERR) {
+			res = brasero_burn_dialog_wait_for_insertion (dialog,
+								      burner,
+								      _("Please insert a recordable CD or DVD."),
+								      _("Not enough space available on the disc"));
+			if (res != GTK_RESPONSE_OK) {
+				g_free (secondary_message);
+				return BRASERO_BURN_CANCEL;
+			}
+			result = brasero_session_span_next (BRASERO_SESSION_SPAN (priv->session));
+		}
+
+	} while (result == BRASERO_BURN_RETRY);
+
+	brasero_session_span_stop (BRASERO_SESSION_SPAN (priv->session));
+	return result;
+}
+
+static BraseroBurnResult
 brasero_burn_dialog_record_session (BraseroBurnDialog *dialog,
 				    BraseroMedia media)
 {
@@ -2060,14 +2143,16 @@ brasero_burn_dialog_record_session (BraseroBurnDialog *dialog,
 	if (result != BRASERO_BURN_OK)
 		return result;
 
-	result = brasero_burn_record (priv->burn,
-				      priv->session,
-				      &error);
+	if (BRASERO_IS_SESSION_SPAN (priv->session))
+		result = brasero_burn_dialog_record_spanned_session (dialog, &error);
+	else
+		result = brasero_burn_record (priv->burn,
+					      priv->session,
+					      &error);
 
 	retry = brasero_burn_dialog_end_session (dialog,
 						 result,
 						 error);
-
 	if (result == BRASERO_BURN_RETRY)
 		return result;
 
diff --git a/libbrasero-burn/brasero-burn-options.c b/libbrasero-burn/brasero-burn-options.c
index 4dc8456..9e1fcdf 100644
--- a/libbrasero-burn/brasero-burn-options.c
+++ b/libbrasero-burn/brasero-burn-options.c
@@ -43,6 +43,7 @@
 #include "brasero-medium.h"
 #include "brasero-medium-selection-priv.h"
 
+#include "burn-debug.h"
 #include "brasero-session.h"
 #include "brasero-session-helper.h"
 #include "brasero-burn-options.h"
@@ -215,6 +216,21 @@ brasero_burn_options_message_response_cb (BraseroDiscMessage *message,
 	}
 }
 
+static void
+brasero_burn_options_message_response_span_cb (BraseroDiscMessage *message,
+					       GtkResponseType response,
+					       BraseroBurnOptions *self)
+{
+	if (response == GTK_RESPONSE_OK) {
+		BraseroBurnOptionsPrivate *priv;
+
+		priv = BRASERO_BURN_OPTIONS_PRIVATE (self);
+		brasero_session_span_start (BRASERO_SESSION_SPAN (priv->session));
+		if (brasero_session_span_next (BRASERO_SESSION_SPAN (priv->session)) == BRASERO_BURN_ERR)
+			BRASERO_BURN_LOG ("Spanning failed\n");
+	}
+}
+
 #define BRASERO_BURN_OPTIONS_NO_MEDIUM_WARNING	1000
 
 static void
@@ -321,11 +337,33 @@ brasero_burn_options_update_valid (BraseroBurnOptions *self)
 	}
 
 	if (valid == BRASERO_SESSION_INSUFFICIENT_SPACE) {
-		brasero_notify_message_add (BRASERO_NOTIFY (priv->message_output),
-					    _("Please choose another CD or DVD or insert a new one."),
-					    _("The size of the project is too large for the disc even with the overburn option."),
-					    -1,
-					    BRASERO_NOTIFY_CONTEXT_SIZE);
+		/* Here there is an alternative: we may be able to span the data
+		 * across multiple media. So try that. */
+		if (brasero_session_span_possible (BRASERO_SESSION_SPAN (priv->session)) == BRASERO_BURN_RETRY) {
+			GtkWidget *message;
+
+			message = brasero_notify_message_add (BRASERO_NOTIFY (priv->message_output),
+							      _("Would you like to burn the selection of files across several media?"),
+							      _("The size of the project is too large for the disc even with the overburn option."),
+							      -1,
+							      BRASERO_NOTIFY_CONTEXT_SIZE);
+			brasero_notify_button_add (BRASERO_NOTIFY (priv->message_output),
+						   BRASERO_DISC_MESSAGE (message),
+						   _("_Span File Selection"),
+						   _("Burn the selection of files across several media"),
+						   GTK_RESPONSE_OK);
+
+			g_signal_connect (message,
+					  "response",
+					  G_CALLBACK (brasero_burn_options_message_response_span_cb),
+					  self);
+		}
+		else
+			brasero_notify_message_add (BRASERO_NOTIFY (priv->message_output),
+						    _("Please choose another CD or DVD or insert a new one."),
+						    _("The size of the project is too large for the disc even with the overburn option."),
+						    -1,
+						    BRASERO_NOTIFY_CONTEXT_SIZE);
 	}
 	else if (valid == BRASERO_SESSION_NO_OUTPUT) {
 		brasero_notify_message_add (BRASERO_NOTIFY (priv->message_output),
@@ -366,6 +404,7 @@ brasero_burn_options_update_valid (BraseroBurnOptions *self)
 						    -1,
 						    BRASERO_NOTIFY_CONTEXT_SIZE);
 		brasero_track_type_free (type);
+		gtk_window_resize (GTK_WINDOW (self), 10, 10);
 		return;		      
 	}
 	else if (valid == BRASERO_SESSION_NO_INPUT_MEDIUM) {
diff --git a/libbrasero-burn/brasero-data-project.c b/libbrasero-burn/brasero-data-project.c
index 9ef2254..a04fc9e 100644
--- a/libbrasero-burn/brasero-data-project.c
+++ b/libbrasero-burn/brasero-data-project.c
@@ -52,6 +52,7 @@
 #include "brasero-misc.h"
 #include "brasero-io.h"
 
+#include "burn-debug.h"
 #include "brasero-track-data.h"
 
 typedef struct _BraseroDataProjectPrivate BraseroDataProjectPrivate;
@@ -2494,7 +2495,7 @@ brasero_data_project_span_generate (BraseroDataProject *self,
 			graft->path = g_strconcat (graft->path, "/", NULL);
 			g_free (tmp);
 		}
-
+		graft->uri = brasero_data_project_node_to_uri (self, node);
 		grafts = g_slist_prepend (grafts, graft);
 	}
 
@@ -2642,8 +2643,10 @@ brasero_data_project_span (BraseroDataProject *self,
 	}
 
 	/* This means it's finished */
-	if (!callback_data.grafts)
+	if (!callback_data.grafts) {
+		BRASERO_BURN_LOG ("No graft found for spanning");
 		return BRASERO_BURN_OK;
+	}
 
 	brasero_data_project_span_generate (self,
 					    &callback_data,
@@ -2654,14 +2657,82 @@ brasero_data_project_span (BraseroDataProject *self,
 	brasero_track_data_add_fs (track, callback_data.fs_type);
 	brasero_track_data_set_file_num (track, callback_data.files_num);
 
+	BRASERO_BURN_LOG ("Set object (size %" G_GOFFSET_FORMAT ")", total_sectors);
+
 	g_slist_free (callback_data.grafts);
 	g_slist_free (callback_data.joliet_grafts);
 
 	return BRASERO_BURN_RETRY;
 }
 
+BraseroBurnResult
+brasero_data_project_span_possible (BraseroDataProject *self,
+				    goffset max_sectors)
+{
+	BraseroDataProjectPrivate *priv;
+	gboolean has_data_left = FALSE;
+	BraseroFileNode *children;
+
+	priv = BRASERO_DATA_PROJECT_PRIVATE (self);
+
+	/* When empty this is an error */
+	if (!g_hash_table_size (priv->grafts))
+		return BRASERO_BURN_ERR;
+
+	children = BRASERO_FILE_NODE_CHILDREN (priv->root);
+	while (children) {
+		goffset child_sectors;
+
+		if (g_slist_find (priv->spanned, children)) {
+			children = children->next;
+			continue;
+		}
+
+		if (children->is_file)
+			child_sectors = BRASERO_FILE_NODE_SECTORS (children);
+		else
+			child_sectors = brasero_data_project_get_folder_sectors (self, children);
+
+		/* Find at least one file or directory that can be spanned */
+		if (child_sectors < max_sectors)
+			return BRASERO_BURN_RETRY;
+
+		/* if the top directory is too large, continue */
+		children = children->next;
+		has_data_left = TRUE;
+	}
+
+	if (has_data_left)
+		return BRASERO_BURN_ERR;
+
+	return BRASERO_BURN_OK;
+}
+
+BraseroBurnResult
+brasero_data_project_span_again (BraseroDataProject *self)
+{
+	BraseroDataProjectPrivate *priv;
+	BraseroFileNode *children;
+
+	priv = BRASERO_DATA_PROJECT_PRIVATE (self);
+
+	/* When empty this is an error */
+	if (!g_hash_table_size (priv->grafts))
+		return BRASERO_BURN_ERR;
+
+	children = BRASERO_FILE_NODE_CHILDREN (priv->root);
+	while (children) {
+		if (!g_slist_find (priv->spanned, children))
+			return BRASERO_BURN_RETRY;
+
+		children = children->next;
+	}
+
+	return BRASERO_BURN_OK;
+}
+
 void
-brasero_data_project_span_cancel (BraseroDataProject *self)
+brasero_data_project_span_stop (BraseroDataProject *self)
 {
 	BraseroDataProjectPrivate *priv;
 
diff --git a/libbrasero-burn/brasero-data-project.h b/libbrasero-burn/brasero-data-project.h
index 4d81134..873d969 100644
--- a/libbrasero-burn/brasero-data-project.h
+++ b/libbrasero-burn/brasero-data-project.h
@@ -237,8 +237,14 @@ brasero_data_project_span (BraseroDataProject *project,
 			   gboolean append_slash,
 			   gboolean joliet,
 			   BraseroTrackData *track);
+BraseroBurnResult
+brasero_data_project_span_again (BraseroDataProject *project);
+
+BraseroBurnResult
+brasero_data_project_span_possible (BraseroDataProject *project,
+				    goffset max_sectors);
 void
-brasero_data_project_span_cancel (BraseroDataProject *project);
+brasero_data_project_span_stop (BraseroDataProject *project);
 
 G_END_DECLS
 
diff --git a/libbrasero-burn/brasero-session-span.c b/libbrasero-burn/brasero-session-span.c
new file mode 100644
index 0000000..02eeb29
--- /dev/null
+++ b/libbrasero-burn/brasero-session-span.c
@@ -0,0 +1,328 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Libbrasero-burn
+ * Copyright (C) Philippe Rouquier 2005-2009 <bonfire-app wanadoo fr>
+ *
+ * Libbrasero-burn is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The Libbrasero-burn authors hereby grant permission for non-GPL compatible
+ * GStreamer plugins to be used and distributed together with GStreamer
+ * and Libbrasero-burn. This permission is above and beyond the permissions granted
+ * by the GPL license by which Libbrasero-burn is covered. If you modify this code
+ * you may extend this exception to your version of the code, but you are not
+ * obligated to do so. If you do not wish to do so, delete this exception
+ * statement from your version.
+ * 
+ * Libbrasero-burn is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "brasero-drive.h"
+#include "brasero-medium.h"
+
+#include "burn-debug.h"
+#include "brasero-track.h"
+#include "brasero-track-data.h"
+#include "brasero-track-data-cfg.h"
+#include "brasero-session-span.h"
+
+typedef struct _BraseroSessionSpanPrivate BraseroSessionSpanPrivate;
+struct _BraseroSessionSpanPrivate
+{
+	GSList * track_list;
+	BraseroTrack * last_track;
+};
+
+#define BRASERO_SESSION_SPAN_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), BRASERO_TYPE_SESSION_SPAN, BraseroSessionSpanPrivate))
+
+G_DEFINE_TYPE (BraseroSessionSpan, brasero_session_span, BRASERO_TYPE_BURN_SESSION);
+
+static goffset
+brasero_session_span_get_available_medium_space (BraseroSessionSpan *session)
+{
+	BraseroDrive *burner;
+	BraseroMedium *medium;
+	BraseroBurnFlag flags;
+	goffset available_blocks = 0;
+
+	/* Retrieve the size available for burning */
+	burner = brasero_burn_session_get_burner (BRASERO_BURN_SESSION (session));
+	if (!burner)
+		return 0;
+
+	medium = brasero_drive_get_medium (burner);
+	if (!medium)
+		return 0;
+
+	flags = brasero_burn_session_get_flags (BRASERO_BURN_SESSION (session));
+	if (flags & (BRASERO_BURN_FLAG_MERGE|BRASERO_BURN_FLAG_APPEND))
+		brasero_medium_get_free_space (medium, NULL, &available_blocks);
+	else if (brasero_burn_session_can_blank (BRASERO_BURN_SESSION (session)) == BRASERO_BURN_OK)
+		brasero_medium_get_capacity (medium, NULL, &available_blocks);
+	else
+		brasero_medium_get_free_space (medium, NULL, &available_blocks);
+
+	BRASERO_BURN_LOG ("Available space for spanning %" G_GINT64_FORMAT, available_blocks);
+	return available_blocks;
+}
+
+BraseroBurnResult
+brasero_session_span_again (BraseroSessionSpan *session)
+{
+	GSList *tracks;
+	BraseroTrack *track;
+	BraseroSessionSpanPrivate *priv;
+
+	g_return_val_if_fail (BRASERO_IS_SESSION_SPAN (session), BRASERO_BURN_ERR);
+
+	priv = BRASERO_SESSION_SPAN_PRIVATE (session);
+	if (!priv->track_list)
+		return BRASERO_BURN_ERR;
+
+	if (priv->last_track) {
+		tracks = g_slist_find (priv->track_list, priv->last_track);
+		if (!tracks->next) {
+			priv->track_list = NULL;
+			return BRASERO_BURN_OK;
+		}
+
+		return BRASERO_BURN_RETRY;
+	}
+
+	tracks = priv->track_list;
+	track = tracks->data;
+
+	if (BRASERO_IS_TRACK_DATA_CFG (track))
+		return brasero_track_data_cfg_span_again (BRASERO_TRACK_DATA_CFG (track));
+
+	return (tracks != NULL)? BRASERO_BURN_RETRY:BRASERO_BURN_OK;
+}
+
+BraseroBurnResult
+brasero_session_span_possible (BraseroSessionSpan *session)
+{
+	GSList *tracks;
+	BraseroTrack *track;
+	goffset max_sectors = 0;
+	goffset track_blocks = 0;
+	BraseroSessionSpanPrivate *priv;
+
+	g_return_val_if_fail (BRASERO_IS_SESSION_SPAN (session), BRASERO_BURN_ERR);
+
+	priv = BRASERO_SESSION_SPAN_PRIVATE (session);
+
+	max_sectors = brasero_session_span_get_available_medium_space (session);
+	if (max_sectors <= 0)
+		return BRASERO_BURN_ERR;
+
+	if (!priv->track_list)
+		tracks = brasero_burn_session_get_tracks (BRASERO_BURN_SESSION (session));
+	else if (priv->last_track) {
+		tracks = g_slist_find (priv->track_list, priv->last_track);
+		if (!tracks->next) {
+			priv->track_list = NULL;
+			return BRASERO_BURN_OK;
+		}
+		tracks = tracks->next;
+	}
+	else
+		tracks = priv->track_list;
+
+	if (!tracks)
+		return BRASERO_BURN_ERR;
+
+	track = tracks->data;
+
+	if (BRASERO_IS_TRACK_DATA_CFG (track))
+		return brasero_track_data_cfg_span_possible (BRASERO_TRACK_DATA_CFG (track),
+							     max_sectors);
+
+	/* This is the common case */
+	brasero_track_get_size (BRASERO_TRACK (track),
+				&track_blocks,
+				NULL);
+
+	if (track_blocks >= max_sectors)
+		return BRASERO_BURN_ERR;
+
+	return BRASERO_BURN_RETRY;
+}
+
+BraseroBurnResult
+brasero_session_span_start (BraseroSessionSpan *session)
+{
+	BraseroSessionSpanPrivate *priv;
+
+	g_return_val_if_fail (BRASERO_IS_SESSION_SPAN (session), BRASERO_BURN_ERR);
+
+	priv = BRASERO_SESSION_SPAN_PRIVATE (session);
+
+	priv->track_list = brasero_burn_session_get_tracks (BRASERO_BURN_SESSION (session));
+	if (priv->last_track) {
+		g_object_unref (priv->last_track);
+		priv->last_track = NULL;
+	}
+
+	return BRASERO_BURN_OK;
+}
+
+BraseroBurnResult
+brasero_session_span_next (BraseroSessionSpan *session)
+{
+	GSList *tracks;
+	gboolean pushed = FALSE;
+	goffset max_sectors = 0;
+	goffset total_sectors = 0;
+	BraseroSessionSpanPrivate *priv;
+
+	g_return_val_if_fail (BRASERO_IS_SESSION_SPAN (session), BRASERO_BURN_ERR);
+
+	priv = BRASERO_SESSION_SPAN_PRIVATE (session);
+
+	g_return_val_if_fail (priv->track_list != NULL, BRASERO_BURN_ERR);
+
+	max_sectors = brasero_session_span_get_available_medium_space (session);
+	if (max_sectors <= 0)
+		return BRASERO_BURN_ERR;
+
+	/* NOTE: should we pop here? */
+	if (priv->last_track) {
+		tracks = g_slist_find (priv->track_list, priv->last_track);
+		g_object_unref (priv->last_track);
+		priv->last_track = NULL;
+
+		if (!tracks->next) {
+			priv->track_list = NULL;
+			return BRASERO_BURN_OK;
+		}
+		tracks = tracks->next;
+	}
+	else
+		tracks = priv->track_list;
+
+	for (; tracks; tracks = tracks->next) {
+		BraseroTrack *track;
+		goffset track_blocks = 0;
+
+		track = tracks->data;
+
+		if (BRASERO_IS_TRACK_DATA_CFG (track)) {
+			BraseroTrackData *new_track;
+			BraseroBurnResult result;
+
+			/* NOTE: the case where track_blocks < max_blocks will
+			 * be handled by brasero_track_data_cfg_span () */
+
+			/* This track type is the only one to be able to span itself */
+			new_track = brasero_track_data_new ();
+			result = brasero_track_data_cfg_span (BRASERO_TRACK_DATA_CFG (track),
+							      max_sectors,
+							      new_track);
+			if (result != BRASERO_BURN_RETRY) {
+				g_object_unref (new_track);
+				return result;
+			}
+
+			brasero_burn_session_push_tracks (BRASERO_BURN_SESSION (session));
+			brasero_burn_session_add_track (BRASERO_BURN_SESSION (session), BRASERO_TRACK (new_track));
+			break;
+		}
+
+		/* This is the common case */
+		brasero_track_get_size (BRASERO_TRACK (track),
+					&track_blocks,
+					NULL);
+
+		/* NOTE: keep the order of tracks */
+		if (track_blocks + total_sectors >= max_sectors) {
+			BRASERO_BURN_LOG ("Reached end of spanned size");
+			break;
+		}
+
+		total_sectors += track_blocks;
+
+		if (!pushed) {
+			BRASERO_BURN_LOG ("Pushing tracks for media spanning");
+			brasero_burn_session_push_tracks (BRASERO_BURN_SESSION (session));
+			pushed = TRUE;
+		}
+
+		BRASERO_BURN_LOG ("Adding tracks");
+		brasero_burn_session_add_track (BRASERO_BURN_SESSION (session), track);
+
+		if (priv->last_track)
+			g_object_unref (priv->last_track);
+
+		priv->last_track = g_object_ref (track);
+	}
+
+	/* If we pushed anything it means we succeeded */
+	return (pushed? BRASERO_BURN_RETRY:BRASERO_BURN_ERR);
+}
+
+void
+brasero_session_span_stop (BraseroSessionSpan *session)
+{
+	BraseroSessionSpanPrivate *priv;
+
+	g_return_if_fail (BRASERO_IS_SESSION_SPAN (session));
+
+	priv = BRASERO_SESSION_SPAN_PRIVATE (session);
+
+	if (priv->last_track) {
+		g_object_unref (priv->last_track);
+		priv->last_track = NULL;
+	}
+	else if (priv->track_list) {
+		BraseroTrack *track;
+
+		track = priv->track_list->data;
+		if (BRASERO_IS_TRACK_DATA_CFG (track))
+			brasero_track_data_cfg_span_stop (BRASERO_TRACK_DATA_CFG (track));
+	}
+
+	priv->track_list = NULL;
+}
+
+static void
+brasero_session_span_init (BraseroSessionSpan *object)
+{ }
+
+static void
+brasero_session_span_finalize (GObject *object)
+{
+	brasero_session_span_stop (BRASERO_SESSION_SPAN (object));
+	G_OBJECT_CLASS (brasero_session_span_parent_class)->finalize (object);
+}
+
+static void
+brasero_session_span_class_init (BraseroSessionSpanClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (BraseroSessionSpanPrivate));
+
+	object_class->finalize = brasero_session_span_finalize;
+}
+
+BraseroSessionSpan *
+brasero_session_span_new (void)
+{
+	return g_object_new (BRASERO_TYPE_SESSION_SPAN, NULL);
+}
+
diff --git a/libbrasero-burn/brasero-session-span.h b/libbrasero-burn/brasero-session-span.h
new file mode 100644
index 0000000..db34ea8
--- /dev/null
+++ b/libbrasero-burn/brasero-session-span.h
@@ -0,0 +1,82 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Libbrasero-burn
+ * Copyright (C) Philippe Rouquier 2005-2009 <bonfire-app wanadoo fr>
+ *
+ * Libbrasero-burn is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The Libbrasero-burn authors hereby grant permission for non-GPL compatible
+ * GStreamer plugins to be used and distributed together with GStreamer
+ * and Libbrasero-burn. This permission is above and beyond the permissions granted
+ * by the GPL license by which Libbrasero-burn is covered. If you modify this code
+ * you may extend this exception to your version of the code, but you are not
+ * obligated to do so. If you do not wish to do so, delete this exception
+ * statement from your version.
+ * 
+ * Libbrasero-burn is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _BRASERO_SESSION_SPAN_H_
+#define _BRASERO_SESSION_SPAN_H_
+
+#include <glib-object.h>
+
+#include <brasero-session.h>
+
+G_BEGIN_DECLS
+
+#define BRASERO_TYPE_SESSION_SPAN             (brasero_session_span_get_type ())
+#define BRASERO_SESSION_SPAN(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), BRASERO_TYPE_SESSION_SPAN, BraseroSessionSpan))
+#define BRASERO_SESSION_SPAN_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), BRASERO_TYPE_SESSION_SPAN, BraseroSessionSpanClass))
+#define BRASERO_IS_SESSION_SPAN(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BRASERO_TYPE_SESSION_SPAN))
+#define BRASERO_IS_SESSION_SPAN_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), BRASERO_TYPE_SESSION_SPAN))
+#define BRASERO_SESSION_SPAN_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), BRASERO_TYPE_SESSION_SPAN, BraseroSessionSpanClass))
+
+typedef struct _BraseroSessionSpanClass BraseroSessionSpanClass;
+typedef struct _BraseroSessionSpan BraseroSessionSpan;
+
+struct _BraseroSessionSpanClass
+{
+	BraseroBurnSessionClass parent_class;
+};
+
+struct _BraseroSessionSpan
+{
+	BraseroBurnSession parent_instance;
+};
+
+GType brasero_session_span_get_type (void) G_GNUC_CONST;
+
+BraseroSessionSpan *
+brasero_session_span_new (void);
+
+BraseroBurnResult
+brasero_session_span_again (BraseroSessionSpan *session);
+
+BraseroBurnResult
+brasero_session_span_possible (BraseroSessionSpan *session);
+
+BraseroBurnResult
+brasero_session_span_start (BraseroSessionSpan *session);
+
+BraseroBurnResult
+brasero_session_span_next (BraseroSessionSpan *session);
+
+void
+brasero_session_span_stop (BraseroSessionSpan *session);
+
+G_END_DECLS
+
+#endif /* _BRASERO_SESSION_SPAN_H_ */
diff --git a/libbrasero-burn/brasero-session.c b/libbrasero-burn/brasero-session.c
index a15c8b1..8958ee6 100644
--- a/libbrasero-burn/brasero-session.c
+++ b/libbrasero-burn/brasero-session.c
@@ -261,16 +261,18 @@ brasero_burn_session_add_track (BraseroBurnSession *self,
 
 		priv->tracks = g_slist_prepend (NULL, new_track);
 		brasero_burn_session_start_track_monitoring (self, new_track);
-
-		g_signal_emit (self,
-			       brasero_burn_session_signals [INPUT_CHANGED_SIGNAL],
-			       0);
 	}
 	else {
 		brasero_burn_session_start_track_monitoring (self, new_track);
 		priv->tracks = g_slist_append (priv->tracks, new_track);
 	}
 
+	/* Always emit the signal even when adding another BraseroTrackStream
+	 * since the size has probably changed. */
+	g_signal_emit (self,
+		       brasero_burn_session_signals [INPUT_CHANGED_SIGNAL],
+		       0);
+
 	return BRASERO_BURN_OK;
 }
 
diff --git a/libbrasero-burn/brasero-track-data-cfg.c b/libbrasero-burn/brasero-track-data-cfg.c
index 7eeae09..979e712 100644
--- a/libbrasero-burn/brasero-track-data-cfg.c
+++ b/libbrasero-burn/brasero-track-data-cfg.c
@@ -2327,6 +2327,40 @@ brasero_track_data_cfg_span (BraseroTrackDataCfg *track,
 	return BRASERO_BURN_RETRY;
 }
 
+BraseroBurnResult
+brasero_track_data_cfg_span_again (BraseroTrackDataCfg *track)
+{
+	BraseroTrackDataCfgPrivate *priv;
+
+	priv = BRASERO_TRACK_DATA_CFG_PRIVATE (track);
+	return brasero_data_project_span_again (BRASERO_DATA_PROJECT (priv->tree));
+}
+
+BraseroBurnResult
+brasero_track_data_cfg_span_possible (BraseroTrackDataCfg *track,
+				      goffset sectors)
+{
+	BraseroTrackDataCfgPrivate *priv;
+
+	priv = BRASERO_TRACK_DATA_CFG_PRIVATE (track);
+	if (priv->loading
+	||  brasero_data_vfs_is_active (BRASERO_DATA_VFS (priv->tree))
+	||  brasero_data_session_get_loaded_medium (BRASERO_DATA_SESSION (priv->tree)) != NULL)
+		return BRASERO_BURN_NOT_READY;
+
+	return brasero_data_project_span_possible (BRASERO_DATA_PROJECT (priv->tree),
+						   sectors);
+}
+
+void
+brasero_track_data_cfg_span_stop (BraseroTrackDataCfg *track)
+{
+	BraseroTrackDataCfgPrivate *priv;
+
+	priv = BRASERO_TRACK_DATA_CFG_PRIVATE (track);
+	brasero_data_project_span_stop (BRASERO_DATA_PROJECT (priv->tree));
+}
+
 static void
 brasero_track_data_cfg_init (BraseroTrackDataCfg *object)
 {
diff --git a/libbrasero-burn/brasero-track-data-cfg.h b/libbrasero-burn/brasero-track-data-cfg.h
index fc74ecb..018116e 100644
--- a/libbrasero-burn/brasero-track-data-cfg.h
+++ b/libbrasero-burn/brasero-track-data-cfg.h
@@ -156,6 +156,15 @@ BraseroBurnResult
 brasero_track_data_cfg_span (BraseroTrackDataCfg *track,
 			     goffset sectors,
 			     BraseroTrackData *new_track);
+BraseroBurnResult
+brasero_track_data_cfg_span_again (BraseroTrackDataCfg *track);
+
+BraseroBurnResult
+brasero_track_data_cfg_span_possible (BraseroTrackDataCfg *track,
+				      goffset sectors);
+
+void
+brasero_track_data_cfg_span_stop (BraseroTrackDataCfg *track);
 
 G_END_DECLS
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]