Logo Search packages:      
Sourcecode: nautilus-cd-burner version File versions  Download package

nautilus-cd-burner.c

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
 * 
 * nautilus-cd-burner.c: easy to use cd burner software
 * 
 * Copyright (C) 2002-2004 Red Hat, Inc.
 * Copyright (C) 2005-2006 William Jon McCann <mccann@jhu.edu>
 *   
 * This program 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.
 *   
 * This program 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
 * 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., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *   
 * Authors: Alexander Larsson <alexl@redhat.com>
 *          Bastien Nocera <hadess@hadess.net>
 *          William Jon McCann <mccann@jhu.edu>
 */

#include "config.h"

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <glib.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include <glade/glade.h>
#include <libgnomevfs/gnome-vfs.h>

#include <libgnome/gnome-help.h>
#include <libgnomeui/gnome-ui-init.h>
#include <gconf/gconf-client.h>

#include "nautilus-burn-drive-selection.h"
#include "nautilus-cd-burner.h"
#include "make-iso.h"

#define MAX_ISO_NAME_LEN  32
#define RESPONSE_OVERBURN 1
#define SUGGEST_OVERBURN  5 * 1024 * 1024

#define BURN_URI "burn:///"

enum {
      CANCEL_NONE,
      CANCEL_MAKE_ISO,
      CANCEL_CD_RECORD,
};

enum {
      NCB_SOURCE_BURN = 0,
      NCB_SOURCE_IMAGE = 1,
      NCB_SOURCE_DRIVE = 2,
};

enum {
      NCB_OUTPUT_DEFAULT = 0,
      NCB_OUTPUT_FILE = 1,
      NCB_OUTPUT_CD = 2,
      NCB_OUTPUT_DVD = 3,
};

typedef struct {
      char              *source_device;
      char              *source_iso;
      char              *source_cue;
      NautilusBurnDrive *source_drive;
      gint64             size;
      guint              ref_count;
} NautilusBurnerSourceData;

typedef struct {
      NautilusBurnDrive             *drive;
      NautilusBurnRecorderWriteFlags flags;
      GList                         *tracks;
      int                            speed;
      gint64                         size;
} NautilusBurnerWriteData;

static GladeXML *xml;

static NautilusBurnRecorder    *recorder = NULL;
static int                      cancel   = CANCEL_NONE;
/* For the image spinning */
static GList                   *image_list;
static GList                   *files_for_cleanup = NULL;
static NautilusBurnerWriteData *write_data = NULL;

static int write_disc (NautilusBurnerWriteData *data);

/* Profiling stuff adapted from gtkfilechooserdefault */
/* To use run:
 *  strace -ttt -f -o logfile.txt nautilus-cd-burner
 */

#undef PROFILE_NCB
#ifdef PROFILE_NCB

#define PROFILE_INDENT 4
static int profile_indent;

static void
profile_add_indent (int indent)
{
      profile_indent += indent;
      if (profile_indent < 0) {
            g_error ("You screwed up your indentation");
      }
}

static void
_ncb_profile_log (const char *func,
              int         indent,
              const char *msg1,
              const char *msg2)
{
      char *str;

      if (indent < 0) {
            profile_add_indent (indent);
      }

      if (profile_indent == 0) {
            str = g_strdup_printf ("MARK: %s: %s %s %s", G_STRLOC, func, msg1 ? msg1 : "", msg2 ? msg2 : "");
      } else {
            str = g_strdup_printf ("MARK: %s: %*c %s %s %s", G_STRLOC, profile_indent - 1, ' ', func, msg1 ? msg1 : "", msg2 ? msg2 : "");
      }

      access (str, F_OK);

      g_free (str);

      if (indent > 0) {
            profile_add_indent (indent);
      }
}

#define profile_start(x, y) _ncb_profile_log (G_STRFUNC, PROFILE_INDENT, x, y)
#define profile_end(x, y)   _ncb_profile_log (G_STRFUNC, -PROFILE_INDENT, x, y)
#define profile_msg(x, y)   _ncb_profile_log (NULL, 0, x, y)
#else
#define profile_start(x, y)
#define profile_end(x, y)
#define profile_msg(x, y)
#endif

static void
nautilus_burn_progress_write_data_free (NautilusBurnerWriteData *data)
{
      if (! data) {
            return;
      }

      nautilus_burn_drive_unref (data->drive);

      g_list_foreach (data->tracks, (GFunc)nautilus_burn_recorder_track_free, NULL);
      g_list_free (data->tracks);

      g_free (data);
}

static GtkWidget *
ncb_hig_dialog (GtkMessageType type,
            char          *title,
            char          *reason,
            GtkWindow     *parent)
{
      GtkWidget *error_dialog;

      if (reason == NULL) {
            g_warning ("ncb_hig_dialog called with reason == NULL");
      }

      error_dialog =
            gtk_message_dialog_new (parent,
                              GTK_DIALOG_DESTROY_WITH_PARENT,
                              type,
                              GTK_BUTTONS_NONE,
                              title);
      gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (error_dialog), reason);
      gtk_window_set_title (GTK_WINDOW (error_dialog), "");
      gtk_window_set_icon_name (GTK_WINDOW (error_dialog), "gnome-dev-cdrom");

      gtk_container_set_border_width (GTK_CONTAINER (error_dialog), 5);

      return error_dialog;
}

static void
ncb_hig_show_error_dialog (char      *title,
                     char      *reason,
                     GtkWindow *parent)
{
      GtkWidget *dialog;

      dialog = ncb_hig_dialog (GTK_MESSAGE_ERROR, title, reason, parent);
      gtk_dialog_add_button (GTK_DIALOG (dialog),
                         GTK_STOCK_OK, GTK_RESPONSE_OK);
      gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
      gtk_dialog_run (GTK_DIALOG (dialog));
      gtk_widget_destroy (dialog);
}

GtkWindow *
nautilus_burn_progress_get_window (void)
{
      return GTK_WINDOW (glade_xml_get_widget (xml, "progress_window"));
}

void 
nautilus_burn_progress_set_fraction (double fraction)
{
      GtkWidget *progress_bar;
      
      progress_bar = glade_xml_get_widget (xml, "cd_progress");

      gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress_bar), fraction);
}

/* Adapted from totem_time_to_string_text */
static char *
time_to_string_text (long time)
{
      char *secs, *mins, *hours, *string;
      int sec, min, hour;

      sec = time % 60;
      time = time - sec;
      min = (time % (60 * 60)) / 60;
      time = time - (min * 60);
      hour = time / (60 * 60);

      hours = g_strdup_printf (ngettext ("%d hour", "%d hours", hour), hour);

      mins = g_strdup_printf (ngettext ("%d minute",
                                "%d minutes", min), min);

      secs = g_strdup_printf (ngettext ("%d second",
                                "%d seconds", sec), sec);

      if (hour > 0) {
            /* hour:minutes:seconds */
            string = g_strdup_printf (_("%s %s %s"), hours, mins, secs);
      } else if (min > 0) {
            /* minutes:seconds */
            string = g_strdup_printf (_("%s %s"), mins, secs);
      } else if (sec > 0) {
            /* seconds */
            string = g_strdup_printf (_("%s"), secs);
      } else {
            /* 0 seconds */
            string = g_strdup (_("0 seconds"));
      }

      g_free (hours);
      g_free (mins);
      g_free (secs);

      return string;
}

void 
nautilus_burn_progress_set_time (long secs)
{
      GtkWidget *progress_bar;
      char      *text;

      progress_bar = glade_xml_get_widget (xml, "cd_progress");

      if (secs >= 0) {
            char *remaining;
            remaining = time_to_string_text (secs);
            text = g_strdup_printf (_("About %s left"), remaining);
            g_free (remaining);
      } else {
            text = g_strdup (" ");
      }

      gtk_progress_bar_set_text (GTK_PROGRESS_BAR (progress_bar), text);

      g_free (text);
}

void 
nautilus_burn_progress_set_text (const char *text)
{
      GtkWidget *progress_label;
      char      *string;

      progress_label = glade_xml_get_widget (xml, "cd_progress_label");
      string = g_strdup_printf ("<i>%s</i>", text);
      gtk_label_set_markup (GTK_LABEL (progress_label), string);
      g_free (string);
}

static gboolean
nautilus_burn_progress_set_image (gpointer user_data)
{
      GtkWidget *image;
      GdkPixbuf *pixbuf;

      if (image_list == NULL) {
            return FALSE;
      }

      image = glade_xml_get_widget (xml, "cd_image");
      pixbuf = image_list->data;

      if (pixbuf == NULL || image == NULL) {
            return FALSE;
      }

      gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);

      if (image_list->next != NULL) {
            image_list = image_list->next;
      } else {
            image_list = g_list_first (image_list);
      }

      return TRUE;
}

void
nautilus_burn_progress_set_image_spinning (gboolean spinning)
{
      static guint spin_id = 0;

      if (spinning) {
            if (spin_id == 0) {
                  spin_id = g_timeout_add (100, (GSourceFunc) nautilus_burn_progress_set_image, NULL);
            }
      } else {
            if (spin_id != 0) {
                  g_source_remove (spin_id);
                  spin_id = 0;
            }
      }
}

static void
nautilus_burn_progress_image_setup (void)
{
      GdkPixbuf *pixbuf;
      char      *filename;
      int        i;

      image_list = NULL;
      i = 1;

      /* Setup the pixbuf list */
      filename = g_strdup_printf (DATADIR "/cdspin%d.png", i);
      while (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
            pixbuf = gdk_pixbuf_new_from_file (filename, NULL);

            if (pixbuf != NULL) {
                  image_list = g_list_prepend (image_list, (gpointer) pixbuf);
            }

            i++;
            g_free (filename);
            filename = g_strdup_printf (DATADIR "/cdspin%d.png", i);
      }

      g_free (filename);
      if (image_list != NULL) {
            image_list = g_list_reverse (image_list);
      }

      /* Set the first image */
      nautilus_burn_progress_set_image (NULL);
}

static void
nautilus_burn_progress_image_cleanup (void)
{
      GdkPixbuf *pixbuf;

      image_list = g_list_first (image_list);

      while (image_list != NULL) {
            pixbuf = (GdkPixbuf *) image_list->data;
            if (pixbuf != NULL) {
                  gdk_pixbuf_unref (pixbuf);
            }
            image_list = g_list_remove (image_list, image_list->data);
      }
}

static void
nautilus_burn_progress_temp_files_add (const char *filename)
{
      files_for_cleanup = g_list_append (files_for_cleanup, g_strdup (filename));
}

static void
nautilus_burn_progress_temp_files_cleanup (void)
{
      files_for_cleanup = g_list_first (files_for_cleanup);

      while (files_for_cleanup != NULL) {
            char *filename = files_for_cleanup->data;

            if (filename) {
                  g_unlink (filename);
            }

            g_free (filename);

            files_for_cleanup = g_list_remove (files_for_cleanup, files_for_cleanup->data);
      }
}

static void
nautilus_burn_progress_set_write_data (NautilusBurnerWriteData *data)
{
      /* just set a global for now */
      write_data = data;
}

static NautilusBurnerWriteData *
nautilus_burn_progress_get_write_data (void)
{
      return write_data;
}

static void
nautilus_burn_progress_cleanup (void)
{
      NautilusBurnerWriteData *data;

      nautilus_burn_progress_image_cleanup ();
      nautilus_burn_progress_temp_files_cleanup ();

      data = nautilus_burn_progress_get_write_data ();
      if (data) {
            nautilus_burn_progress_write_data_free (data);
      }
}

static int
nautilus_burn_progress_write_disc (void)
{
      NautilusBurnerWriteData *data;
      int                      res;

      data = nautilus_burn_progress_get_write_data ();

      res = write_disc (data);

      return res;
}

static void
animation_changed_cb (NautilusBurnRecorder *recorder,
                  gboolean              spinning,
                  gpointer              data)
{
      nautilus_burn_progress_set_image_spinning (spinning);
}

static void
action_changed_cb (NautilusBurnRecorder       *recorder,
               NautilusBurnRecorderActions action,
               NautilusBurnRecorderMedia   media)
{
      const char *text;

      text = NULL;

      switch (action) {

      case NAUTILUS_BURN_RECORDER_ACTION_PREPARING_WRITE:
            if (media == NAUTILUS_BURN_RECORDER_MEDIA_CD) {
                  text = _("Preparing to write CD");
            } else {
                  text = _("Preparing to write DVD");
            }
            break;
      case NAUTILUS_BURN_RECORDER_ACTION_WRITING:
            if (media == NAUTILUS_BURN_RECORDER_MEDIA_CD) {
                  text = _("Writing CD");
            } else {
                  text = _("Writing DVD");
            }
            break;
      case NAUTILUS_BURN_RECORDER_ACTION_FIXATING:
            if (media == NAUTILUS_BURN_RECORDER_MEDIA_CD) {
                  text = _("Finishing write");
            } else {
                  text = _("Finishing write");
            }
            break;
      case NAUTILUS_BURN_RECORDER_ACTION_BLANKING:
            if (media == NAUTILUS_BURN_RECORDER_MEDIA_CD) {
                  text = _("Erasing CD");
            } else {
                  text = _("Erasing DVD");
            }
            break;
      default:
            g_warning ("Unhandled action in action_changed_cb");
      }

      nautilus_burn_progress_set_time (-1);
      nautilus_burn_progress_set_text (text);
}

static void
progress_changed_cb (NautilusBurnRecorder *recorder,
                 gdouble               fraction,
                 long                  secs,
                 gpointer              data)
{
      nautilus_burn_progress_set_fraction (fraction);
      nautilus_burn_progress_set_time (secs);
}

static int  
ask_for_media (NautilusBurnDrive *drive,
             gboolean           is_reload,
             gboolean           busy_cd,
             gboolean           ask_overburn,
             gint64             required_size)
{
      GtkWidget  *dialog;
      GtkWidget  *parent;
      GtkWidget  *button;
      gboolean    can_rewrite;
      gboolean    show_eject;
      char       *msg;
      char       *type_string;
      const char *title;
      int         res;
      int         mibs;

      mibs = (required_size + 1024 * 1024 - 1) / (1024 * 1024);

      type_string = nautilus_burn_drive_get_supported_media_string (drive, TRUE);

      can_rewrite = nautilus_burn_drive_can_rewrite (drive);
      show_eject = FALSE;

      if (busy_cd) {
            msg = g_strdup (_("Please make sure another application is not using the drive."));
            title = N_("Drive is busy");
      } else if (!is_reload && can_rewrite) {
            msg = g_strdup_printf (_("Please put a disc, with at least %d MiB free, into the drive.  The following disc types are supported:\n%s"),
                               mibs,
                               type_string);
            title = N_("Insert a rewritable or blank disc");
      } else if (!is_reload && !can_rewrite) {
            msg = g_strdup_printf (_("Please put a disc, with at least %d MiB free, into the drive.  The following disc types are supported:\n%s"),
                               mibs,
                               type_string);
            title = N_("Insert a blank disc");
      } else if (can_rewrite) {
            show_eject = TRUE;
            msg = g_strdup_printf (_("Please replace the disc in the drive with a supported disc with at least %d MiB free.  The following disc types are supported:\n%s"),
                               mibs,
                               type_string);
            title = N_("Reload a rewritable or blank disc");
      } else {
            show_eject = TRUE;
            msg = g_strdup_printf (_("Please replace the disc in the drive with a supported disc with at least %d MiB free.  The following disc types are supported:\n%s"),
                               mibs,
                               type_string);
            title = N_("Reload a blank disc");
      }

      g_free (type_string);

      parent = (GtkWidget *)nautilus_burn_progress_get_window ();
      if (! parent) {
            parent = glade_xml_get_widget (xml, "cdr_dialog");
      }

      dialog = ncb_hig_dialog (GTK_MESSAGE_INFO,
                         _(title), _(msg), GTK_WINDOW (parent));

      if (show_eject) {
            button = gtk_dialog_add_button (GTK_DIALOG (dialog),
                                    _("_Eject"),
                                    GTK_RESPONSE_NO);
      }

      gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
      gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_OK, GTK_RESPONSE_OK);

      gtk_dialog_set_default_response (GTK_DIALOG (dialog),
                               GTK_RESPONSE_OK);

 retry:
      res = gtk_dialog_run (GTK_DIALOG (dialog));

      if (res == GTK_RESPONSE_NO) {
            nautilus_burn_drive_eject (drive);
            goto retry;
      }

      gtk_widget_destroy (dialog);

      g_free (msg);

      return res;
}

typedef struct
{
      gint64             size;
      NautilusBurnDrive *drive;
} InsertMediaCallbackData;

static gboolean
insert_media_request_cb (NautilusBurnRecorder *recorder,
                   gboolean              is_reload,
                   gboolean              can_rewrite,
                   gboolean              busy_cd,
                   gpointer              data)
{
      InsertMediaCallbackData *info = data;
      int                      res;

      res = ask_for_media (info->drive,
                       is_reload,
                       busy_cd,
                       FALSE,
                       info->size);

      if (res == GTK_RESPONSE_CANCEL) {
            return FALSE;
      }
 
      return TRUE;
}

static int
ask_rewrite_disc (NautilusBurnDrive *drive)
{
      GtkWidget            *dialog;
      GtkWidget            *button;
      GtkWidget            *image;
      int                   res;
      NautilusBurnMediaType type;
      char                 *msg;

      type = nautilus_burn_drive_get_media_type (drive);

      msg = g_strdup_printf (_("This %s appears to have information already recorded on it."),
                         nautilus_burn_drive_media_type_get_string (type));

      dialog = ncb_hig_dialog (GTK_MESSAGE_WARNING,
                         _("Erase information on this disc?"),
                         msg, 
                         nautilus_burn_progress_get_window ());
      g_free (msg);

      image = gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_BUTTON);
      gtk_widget_show (image);
      button = gtk_dialog_add_button (GTK_DIALOG (dialog),
                              _("_Try Another"),
                              NAUTILUS_BURN_RECORDER_RESPONSE_RETRY);
      g_object_set (button, "image", image, NULL);

      gtk_dialog_add_button (GTK_DIALOG (dialog),
                         GTK_STOCK_CANCEL,
                         NAUTILUS_BURN_RECORDER_RESPONSE_CANCEL);

      image = gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_BUTTON);
      gtk_widget_show (image);
      button = gtk_dialog_add_button (GTK_DIALOG (dialog),
                              _("_Erase Disc"),
                              NAUTILUS_BURN_RECORDER_RESPONSE_ERASE);
      g_object_set (button, "image", image, NULL);

      gtk_dialog_set_default_response (GTK_DIALOG (dialog),
                               NAUTILUS_BURN_RECORDER_RESPONSE_CANCEL);

      res = gtk_dialog_run (GTK_DIALOG (dialog));
      gtk_widget_destroy (dialog);

      if (res == NAUTILUS_BURN_RECORDER_RESPONSE_RETRY) {
            nautilus_burn_drive_eject (drive);
      }

      return res;
}

static int
warn_data_loss_cb (NautilusBurnRecorder *recorder,
               NautilusBurnDrive    *drive)
{
      return ask_rewrite_disc (drive);
}

static void
show_error_message (NautilusBurnRecorder *recorder,
                GError               *error)
{
      GtkWidget *dialog;
      char      *msg;

      if (error) {
            msg = g_strdup_printf (_("There was an error writing to the disc:\n%s"),
                               error->message);
      } else {
            msg = g_strdup (_("There was an error writing to the disc"));
      }

      dialog = ncb_hig_dialog (GTK_MESSAGE_ERROR, _("Error writing to disc"),
                         msg, nautilus_burn_progress_get_window ());
      g_free (msg);
      gtk_dialog_add_button (GTK_DIALOG (dialog),
                         GTK_STOCK_OK, GTK_RESPONSE_OK);

      gtk_dialog_run (GTK_DIALOG (dialog));
      gtk_widget_destroy (dialog);
}

typedef struct
{
      GList           *unreadable_paths;
      GList           *image_paths;
      gboolean         only_images;
      GnomeVFSFileSize size;
} EstimateSizeCallbackData;

/* FIXME: This should probably be an inline */
static gboolean
file_info_is_image (GnomeVFSFileInfo *info)
{
      gboolean is_image;

      g_return_val_if_fail (info != NULL, FALSE);

      if (!info->mime_type) {
            return FALSE;
      }

      is_image = (strcmp (info->mime_type, "application/x-cd-image") == 0);

      return is_image;
}

/* FIXME: This should probably be an inline */
static gboolean
file_info_is_allowed (GnomeVFSFileInfo *info)
{
      g_return_val_if_fail (info != NULL, FALSE);

      /* only allow regular,directory,symlink files */
      if (info->type != GNOME_VFS_FILE_TYPE_REGULAR
          && info->type != GNOME_VFS_FILE_TYPE_DIRECTORY
          && info->type != GNOME_VFS_FILE_TYPE_SYMBOLIC_LINK) {
            return FALSE;
      } else if (info->type == GNOME_VFS_FILE_TYPE_REGULAR
               && !(info->permissions & GNOME_VFS_PERM_ACCESS_READABLE)) {
            return FALSE;
      }

      return TRUE;
}

static char *
get_backing_file (const char *virtual_path)
{
      GnomeVFSHandle *handle;
      GnomeVFSResult  res;
      char           *escaped_path, *uri;
      char           *mapping;

      escaped_path = gnome_vfs_escape_path_string (virtual_path);
      uri = g_strconcat ("burn:///", escaped_path, NULL);
      g_free (escaped_path);
      /* warning, this can hang on fifos etc */
      res = gnome_vfs_open (&handle,
                        uri,
                        GNOME_VFS_OPEN_READ);
      g_free (uri);
      if (res == GNOME_VFS_OK) {
            res =  gnome_vfs_file_control (handle,
                                     "mapping:get_mapping",
                                     &mapping);
            gnome_vfs_close   (handle);
            if (res == GNOME_VFS_OK) {
                  return mapping;
            }
      }
      return NULL;
}

static gboolean
estimate_size_callback (const char       *rel_path,
                  GnomeVFSFileInfo *info,
                  gboolean          recursing_will_loop,
                  gpointer          data,
                  gboolean         *recurse)
{
      EstimateSizeCallbackData *cb_data = data;

      if (file_info_is_image (info)) {
            cb_data->image_paths = g_list_append (cb_data->image_paths, get_backing_file (rel_path));
      } else {
            cb_data->only_images = FALSE;
      }

      if (file_info_is_allowed (info)) {
            if (info->type != GNOME_VFS_FILE_TYPE_DIRECTORY) {
                  cb_data->size += info->size;
            }
      } else {
            cb_data->unreadable_paths = g_list_append (cb_data->unreadable_paths, g_strdup (rel_path));
      }

      *recurse = TRUE;

      return TRUE;
}

static GnomeVFSFileSize
estimate_size (const char *uri,
             GList     **unreadable_paths,
             GList     **image_paths,
             gboolean   *only_images)
{
      GnomeVFSFileSize          size;
      EstimateSizeCallbackData *data;

      profile_start ("start", NULL);

      data = g_new0 (EstimateSizeCallbackData, 1);
      data->only_images = TRUE;

      gnome_vfs_directory_visit (uri,
                           GNOME_VFS_FILE_INFO_DEFAULT
                           | GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS
                           | GNOME_VFS_FILE_INFO_GET_MIME_TYPE
                           | GNOME_VFS_FILE_INFO_FORCE_FAST_MIME_TYPE,
                           GNOME_VFS_DIRECTORY_VISIT_DEFAULT,
                           (GnomeVFSDirectoryVisitFunc) estimate_size_callback,
                           data);

      if (data->size == 0) {
            GList *list;

            if (gnome_vfs_directory_list_load (&list, uri, GNOME_VFS_FILE_INFO_FIELDS_NONE) == GNOME_VFS_OK) {
                  if (list != NULL) {
                        data->size = 1;
                        gnome_vfs_file_info_list_free (list);
                  }
            }
      }

      if (data->unreadable_paths) {
            if (unreadable_paths) {
                  GList *l;
                  *unreadable_paths = NULL;
                  for (l = data->unreadable_paths; l; l = l->next) {
                        *unreadable_paths = g_list_append (*unreadable_paths, g_strdup ((char *)l->data));
                  }
            }

            g_list_foreach (data->unreadable_paths, (GFunc)g_free, NULL);
            g_list_free (data->unreadable_paths);
      }

      if (data->image_paths) {
            if (image_paths) {
                  GList *l;
                  *image_paths = NULL;
                  for (l = data->image_paths; l; l = l->next) {
                        *image_paths = g_list_append (*image_paths, g_strdup ((char *)l->data));
                  }
            }

            g_list_foreach (data->image_paths, (GFunc)g_free, NULL);
            g_list_free (data->image_paths);
      }

      size = data->size;
      *only_images = data->only_images;

      g_free (data);

      profile_end ("end", NULL);

      return size;
}

static void
setup_cancel_button (void)
{
      GtkWidget *close_button;
      GtkWidget *cancel_button;
      GtkWidget *write_another_button;

      cancel_button = glade_xml_get_widget (xml, "cancel_button");
      close_button = glade_xml_get_widget (xml, "close_button");
      write_another_button = glade_xml_get_widget (xml, "write_another_button");

      gtk_widget_show (cancel_button);
      gtk_widget_hide (close_button);
      gtk_widget_hide (write_another_button);

      /* FIXME: disconnect signal handlers? */
}

static void
eject_disc_cb (GtkWidget *widget,
             gpointer   user_data)
             
{
      NautilusBurnerWriteData *data;

      data = nautilus_burn_progress_get_write_data ();
      if (data != NULL && data->drive != NULL) {
            nautilus_burn_drive_eject ((NautilusBurnDrive *)data->drive);
      }
}

static void
write_another_disc_cb (GtkWidget *widget,
                   gpointer   user_data)
{
      int                      res;
      NautilusBurnerWriteData *data;

      setup_cancel_button ();

      data = nautilus_burn_progress_get_write_data ();
      if (data != NULL && data->drive != NULL) {
            nautilus_burn_drive_eject ((NautilusBurnDrive *)data->drive);
      }

      res = nautilus_burn_progress_write_disc ();

      if (res == NAUTILUS_BURN_RECORDER_RESULT_CANCEL) {
            gtk_main_quit ();
      }
}

static void
setup_close_button (void)
{
      GtkWidget               *close_button;
      GtkWidget               *cancel_button;
      NautilusBurnerWriteData *data;

      cancel_button = glade_xml_get_widget (xml, "cancel_button");
      close_button = glade_xml_get_widget (xml, "close_button");

      gtk_widget_hide (cancel_button);
      gtk_widget_show (close_button);
      gtk_widget_grab_focus (close_button);

      g_signal_handlers_disconnect_by_func (close_button, gtk_main_quit, NULL);
      g_signal_connect (close_button, "clicked", G_CALLBACK (gtk_main_quit), NULL);

      data = nautilus_burn_progress_get_write_data ();
      if (data != NULL) {
            GtkWidget *write_another_button;
            write_another_button = glade_xml_get_widget (xml, "write_another_button");
            gtk_widget_show (write_another_button);

            g_signal_handlers_disconnect_by_func (write_another_button, write_another_disc_cb, NULL);
            g_signal_connect (write_another_button, "clicked", G_CALLBACK (write_another_disc_cb), NULL);
      }

      if (data != NULL) {
            GtkWidget *button;
            button = glade_xml_get_widget (xml, "eject_button");
            gtk_widget_show (button);

            g_signal_handlers_disconnect_by_func (button, eject_disc_cb, NULL);
            g_signal_connect (button, "clicked", G_CALLBACK (eject_disc_cb), NULL);
      }
}

static gboolean 
overwrite_existing_file (GtkWindow  *filesel,
                   const char *filename)
{
      GtkWidget *dialog;
      int        ret;
      char      *msg;

      msg = g_strdup_printf (_("A file named \"%s\" already exists.  Do you want to overwrite it?"),
                         filename);
      dialog = ncb_hig_dialog (GTK_MESSAGE_QUESTION, _("Overwrite existing file?"),
                         msg, filesel);

      /* Add Cancel button */
      gtk_dialog_add_button (GTK_DIALOG (dialog),
                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);

      /* Add Overwrite button */
      gtk_dialog_add_button (GTK_DIALOG (dialog),
                         _("_Overwrite"), GTK_RESPONSE_YES);

      gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
      gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);

      ret = gtk_dialog_run (GTK_DIALOG (dialog));

      gtk_widget_destroy (dialog);

      return (ret == GTK_RESPONSE_YES);
}

static char *
select_iso_filename (const char *default_name)
{
      GtkWidget *chooser;
      char      *filename;
      int        response;

      chooser = gtk_file_chooser_dialog_new_with_backend (_("Choose a filename for the disc image"),
                                              NULL,
                                              GTK_FILE_CHOOSER_ACTION_SAVE,
                                              "unix",
                                              GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                              GTK_STOCK_OK, GTK_RESPONSE_OK,
                                              NULL);
      gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (chooser),
                                 default_name);
 reselect:
      filename = NULL;
      response = gtk_dialog_run (GTK_DIALOG (chooser));
      
      if (response == GTK_RESPONSE_OK) {
            filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
            if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
                  if (! overwrite_existing_file (GTK_WINDOW (chooser), filename)) {
                        g_free (filename);
                        goto reselect;
                  }
            }

      }
      gtk_widget_destroy (chooser);

      return filename;
}

static gboolean
request_media (NautilusBurnDrive *drive,
             gint64             required_size,
             gboolean           request_overburn,
             gboolean          *use_overburn)
{
      gint64                media_size;
      gboolean              reload;
      NautilusBurnMediaType type;
      gboolean              is_rewritable;
      gboolean              can_write;
      gboolean              is_blank;
      gboolean              has_data;
      gboolean              has_audio;

      /* If the output is a file no need to prompt */
      if (drive->type == NAUTILUS_BURN_DRIVE_TYPE_FILE) {
            return TRUE;
      }

      reload = FALSE;

 again:

      /* if drive is mounted then unmount before checking anything */
      if (nautilus_burn_drive_is_mounted (drive)) {
            gboolean res;
            res = nautilus_burn_drive_unmount (drive);
            if (! res) {
                  g_warning ("Couldn't unmount volume in drive: %s", drive->device);
            }
      }

      /* if overburn requested then no need to check size/type */
      if (request_overburn) {
            return TRUE;
      }

      media_size = nautilus_burn_drive_get_media_size (drive);
      type = nautilus_burn_drive_get_media_type_full (drive, &is_rewritable, &is_blank, &has_data, &has_audio);
      can_write = nautilus_burn_drive_media_type_is_writable (type, is_blank);

      if ((! can_write) || (required_size > media_size)) {
            gboolean suggest_overburn;
            int      res;

            reload = (media_size > 0);
            if (type == NAUTILUS_BURN_MEDIA_TYPE_ERROR) {
                  reload = FALSE;
            }

            suggest_overburn = ((required_size - media_size) <= SUGGEST_OVERBURN);

            res = ask_for_media (drive,
                             reload,
                             FALSE,
                             suggest_overburn,
                             required_size);

            if (res == GTK_RESPONSE_CANCEL) {
                  return FALSE;
            }

            if (res == RESPONSE_OVERBURN) {
                  if (use_overburn) {
                        *use_overburn = TRUE;
                  }

                  return TRUE;
            }

            goto again;
      }

      return TRUE;
}

/* Adapted from sound-juicer */
static char *
sanitize_filename (const char *path,
               gboolean    strip_chars)
{
      char *ret;

      /* Skip leading periods, otherwise files disappear... */
      while (*path == '.') {
            path++;
      }
  
      ret = g_strdup (path);
      /* Replace path seperators with a hyphen */
      g_strdelimit (ret, "/", '-');

      if (strip_chars) {
            /* Replace separators with a hyphen */
            g_strdelimit (ret, "\\:|", '-');
            /* Replace all other weird characters to whitespace */
            g_strdelimit (ret, "*?&!\'\"$()`>{}", ' ');
            /* Replace all whitespace with underscores */
            /* TODO: I'd like this to compress whitespace aswell */
            g_strdelimit (ret, "\t ", '_');
      }

      return ret;
}

static char *
get_output_filename (const char *disc_name)
{
      char *filename         = NULL;
      char *default_filename = NULL;
      char *temp;

      if (disc_name != NULL) {
            default_filename = g_strdup_printf ("%s.iso", disc_name);
      }

      if (default_filename == NULL) {
            /* Translators: this is the filename of the image */
            default_filename = g_strdup (_("image.iso"));
      } else {
            temp = sanitize_filename (default_filename, TRUE);
            g_free (default_filename);
            default_filename = temp;
      }

      /* Run the file selector and get the iso file name selected */
      filename = select_iso_filename (default_filename);
      g_free (default_filename);

      if (filename == NULL) {
            return NULL;
      }

      /* Check if you have permission to create or
       * overwrite the file.
       */
      if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
            if (access (filename, W_OK) == -1) {
                  char *msg;
                  msg = g_strdup_printf (_("You do not have permissions to overwrite that file (%s)."), filename);
                  ncb_hig_show_error_dialog (_("File image creation failed"), msg, NULL);

                  g_free (msg);
                  g_free (filename);

                  return NULL;
            }
      } else {
            char *dir_name;
            dir_name = g_path_get_dirname (filename);

            if (access (dir_name, W_OK) == -1) {
                  char *msg;

                  msg = g_strdup_printf (_("You do not have permissions to create that file (%s)."), filename);
                  ncb_hig_show_error_dialog (_("File image creation failed"), msg, NULL);

                  g_free (filename);
                  g_free (dir_name);
                  g_free (msg);

                  return NULL;
            }

            g_free (dir_name);
      }

      return filename;
}

static int
write_disc (NautilusBurnerWriteData *data)
{
      InsertMediaCallbackData   *insert_media_info;
      GError                    *error = NULL;
      int                        res   = NAUTILUS_BURN_RECORDER_RESULT_ERROR;

      recorder = nautilus_burn_recorder_new ();
      cancel = CANCEL_CD_RECORD;

      insert_media_info = g_new (InsertMediaCallbackData, 1);
      insert_media_info->size  = data->size;
      insert_media_info->drive = data->drive;

      g_signal_connect (G_OBJECT (recorder),
                    "progress-changed",
                    G_CALLBACK (progress_changed_cb),
                    NULL);
      g_signal_connect (G_OBJECT (recorder),
                    "action-changed",
                    G_CALLBACK (action_changed_cb),
                    NULL);
      g_signal_connect (G_OBJECT (recorder),
                    "animation-changed",
                    G_CALLBACK (animation_changed_cb),
                    NULL);
      g_signal_connect (G_OBJECT (recorder),
                    "warn-data-loss",
                    G_CALLBACK (warn_data_loss_cb),
                    data->drive);
      g_signal_connect_data (G_OBJECT (recorder),
                         "insert-media-request",
                         G_CALLBACK (insert_media_request_cb),
                         insert_media_info,
                         (GClosureNotify) g_free, 0);


      res = nautilus_burn_recorder_write_tracks (recorder,
                                       data->drive,
                                       data->tracks,
                                       data->speed,
                                       data->flags,
                                       &error);

      nautilus_burn_progress_set_fraction (1.0);
      nautilus_burn_progress_set_time (-1);

      cancel = CANCEL_NONE;

      if (res == NAUTILUS_BURN_RECORDER_RESULT_FINISHED) {
            nautilus_burn_progress_set_text (_("Complete"));

            setup_close_button ();

      } else if (res != NAUTILUS_BURN_RECORDER_RESULT_CANCEL) {
            nautilus_burn_progress_set_text (_("An error occurred while writing"));

            setup_close_button ();

            show_error_message (recorder, error);
            g_error_free (error);
      }

      g_object_unref (recorder);

      return res;
}

static int
get_input_type_from_source_data (NautilusBurnerSourceData *burn_data)
{
      int input_type;

      if (! burn_data) {
            input_type = NCB_SOURCE_BURN;
      } else if (burn_data->source_iso || burn_data->source_cue) {
            input_type = NCB_SOURCE_IMAGE;
      } else if (burn_data->source_drive || burn_data->source_device) {
            input_type = NCB_SOURCE_DRIVE;
      } else {
            input_type = NCB_SOURCE_BURN;
      }

      return input_type;
}

static void
update_progress_dialog_disc_type (NautilusBurnDrive        *drive,
                          NautilusBurnerSourceData *burn_data,
                          NautilusBurnMediaType     type)
{
      GtkWidget *label;
      GtkWidget *dialog;
      GtkWidget *heading;
      const char *label_text;
      const char *title_text;
      const char *heading_text;
      char      *heading_markup;
      int        input_type;
      int        output_type;
      /* Arrays structured as [input-type][output-type]
         input-type: files/default, image, drive
         output-type: disc/default, file, CD, DVD
       */
      static const char *titles [][4] = {
            { N_("Writing Files to Disc"),
              N_("Writing Files to a Disc Image"),
              N_("Writing Files to CD"),
              N_("Writing Files to DVD")
            },

            { N_("Writing Image to Disc"),
              N_("Copying Disc Image"),
              N_("Writing Image to CD"),
              N_("Writing Image to DVD")
            },

            { N_("Copying Disc"),
              N_("Copying Disc to a Disc Image"),
              N_("Copying Disc to CD"),
              N_("Copying Disc to DVD")
            }
      };
      static const char *headings [][4] = {
            { N_("Writing files to disc"),
              N_("Writing files to a disc image"),
              N_("Writing files to CD"),
              N_("Writing files to DVD")
            },

            { N_("Writing image to disc"),
              N_("Copying disc image"),
              N_("Writing image to CD"),
              N_("Writing image to DVD")
            },

            { N_("Copying disc"),
              N_("Copying disc to a disc image"),
              N_("Copying disc to CD"),
              N_("Copying disc to DVD")
            }
      };
      static const char *descriptions [][4] = {
            { N_("The selected files are being written to a CD or DVD.  This operation may take a long time, depending on data size and write speed."),
              N_("The selected files are being written to a disc image file."),
              N_("The selected files are being written to a CD.  This operation may take a long time, depending on data size and write speed."),
              N_("The selected files are being written to a DVD.  This operation may take a long time, depending on data size and write speed.")
            },

            { N_("The selected disc image is being written to a CD or DVD.  This operation may take a long time, depending on data size and write speed."),
              N_("The selected disc image is being copied to a disc image file."),
              N_("The selected disc image is being written to a CD.  This operation may take a long time, depending on data size and write speed."),
              N_("The selected disc image is being written to a DVD.  This operation may take a long time, depending on data size and write speed.")
            },

            { N_("The selected disc is being copied to a CD or DVD.  This operation may take a long time, depending on data size and drive speed."),
              N_("The selected disc is being copied to a disc image file.  This operation may take a long time, depending on data size and drive speed."),
              N_("The selected disc is being copied to a CD.  This operation may take a long time, depending on data size and drive speed."),
              N_("The selected disc is being copied to a DVD.  This operation may take a long time, depending on data size and drive speed.")
            }
      };

      input_type = get_input_type_from_source_data (burn_data);

      if (drive->type == NAUTILUS_BURN_DRIVE_TYPE_FILE) {
            output_type = NCB_OUTPUT_FILE;
      } else {
            switch (type) {
            case NAUTILUS_BURN_MEDIA_TYPE_CD:
            case NAUTILUS_BURN_MEDIA_TYPE_CDR:
            case NAUTILUS_BURN_MEDIA_TYPE_CDRW:
                  output_type = NCB_OUTPUT_CD;
                  break;
            case NAUTILUS_BURN_MEDIA_TYPE_DVD:
            case NAUTILUS_BURN_MEDIA_TYPE_DVDR:
            case NAUTILUS_BURN_MEDIA_TYPE_DVDRW:
            case NAUTILUS_BURN_MEDIA_TYPE_DVD_RAM:
            case NAUTILUS_BURN_MEDIA_TYPE_DVD_PLUS_R:
            case NAUTILUS_BURN_MEDIA_TYPE_DVD_PLUS_RW:
            case NAUTILUS_BURN_MEDIA_TYPE_DVD_PLUS_R_DL:
                  output_type = NCB_OUTPUT_DVD;
                  break;
            case NAUTILUS_BURN_MEDIA_TYPE_UNKNOWN:
            default:
                  output_type = NCB_OUTPUT_DEFAULT;
                  break;
            }
      }

      label_text = descriptions [input_type][output_type];
      title_text = titles [input_type][output_type];
      heading_text = headings [input_type][output_type];

      label   = glade_xml_get_widget (xml, "progress_description_label");
      heading = glade_xml_get_widget (xml, "info_title_label");
      dialog  = glade_xml_get_widget (xml, "progress_window");

      gtk_label_set_text (GTK_LABEL (label), _(label_text));
      gtk_window_set_title (GTK_WINDOW (dialog), _(title_text));

      heading_markup = g_strdup_printf ("<big><b>%s</b></big>", _(heading_text));
      gtk_label_set_markup (GTK_LABEL (heading), heading_markup);
      g_free (heading_markup);
}

static int
burn_cd (NautilusBurnDrive        *drive,
       NautilusBurnerSourceData *burn_data,
       const char               *label,
       gboolean                  eject_cd,
       int                       speed,
       gboolean                  dummy,
       gboolean                  debug,
       gboolean                  overburn,
       gboolean                  burnproof)
{
      GError                        *error        = NULL;
      char                          *filename     = NULL;
      char                          *toc_filename = NULL;
      NautilusBurnImageType          image_type   = NAUTILUS_BURN_IMAGE_TYPE_UNKNOWN;
      char                          *str;
      int                            fd;
      int                            res      = NAUTILUS_BURN_RECORDER_RESULT_ERROR;
      gboolean                       try_overburn = FALSE;
      NautilusBurnDrive             *source_drive;
      const char                    *source_iso;
      const char                    *source_cue;
      gint64                         burn_size;
      NautilusBurnMediaType          media_type = NAUTILUS_BURN_MEDIA_TYPE_UNKNOWN;

      source_drive = burn_data->source_drive;
      source_iso   = burn_data->source_iso;
      source_cue   = burn_data->source_cue;
      burn_size    = burn_data->size;

      filename = NULL;

      if (drive->type == NAUTILUS_BURN_DRIVE_TYPE_FILE) {
            char *disc_name = NULL;

            if (source_drive) {
                  disc_name = nautilus_burn_drive_get_media_label (source_drive);
            }

            filename = get_output_filename (disc_name);
            g_free (disc_name);

            if (! filename) {
                  return NAUTILUS_BURN_RECORDER_RESULT_CANCEL;
            }
      } else {
            if (source_iso == NULL) {
                  GConfClient *gc;
                  char        *path;

                  gc = gconf_client_get_default ();
                  path = gconf_client_get_string (gc, "/apps/nautilus-cd-burner/temp_iso_dir", NULL);
                  g_object_unref (gc);
                  if (path != NULL && path[0] != '\0') {
                        filename = g_build_filename (path, "image.iso.XXXXXX", NULL);
                        fd = g_mkstemp (filename);
                        if (fd < 0) {
                              g_error ("Could not create temporary filename for ISO image");
                              res = NAUTILUS_BURN_RECORDER_RESULT_ERROR;
                              goto out;
                        } else {
                              close (fd);
                        }
                  }

                  g_free (path);
            } else {
                  filename = g_strdup (source_iso);
            }
      }

      if (drive->type != NAUTILUS_BURN_DRIVE_TYPE_FILE) {
            /* if we are reading from a drive then don't request media yet */
            if (! source_drive) {
                  gboolean              is_locked;
                  gboolean              got_media;

                  is_locked = nautilus_burn_drive_lock (drive, _("Burning CD"), NULL);
                  got_media = request_media (drive, burn_size, overburn, &try_overburn);

                  if (got_media) {
                        media_type = nautilus_burn_drive_get_media_type (drive);
                  }

                  if (is_locked) {
                        nautilus_burn_drive_unlock (drive);
                  } 

                  if (! got_media) {
                        res = NAUTILUS_BURN_RECORDER_RESULT_CANCEL;
                        goto out;
                  }
            }
      }

      /* update the description now that we may know the media type */
      update_progress_dialog_disc_type (drive, burn_data, media_type);

      if (source_iso == NULL
          && source_cue == NULL) {
            NautilusBurnImageCreateFlags image_flags = 0;

            if (debug) {
                  image_flags |= NAUTILUS_BURN_IMAGE_CREATE_DEBUG;
            }
            if (1) {
                  image_flags |= NAUTILUS_BURN_IMAGE_CREATE_JOLIET;
            }

            cancel = CANCEL_MAKE_ISO;

            if (filename != NULL) {

                  if (drive->type == NAUTILUS_BURN_DRIVE_TYPE_FILE) {
                        image_flags |= NAUTILUS_BURN_IMAGE_CREATE_WARN_SPACE;
                  }

                  /* Don't warn on low space unless the user selected this file specifically */
                  if (source_drive) {
                        res = nautilus_burn_make_iso_from_drive (filename,
                                                       source_drive,
                                                       image_flags,
                                                       &image_type,
                                                       &toc_filename,
                                                       &error);
                  } else {
                        res = nautilus_burn_make_iso (filename, label, image_flags, &image_type, &error);
                  }
            } else {
                  res = NAUTILUS_BURN_RECORDER_RESULT_RETRY;
            }

            if (res == NAUTILUS_BURN_RECORDER_RESULT_RETRY) {
                  g_free (toc_filename);
                  g_free (filename);

                  filename = g_build_filename (g_get_tmp_dir (), "image.iso.XXXXXX", NULL);
                  fd = g_mkstemp (filename);
                  if (fd < 0) {
                        g_error ("Could not create temporary filename for ISO image");
                        res = NAUTILUS_BURN_RECORDER_RESULT_ERROR;
                        goto out;
                  } else {
                        close (fd);
                  }

                  image_flags &= ~NAUTILUS_BURN_IMAGE_CREATE_WARN_SPACE;

                  if (source_drive) {
                        res = nautilus_burn_make_iso_from_drive (filename,
                                                       source_drive,
                                                       image_flags,
                                                       &image_type,
                                                       &toc_filename,
                                                       &error);
                  } else {
                        res = nautilus_burn_make_iso (filename, label, image_flags, &image_type, &error);
                  }

                  if (res == NAUTILUS_BURN_RECORDER_RESULT_RETRY) {
                        g_free (toc_filename);
                        g_free (filename);

                        filename = g_build_filename (g_get_home_dir (), ".image.iso.XXXXXX", NULL);
                        fd = g_mkstemp (filename);
                        if (fd < 0) {
                              g_error ("Could not create temporary filename for ISO image");
                              res = NAUTILUS_BURN_RECORDER_RESULT_ERROR;
                              goto out;
                        } else {
                              close (fd);
                        }

                        image_flags |= NAUTILUS_BURN_IMAGE_CREATE_WARN_SPACE;

                        if (source_drive) {
                              res = nautilus_burn_make_iso_from_drive (filename,
                                                             source_drive,
                                                             image_flags,
                                                             &image_type,
                                                             &toc_filename,
                                                             &error);
                        } else {
                              res = nautilus_burn_make_iso (filename, label, image_flags, &image_type, &error);
                        }
                  }
            }

            if (res != NAUTILUS_BURN_RECORDER_RESULT_FINISHED) {
                  /* User cancelled or we had an error. */
                  if (res == NAUTILUS_BURN_RECORDER_RESULT_ERROR) {
                        ncb_hig_show_error_dialog (_("File image creation failed"), error ? error->message : NULL, NULL);
                        g_error_free (error);
                  }
                  cancel = CANCEL_NONE;
                  res = NAUTILUS_BURN_RECORDER_RESULT_CANCEL;
                  goto out;
            }
      } else if (source_cue) {
            /* TODO: validate file */
            image_type = NAUTILUS_BURN_IMAGE_TYPE_BINCUE;
            toc_filename = g_strdup (source_cue);
      } else if (source_iso) {
            image_type = NAUTILUS_BURN_IMAGE_TYPE_ISO9660;
      }

      if (drive->type == NAUTILUS_BURN_DRIVE_TYPE_FILE) {
            str = g_strdup_printf (_("Completed writing %s"), filename);
            nautilus_burn_progress_set_text (str);
            nautilus_burn_progress_set_time (-1);
            g_free (str);

            setup_close_button ();

            res = NAUTILUS_BURN_RECORDER_RESULT_FINISHED;
            goto out;
      } else {
            NautilusBurnRecorderTrack     *track;
            NautilusBurnerWriteData       *data;
            NautilusBurnRecorderWriteFlags record_flags = 0;

            data = g_new0 (NautilusBurnerWriteData, 1);

            track = g_new0 (NautilusBurnRecorderTrack, 1);

            switch (image_type) {
            case NAUTILUS_BURN_IMAGE_TYPE_BINCUE:
                  track->type = NAUTILUS_BURN_RECORDER_TRACK_TYPE_CUE;
                  /* TODO: make sure cue exists */
                  track->contents.cue.filename = g_strdup (toc_filename);
                  break;
            case NAUTILUS_BURN_IMAGE_TYPE_ISO9660:
                  track->type = NAUTILUS_BURN_RECORDER_TRACK_TYPE_DATA;
                  track->contents.data.filename = g_strdup (filename);
                  break;
            default:
                  break;
            }

            record_flags = 0;
            if (eject_cd) {
                  record_flags |= NAUTILUS_BURN_RECORDER_WRITE_EJECT;
            }
            if (dummy) {
                  record_flags |= NAUTILUS_BURN_RECORDER_WRITE_DUMMY_WRITE;
            }
            if (debug) {
                  record_flags |= NAUTILUS_BURN_RECORDER_WRITE_DEBUG;
            }
            if (overburn || try_overburn) {
                  record_flags |= NAUTILUS_BURN_RECORDER_WRITE_OVERBURN;
            }
            if (1) {
                  record_flags |= NAUTILUS_BURN_RECORDER_WRITE_BURNPROOF;
            }
            if (1) {
                  record_flags |= NAUTILUS_BURN_RECORDER_WRITE_DISC_AT_ONCE;
            }

            if (source_drive
                && nautilus_burn_drive_equal (source_drive, drive)) {
                  nautilus_burn_drive_eject (source_drive);
            }

            data->drive  = nautilus_burn_drive_ref (drive);
            data->tracks = g_list_prepend (data->tracks, track);
            data->flags  = record_flags;
            data->speed  = speed;
            data->size   = burn_size;

            nautilus_burn_progress_set_write_data (data);
            res = nautilus_burn_progress_write_disc ();

            if (source_iso == NULL) {
                  nautilus_burn_progress_temp_files_add (filename);
            }
      }

 out:
      g_free (filename);

      return res;
}

static NautilusBurnDrive *
lookup_current_recorder (GladeXML *xml)
{
      GtkWidget         *selection;
      NautilusBurnDrive *drive;

      selection = glade_xml_get_widget (xml, "target_optionmenu");

      if (! selection) {
            return NULL;
      }

      /* the drive is reffed */
      drive = nautilus_burn_drive_selection_get_active (NAUTILUS_BURN_DRIVE_SELECTION (selection));

      return drive;
}

static int
get_speed_selection (GtkWidget *combobox)
{
      int           speed;
      GtkTreeModel *model;
      GtkTreeIter   iter;

      speed = 0;

      if (! gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combobox), &iter)) {
            return speed;
      }

      model = gtk_combo_box_get_model (GTK_COMBO_BOX (combobox));
        gtk_tree_model_get (model, &iter, 1, &speed, -1);

      return speed;
}

static void
refresh_dialog (GladeXML *xml)
{
      GtkWidget               *combobox;
      GConfClient             *gc;
      char                    *name;
      int                      i;
      int                      default_speed;
      int                      default_speed_index;
      NautilusBurnDrive       *drive;
      GtkTreeModel            *model;
      GtkTreeIter              iter;

      default_speed_index = 0;

      /* Find active recorder: */
      drive = lookup_current_recorder (xml);

      /* add speed items: */
      combobox = glade_xml_get_widget (xml, "speed_combobox");
      model = gtk_combo_box_get_model (GTK_COMBO_BOX (combobox));
      gtk_list_store_clear (GTK_LIST_STORE (model));

      gc = gconf_client_get_default ();
      default_speed = gconf_client_get_int (gc, "/apps/nautilus-cd-burner/default_speed", NULL);
      g_object_unref (G_OBJECT (gc));

      gtk_list_store_append (GTK_LIST_STORE (model), &iter);
      gtk_list_store_set (GTK_LIST_STORE (model), &iter,
                      0, _("Maximum possible"),
                      1, 0,
                      -1);

      if (drive) {
            const int *write_speeds;

            write_speeds = nautilus_burn_drive_get_write_speeds (drive);

            for (i = 0; write_speeds[i] > 0; i++) {

                  if (write_speeds[i] == default_speed) {
                        default_speed_index = i + 1;
                  }

                  name = g_strdup_printf ("%d \303\227", write_speeds[i]);
                  gtk_list_store_append (GTK_LIST_STORE (model), &iter);
                  gtk_list_store_set (GTK_LIST_STORE (model), &iter,
                                  0, name,
                                  1, write_speeds [i],
                                  -1);
                  g_free (name);
            }

            /* Disable speed if no items in list */
            gtk_widget_set_sensitive (combobox, i > 0);
      }

      gtk_combo_box_set_active (GTK_COMBO_BOX (combobox), default_speed_index);

      if (drive) {
            nautilus_burn_drive_unref (drive);
      }
}

static void
target_changed (NautilusBurnDriveSelection *selection,
            const char                 *device_path,
            GladeXML                   *xml)
{
      refresh_dialog (xml);
}

static void
cdname_entry_insert_text (GtkEditable *editable,
                    const char  *new_text,
                    int          new_text_length,
                    int         *position)
{
      char *current_text;

      if (new_text_length < 0) {
            new_text_length = strlen (new_text);
      }

      current_text = gtk_editable_get_chars (editable, 0, -1);
      if (strlen (current_text) +  new_text_length >= MAX_ISO_NAME_LEN) {
            gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (editable)));
            g_signal_stop_emission_by_name (editable, "insert_text");
      }

      g_free (current_text);
}

static void
setup_speed_combobox (GtkWidget *combobox)
{
      GtkCellRenderer *cell;
      GtkListStore    *store;

      store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);

      gtk_combo_box_set_model (GTK_COMBO_BOX (combobox),
                         GTK_TREE_MODEL (store));
        g_object_unref (store);

      cell = gtk_cell_renderer_text_new ();
      gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combobox), cell, TRUE);
      gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), cell,
                              "text", 0,
                              NULL);
}

static void
dialog_set_size (GtkWidget       *dialog,
             GnomeVFSFileSize size)
{
      GtkWidget *label;
      char      *str;
      int        size_mb;

      label = glade_xml_get_widget (xml, "size_label");

      size_mb = (size + 1024 * 1024 - 1)/ (1024 * 1024);
      str = g_strdup_printf (_("%d MiB"), size_mb);
      gtk_label_set_markup (GTK_LABEL (label), str);
      g_free (str);
}

static void
dialog_set_disc_name (GtkWidget *dialog,
                  char      *disc_name,
                  gboolean   from_image)
{
      GtkWidget *entry;
      GDate     *now;
      char       buf [129];
      char      *str, *last;

      /* Set default name */
      entry = glade_xml_get_widget (xml, "cdname_entry");
      g_signal_connect (entry, "insert_text", G_CALLBACK (cdname_entry_insert_text),
                    NULL);

      if (from_image != FALSE) {
            gtk_widget_set_sensitive (entry, FALSE);
            if (disc_name != NULL) {
                  gtk_entry_set_text (GTK_ENTRY (entry), disc_name);
                  gtk_editable_set_editable (GTK_EDITABLE (entry), FALSE);
            }
      } else {
            now = g_date_new ();

            g_date_set_time (now, time (NULL));

            /*
              translators: see strftime man page for meaning of %b, %d and %Y
              the maximum length for this field is 32 bytes
            */
            g_date_strftime (buf, sizeof (buf), _("Personal Data, %b %d, %Y"), now);

            g_date_free (now);

            /* Cut off at 32 bytes */
            last = str = buf;
            while (*str != 0 &&
                   (str - buf) < MAX_ISO_NAME_LEN) {
                  last = str;
                  str = g_utf8_next_char (str);
            }
            if (*str != 0) {
                  *last = 0;
            }
            
            gtk_entry_set_text (GTK_ENTRY (entry), buf);
      }
}

static void
init_dialog (GladeXML        *xml,
           GtkWidget       *dialog)
{
      GtkWidget *label;
      GtkWidget *drive_combobox;
      GtkWidget *speed_combobox;

      /* Fill in targets */
      drive_combobox = glade_xml_get_widget (xml, "target_optionmenu");
      gtk_widget_show (drive_combobox);
      g_object_set (drive_combobox, "file-image", TRUE, NULL);
      g_object_set (drive_combobox, "show-recorders-only", TRUE, NULL);
      g_signal_connect (drive_combobox, "device-changed",
                    G_CALLBACK (target_changed), xml);

      speed_combobox = glade_xml_get_widget (xml, "speed_combobox");
      setup_speed_combobox (speed_combobox);

      dialog_set_disc_name (dialog, "", FALSE);

      label = glade_xml_get_widget (xml, "size_label");
      gtk_label_set_markup (GTK_LABEL (label), _("Calculating..."));

      refresh_dialog (xml);
}

/* Returns TRUE if writing should be cancelled */
static gboolean
ask_cancel (void)
{
      GtkWidget *warning_dialog;
      GtkWidget *image;
      GtkWidget *button;
      int        res;

      warning_dialog = ncb_hig_dialog (GTK_MESSAGE_WARNING,
                               _("Interrupt writing files to disc?"),
                               _("Are you sure you want to interrupt the disc write operation? "
                                 "Some drives may require that you restart the computer to get them working again."),
                               nautilus_burn_progress_get_window ());

      image = gtk_image_new_from_stock (GTK_STOCK_STOP, GTK_ICON_SIZE_BUTTON);
      gtk_widget_show (image);
      button = gtk_dialog_add_button (GTK_DIALOG (warning_dialog), _("Interrupt"), GTK_RESPONSE_YES);
      g_object_set (button, "image", image, NULL);
      gtk_dialog_add_button (GTK_DIALOG (warning_dialog), _("Continue"), GTK_RESPONSE_NO);

      gtk_dialog_set_default_response (GTK_DIALOG (warning_dialog), GTK_RESPONSE_NO);
      res = gtk_dialog_run (GTK_DIALOG (warning_dialog));
      gtk_widget_destroy (warning_dialog);

      return (res == GTK_RESPONSE_YES);
}

static gboolean
handle_cancel (void)
{
      gboolean cancelled;

      if (cancel == CANCEL_NONE) {
            return FALSE;
      }

      if (cancel == CANCEL_MAKE_ISO) {
            nautilus_burn_make_iso_cancel ();
            return TRUE;
      }

      cancelled = nautilus_burn_recorder_cancel (recorder, TRUE);

      if (! cancelled) {
            if (ask_cancel () == TRUE) {
                  /* do the dangerous cancel */
                  nautilus_burn_recorder_cancel (recorder, FALSE);
            } else {
                  return TRUE;
            }
      }

      return TRUE;
}

static gboolean
handle_delete_event (GtkWidget           *widget,
                 GdkEventAny     *event)
{
      return handle_cancel ();
}

static void
cancel_clicked (GtkButton *button,
            gpointer   data)
{
      handle_cancel ();
}

static void
help_activate (GtkWindow *parent)
{
      GError *err = NULL;

      if (gnome_help_display_desktop (NULL, "user-guide", "user-guide.xml", "gosnautilus-475", &err) == FALSE) {
            char *msg;

            msg = g_strdup_printf (_("There was a problem displaying the help contents: %s."), err->message);
            ncb_hig_show_error_dialog (_("Cannot display help"),
                                 msg, parent);
            g_error_free (err);
            g_free (msg);
      }
}

static gboolean
verify_source_location_contents (const char *text_uri,
                         gint64     *size_out,
                         GList     **images)
{
      GList    *unreadable_paths = NULL;
      GList    *image_paths      = NULL;
      gboolean  only_images;
      gint64    size;
      int       res;

      if (images) {
            *images = NULL;
      }

      size = estimate_size (text_uri, &unreadable_paths, &image_paths, &only_images);

      if (only_images == TRUE && size != 0) {
            GtkWidget *dialog;
            char      *msg;

            if (g_list_length (image_paths) == 1) {
                  msg = g_strdup (_("It appears that the disc, when created, will contain a single disc image file.  "
                                "Do you want to continue and write it to the disc as a file?"));
                  dialog = ncb_hig_dialog (GTK_MESSAGE_QUESTION,
                                     _("Create disc containing a single disc image file?"),
                                     msg, NULL);
                  gtk_dialog_add_buttons (GTK_DIALOG (dialog),
                                    _("Create From Image"), GTK_RESPONSE_NO,
                                    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                    _("Create With File"), GTK_RESPONSE_YES,
                                    NULL);
            } else {
                  msg = g_strdup (_("It appears that the disc, when created, will contain only disc image files.  "
                                "Do you want to continue and write them to the disc as files?"));
                  dialog = ncb_hig_dialog (GTK_MESSAGE_QUESTION,
                                     _("Create disc containing only disc image files?"),
                                     msg, NULL);
                  gtk_dialog_add_buttons (GTK_DIALOG (dialog),
                                    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                    _("Create With Files"), GTK_RESPONSE_YES,
                                    NULL);
            }
            g_free (msg);

            gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
            res = gtk_dialog_run (GTK_DIALOG (dialog));
            gtk_widget_destroy (dialog);

            if (res == GTK_RESPONSE_NO) {
                  if (images) {
                        *images = image_paths;
                  } else {
                        g_list_foreach (image_paths, (GFunc)g_free, NULL);
                        g_list_free (image_paths);
                  }
                  return FALSE;
            } else if (res == GTK_RESPONSE_CANCEL) {
                  g_list_foreach (image_paths, (GFunc)g_free, NULL);
                  g_list_free (image_paths);
                  return FALSE;
            }
      }

      if (unreadable_paths) {
            GList *l;

            for (l = unreadable_paths; l; l = l->next) {
                  GtkWidget *dialog;
                  char      *msg;

                  msg = g_strdup_printf (_("The file '%s' is unreadable.  Do you wish to skip this file and continue?"),
                                     (char *)l->data);
                  dialog = ncb_hig_dialog (GTK_MESSAGE_WARNING,
                                     _("Skip unreadable file?"),
                                     msg,
                                     NULL);
                  g_free (msg);
                  gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                    _("Skip"), GTK_RESPONSE_ACCEPT, _("Skip All"), GTK_RESPONSE_YES, NULL);
                  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
                  res = gtk_dialog_run (GTK_DIALOG (dialog));
                  gtk_widget_destroy (dialog);
                  if (res == GTK_RESPONSE_ACCEPT) {
                  } else if (res == GTK_RESPONSE_YES) {
                        break;
                  } else {
                        /* cancel */
                        g_list_foreach (unreadable_paths, (GFunc)g_free, NULL);
                        g_list_free (unreadable_paths);
                        return FALSE;
                  }
            }

            g_list_foreach (unreadable_paths, (GFunc)g_free, NULL);
            g_list_free (unreadable_paths);
      }


      if (size <= 0) {
            GtkWidget *dialog;

            dialog = ncb_hig_dialog (GTK_MESSAGE_ERROR,
                               _("No files selected"),
                               _("You need to copy the files you want to write to disc to the CD/DVD Creator window."),
                               NULL);
            gtk_dialog_add_buttons (GTK_DIALOG (dialog),
                              _("Open CD/DVD Creator"), GTK_RESPONSE_YES,
                              GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
                              NULL);
            gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
            res = gtk_dialog_run (GTK_DIALOG (dialog));
            gtk_widget_destroy (dialog);
            if (res == GTK_RESPONSE_YES) {
                  char *argv [] = { "nautilus", "--no-desktop", BURN_URI, NULL };
                  g_spawn_async (NULL, argv, NULL,
                               G_SPAWN_SEARCH_PATH,
                               NULL, NULL, NULL, NULL);
            }

            return FALSE;
      }

      if (size_out) {
            *size_out = size;
      }

      return TRUE;
}

static gboolean
verify_source_image (const char           *text_uri,
                 gint64               *size_out,
                 char                **disc_name)
{
      GError     *error;
      struct stat stat_buf;
      int         res;

      error = NULL;

      if (!nautilus_burn_verify_iso (text_uri, disc_name, &error)) {
            GtkWidget *dialog;
            char      *msg;

            msg = g_strdup_printf (_("The file '%s' is not a valid disc image."),
                               text_uri);
            dialog = ncb_hig_dialog (GTK_MESSAGE_ERROR,
                               error->message,
                               msg, NULL);
            gtk_dialog_add_buttons (GTK_DIALOG (dialog),
                              GTK_STOCK_CLOSE, GTK_RESPONSE_OK,
                              NULL);

            g_free (msg);
            g_error_free (error);
            gtk_dialog_run (GTK_DIALOG (dialog));
            gtk_widget_destroy (dialog);

            return FALSE;
      }

      /* TODO: is this close enough for the CD size? */
      res = g_stat (text_uri, &stat_buf);

      if (size_out) {
            *size_out = (gint64)stat_buf.st_size;
      }

      return TRUE;
}

static void
selection_dialog_response (GtkWidget                *dialog,
                     int                       response_id,
                     NautilusBurnerSourceData *burn_data)
{

      if (response_id == GTK_RESPONSE_HELP) {
            help_activate (GTK_WINDOW (dialog));
            return;
      }

      if (response_id != GTK_RESPONSE_OK) {
            gtk_main_quit ();
            return;
      }

      if (response_id == GTK_RESPONSE_OK) {
            NautilusBurnDrive *drive;
            GtkWidget  *progress_window;
            GtkWidget  *cancel_button;
            GtkWidget  *entry;
            GtkWidget  *speed_combobox;
            GtkWidget  *dummy_check;
            GtkWidget  *description_label;
            gboolean    eject;
            gboolean                 dummy, debug, overburn, burnproof;
            const char              *label;
            int                      res, speed;
            GConfClient             *gconf_client;

            drive = lookup_current_recorder (xml);

            gtk_widget_hide (dialog);

            cancel_button      = glade_xml_get_widget (xml, "cancel_button");
            description_label  = glade_xml_get_widget (xml, "progress_description_label");
            entry              = glade_xml_get_widget (xml, "cdname_entry");
            speed_combobox     = glade_xml_get_widget (xml, "speed_combobox");
            dummy_check        = glade_xml_get_widget (xml, "dummy_check");
            progress_window    = glade_xml_get_widget (xml, "progress_window");

            update_progress_dialog_disc_type (drive, burn_data, NAUTILUS_BURN_MEDIA_TYPE_UNKNOWN);

            gtk_window_set_icon_name (GTK_WINDOW (progress_window), "gnome-dev-cdrom");
            nautilus_burn_progress_image_setup ();
            gtk_widget_show (progress_window);

            g_signal_connect (cancel_button, "clicked", G_CALLBACK (cancel_clicked), NULL);
            g_signal_connect (progress_window, "delete_event", G_CALLBACK (handle_delete_event), NULL);

            label = gtk_entry_get_text (GTK_ENTRY (entry));

            /* eject all discs */
            /* FIXME: make this gconf configurable? */
            eject = FALSE;

            speed = get_speed_selection (speed_combobox);

            gconf_client = gconf_client_get_default ();
            gconf_client_set_int (gconf_client, "/apps/nautilus-cd-burner/default_speed", speed, NULL);
            debug     = gconf_client_get_bool (gconf_client, "/apps/nautilus-cd-burner/debug", NULL);
            overburn  = gconf_client_get_bool (gconf_client, "/apps/nautilus-cd-burner/overburn", NULL);
            burnproof = gconf_client_get_bool (gconf_client, "/apps/nautilus-cd-burner/burnproof", NULL);
            g_object_unref (gconf_client);

            dummy = FALSE;
            if (debug) {
                  dummy = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dummy_check));
            }

            res = burn_cd (drive,
                         burn_data,
                         label,
                         eject,
                         speed,
                         dummy,
                         debug,
                         overburn,
                         burnproof);

            if (drive) {
                  nautilus_burn_drive_unref (drive);
            }

            if (res == NAUTILUS_BURN_RECORDER_RESULT_CANCEL) {
                  gtk_main_quit ();
            }
      }
}

static gboolean
fill_selection_dialog (NautilusBurnerSourceData *burn_data)
{
      char      *disc_name = NULL;
      GtkWidget *dialog;

      dialog = glade_xml_get_widget (xml, "cdr_dialog");

      if (burn_data->source_device) {
            burn_data->source_drive = nautilus_burn_drive_new_from_path (burn_data->source_device);

            if (! burn_data->source_drive) {
                  char *msg;

                  msg = g_strdup_printf (_("The specified device '%s' is not a valid CD/DVD drive."),
                                     burn_data->source_device);
                  ncb_hig_show_error_dialog (_("Unable to read specified location"),
                                       msg,
                                       GTK_WINDOW (dialog));
                  g_free (msg);

                  goto done;
            }
            nautilus_burn_drive_unmount (burn_data->source_drive);
            disc_name = nautilus_burn_drive_get_media_label (burn_data->source_drive);
            burn_data->size = nautilus_burn_drive_get_media_size (burn_data->source_drive);

            if (burn_data->size <= 0) {
                  ncb_hig_show_error_dialog (_("No media available"),
                                       _("There doesn't seem to be any media in the selected drive."),
                                       GTK_WINDOW (dialog));
                  goto done;
            }
      } else if (burn_data->source_cue != NULL) {
            /* FIXME: parse the .BIN file out of the file and check size */
            burn_data->size = 0;
      } else if (burn_data->source_iso != NULL) {
            if (! verify_source_image (burn_data->source_iso, &burn_data->size, &disc_name))
                  goto done;
      } else {
            GList *image_paths = NULL;

            if (! verify_source_location_contents (BURN_URI, &burn_data->size, &image_paths)) {
                  if (image_paths) {
                        burn_data->source_iso = g_strdup ((char *)image_paths->data);
                        g_list_foreach (image_paths, (GFunc)g_free, NULL);
                        g_list_free (image_paths);
                        if (! verify_source_image (burn_data->source_iso, &burn_data->size, &disc_name)) {
                              goto done;
                        }
                  } else 
                        goto done;
            }
      }

      gtk_widget_set_sensitive (dialog, TRUE);
      gdk_window_set_cursor (dialog->window, NULL);

      dialog_set_size (dialog, burn_data->size);
      dialog_set_disc_name (dialog,
                        disc_name,
                        (burn_data->source_iso != NULL)
                        || (burn_data->source_drive != NULL)
                        || (burn_data->source_cue != NULL));

      if (disc_name != NULL) {
            g_free (disc_name);
      }

      return FALSE;

 done:
      g_free (disc_name);

      gtk_main_quit ();

      return FALSE;
}

static void
update_selection_dialog_source_type (NautilusBurnerSourceData *burn_data)
{
      GtkWidget *widget;
      int        input_type;

      input_type = get_input_type_from_source_data (burn_data);

      if (NCB_SOURCE_DRIVE == input_type) {
            widget = glade_xml_get_widget (xml, "cdr_dialog");
            gtk_window_set_title (GTK_WINDOW (widget), _("Copy Disc"));

            widget = glade_xml_get_widget (xml, "target_label");
            gtk_label_set_text_with_mnemonic (GTK_LABEL (widget), _("Copy disc _to:"));
      }
}

static gboolean
create_selection_dialog (NautilusBurnerSourceData *burn_data)
{
      GtkWidget               *dialog;
      GtkWidget               *dummy_check;
      GdkCursor               *cursor;
      GConfClient             *gconf_client;
      gboolean                 debug;

      if (g_file_test ("cdburn.glade", G_FILE_TEST_EXISTS) != FALSE) {
            xml = glade_xml_new ("./cdburn.glade", NULL, NULL);
      } else {
            xml = glade_xml_new (DATADIR "/cdburn.glade", NULL, NULL);
      }

      dialog = glade_xml_get_widget (xml, "cdr_dialog");
            
      init_dialog (xml,
                 dialog);

      gconf_client = gconf_client_get_default ();
      debug        = gconf_client_get_bool (gconf_client, "/apps/nautilus-cd-burner/debug", NULL);
      g_object_unref (gconf_client);

      dummy_check = glade_xml_get_widget (xml, "dummy_check");

      if (debug == FALSE) {
            gtk_widget_hide (dummy_check);
      }

      gtk_window_set_icon_name (GTK_WINDOW (dialog), "gnome-dev-cdrom");

      /* make insensitive until fill_dialog finishes */
      gtk_widget_set_sensitive (dialog, FALSE);

      update_selection_dialog_source_type (burn_data);

      gtk_widget_show (dialog);

      cursor = gdk_cursor_new (GDK_WATCH);
      gdk_window_set_cursor (dialog->window, cursor);
      gdk_cursor_unref (cursor);

      g_signal_connect (dialog, "response", G_CALLBACK (selection_dialog_response), burn_data);

      g_idle_add ((GSourceFunc)fill_selection_dialog, burn_data);

      return FALSE;
}

static char *
expand_path_input (const char *input)
{
      char *uri;
      char *path;

      uri = gnome_vfs_make_uri_from_input_with_dirs (input, GNOME_VFS_MAKE_URI_DIR_CURRENT);
      if (uri == NULL) {
            g_warning ("Could not parse filename");
            return NULL;
      }

      path = gnome_vfs_get_local_path_from_uri (uri);
      g_free (uri);

      if (path == NULL) {
            g_warning ("Only local files are supported at this time");
      }

      return path;
}

int
main (int argc, char *argv[])
{
      NautilusBurnerSourceData *burn_data;
      static char              *source_device;
      static char              *source_iso;
      static char              *source_cue;
        struct poptOption         popt_options []  = {
            { "source-device", 0, POPT_ARG_STRING, &source_device,
              0, N_("Use CD/DVD device as source instead of burn:///"), NULL },
            { "source-iso", 0, POPT_ARG_STRING, &source_iso,
              0, N_("Use ISO image as source instead of burn:///"), NULL },
            { "source-cue", 0, POPT_ARG_STRING, &source_cue,
              0, N_("Use CUE/TOC file as source instead of burn:///"), NULL },
                POPT_TABLEEND
      };

      bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
      bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
      textdomain (GETTEXT_PACKAGE);

      gnome_program_init ("nautilus-cd-burner", VERSION,
                      LIBGNOMEUI_MODULE, argc, argv,
                      GNOME_PARAM_POPT_TABLE, popt_options,
                      GNOME_PARAM_APP_DATADIR, SHAREDIR,
                      GNOME_PARAM_NONE);
    
      gnome_vfs_init ();

      if (argc > 2) {
            GtkWidget *dialog;
            int        res;

            dialog = ncb_hig_dialog (GTK_MESSAGE_ERROR,
                               _("Too many parameters"),
                               _("Too many parameters were passed to the application."),
                               NULL);
            gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_OK,
                               GTK_RESPONSE_OK);
            res = gtk_dialog_run (GTK_DIALOG (dialog));
            gtk_widget_destroy (dialog);

            return 1;
      }

      burn_data = g_new0 (NautilusBurnerSourceData, 1);

      if (source_iso != NULL) {
            char *path;

            path = expand_path_input (source_iso);
            if (path == NULL) {
                  goto out;
            }
            burn_data->source_iso = path;
      }

      if (source_cue != NULL) {
            char *path;

            path = expand_path_input (source_cue);
            if (path == NULL) {
                  goto out;
            }
            burn_data->source_cue = path;
      }

      burn_data->source_device = g_strdup (source_device);

      g_idle_add ((GSourceFunc)create_selection_dialog, burn_data);

      gtk_main ();

 out:
      g_free (burn_data->source_cue);
      g_free (burn_data->source_iso);
      g_free (burn_data->source_device);
      g_free (burn_data);

      nautilus_burn_progress_cleanup ();

      return 0;
}

Generated by  Doxygen 1.6.0   Back to index