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

nautilus-burn-drive.c

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
 *
 * nautilus-burn-drive.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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#ifdef __linux__
#include <linux/cdrom.h>
#include <scsi/scsi.h>
#include <scsi/sg.h>
#endif /* __linux__ */

#ifdef __FreeBSD__
#include <sys/cdio.h>
#include <sys/cdrio.h>
#include <camlib.h>
#endif /* __FreeBSD__ */

#ifdef HAVE_SYS_CDIO_H
#include <sys/cdio.h>
#endif

#include <glib.h>
#include <glib/gstdio.h>
#include <glib/gi18n.h>
#include <gdk/gdk.h>

#include <libhal.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>

#include "nautilus-burn-drive.h"
#include "nautilus-burn-drive-private.h"

#ifndef INVALID_HANDLE
#define INVALID_HANDLE (GINT_TO_POINTER(-1))
#endif

#define CDS_NO_INFO           0     /* if not implemented */
#define CDS_AUDIO       100
#define CDS_DATA_1            101
#define CDS_DATA_2            102
#define CDS_XA_2_1            103
#define CDS_XA_2_2            104
#define CDS_MIXED       105

#define NAUTILUS_BURN_DRIVE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NAUTILUS_BURN_TYPE_DRIVE, NautilusBurnDrivePrivate))

/* Signals */
enum {
      MEDIA_ADDED,
      MEDIA_REMOVED,
      DISCONNECTED,
      LAST_SIGNAL
};

enum {
        PROP_0,
      PROP_MONITOR_ENABLED,
};

static int nautilus_burn_drive_table_signals [LAST_SIGNAL] = { 0 };

G_DEFINE_TYPE(NautilusBurnDrive, nautilus_burn_drive, G_TYPE_OBJECT);

/* Media capacities, someone please check them */
static struct _media_capacity {
      NautilusBurnMediaType  type;
      guint64                  capacity;
} media_capacity[] = {
      { NAUTILUS_BURN_MEDIA_TYPE_CD,                  838860800LL  },
      { NAUTILUS_BURN_MEDIA_TYPE_DVD,                 4700000000LL },

      /* DVD RAM 1.0 holds 2.58 GB,
       * DVD RAM 2.0 holds 4.7 GB, let's assume the bigger one */
      { NAUTILUS_BURN_MEDIA_TYPE_DVD_RAM,       4700000000LL },
      { NAUTILUS_BURN_MEDIA_TYPE_DVD_PLUS_R_DL, 9183000000LL },
};

#ifdef __FreeBSD__

#define get_ioctl_handle_fd(x) (((struct cam_device *)x)->fd)

static gpointer
open_ioctl_handle (const char *device)
{
      struct cam_device *cam;

      cam = cam_open_device (device, O_RDWR);

      return (cam ? (gpointer)cam : INVALID_HANDLE);
}

static void
close_ioctl_handle (gpointer handle)
{
      cam_close_device ((struct cam_device *)handle);
}

#else

#define get_ioctl_handle_fd(x) (GPOINTER_TO_INT(x))

static gpointer
open_ioctl_handle (const char *device)
{
      int fd;

      if ((fd = g_open (device, O_RDWR | O_EXCL | O_NONBLOCK, 0)) < 0
          && (fd = g_open (device, O_RDONLY | O_EXCL | O_NONBLOCK, 0)) < 0
          && (fd = g_open (device, O_RDONLY | O_NONBLOCK, 0)) < 0) {

            return INVALID_HANDLE;
      }

      return GINT_TO_POINTER (fd);
}

static void
close_ioctl_handle (gpointer handle)
{
      close (GPOINTER_TO_INT (handle));
}

#endif

/**
 * nautilus_burn_drive_get_max_speed_write:
 * @drive: #NautilusBurnDrive
 *
 * Get the maximum write speed that the drive is capable of
 *
 * Returns: The speed of the drive, in device units.
 *
 * Since: 2.14
 **/
int
nautilus_burn_drive_get_max_speed_write (NautilusBurnDrive *drive)
{
      int speed;

      g_return_val_if_fail (drive != NULL, -1);

      speed = drive->priv->max_speed_write;

      return speed;
}

/**
 * nautilus_burn_drive_get_max_speed_read:
 * @drive: #NautilusBurnDrive
 *
 * Get the maximum read speed that the drive is capable of
 *
 * Returns: The speed of the drive, in device units.
 *
 * Since: 2.14
 **/
int
nautilus_burn_drive_get_max_speed_read (NautilusBurnDrive *drive)
{
      int speed;

      g_return_val_if_fail (drive != NULL, -1);

      speed = drive->priv->max_speed_read;

      return speed;
}

/**
 * nautilus_burn_drive_get_max_write_speeds:
 * @drive: #NautilusBurnDrive
 *
 * Get the list of supported write speeds
 *
 * Returns: The write speeds of the drive, in device units, as a
 * zero-terminated array of integers.  The array is sorted in
 * descending order and has no duplicate entries.
 *
 * Since: 2.14
 **/
const int *
nautilus_burn_drive_get_write_speeds (NautilusBurnDrive *drive)
{
      const int *speeds;

      g_return_val_if_fail (drive != NULL, NULL);

      speeds = drive->priv->write_speeds;

      return speeds;
}

/**
 * nautilus_burn_drive_get_name_for_display:
 * @drive: #NautilusBurnDrive
 *
 * Get the name of the drive for use in a user interface
 *
 * Returns: name of the drive.  Must be freed with g_free().
 *
 * Since: 2.14
 **/
char *
nautilus_burn_drive_get_name_for_display (NautilusBurnDrive *drive)
{
      char *name;

      g_return_val_if_fail (drive != NULL, NULL);

      name = g_strdup (drive->priv->display_name);

      return name;
}

/**
 * nautilus_burn_drive_get_device:
 * @drive: #NautilusBurnDrive
 *
 * Get the name of the device associated with the drive.
 *
 * Returns: device name.  Must be not be freed.
 *
 * Since: 2.16
 **/
const char *
nautilus_burn_drive_get_device (NautilusBurnDrive *drive)
{
      g_return_val_if_fail (drive != NULL, NULL);

      return drive->priv->device;
}

/**
 * nautilus_burn_drive_get_drive_type:
 * @drive: #NautilusBurnDrive
 *
 * Get the type of the drive.
 *
 * Returns: type of drive
 *
 * Since: 2.16
 **/
int
nautilus_burn_drive_get_drive_type (NautilusBurnDrive *drive)
{
      g_return_val_if_fail (drive != NULL, 0);

      return drive->priv->type;
}

/**
 * nautilus_burn_drive_can_rewrite:
 * @drive: #NautilusBurnDrive
 *
 * Report the whether the drive is capable of re-recording
 *
 * Returns: %TRUE if the drive can rewrite, otherwise return %FALSE.
 *
 * Since: 2.14
 **/
gboolean
nautilus_burn_drive_can_rewrite (NautilusBurnDrive *drive)
{
      int      type;
      gboolean can_rewrite;

      g_return_val_if_fail (drive != NULL, FALSE);

      type = drive->priv->type;

      can_rewrite = (type & NAUTILUS_BURN_DRIVE_TYPE_CDRW_RECORDER
                   || type & NAUTILUS_BURN_DRIVE_TYPE_DVD_RW_RECORDER
                   || type & NAUTILUS_BURN_DRIVE_TYPE_DVD_PLUS_RW_RECORDER);

      return can_rewrite;
}

/**
 * nautilus_burn_drive_can_write:
 * @drive: #NautilusBurnDrive
 *
 * Report the whether the drive is capable of recording
 *
 * Returns: %TRUE if the drive is a recorder, otherwise return %FALSE.
 *
 * Since: 2.14
 **/
gboolean
nautilus_burn_drive_can_write (NautilusBurnDrive *drive)
{
      int      type;
      gboolean can_write;
      gboolean can_rewrite;

      g_return_val_if_fail (drive != NULL, FALSE);

      type = drive->priv->type;

      /* Handle rewritables first */
      can_rewrite = nautilus_burn_drive_can_rewrite (drive);
      if (can_rewrite)
            return TRUE;

      /* now only handle non-rewritables */
      can_write = (type & NAUTILUS_BURN_DRIVE_TYPE_FILE
                 || type & NAUTILUS_BURN_DRIVE_TYPE_CD_RECORDER
                 || type & NAUTILUS_BURN_DRIVE_TYPE_DVD_RAM_RECORDER
                 || type & NAUTILUS_BURN_DRIVE_TYPE_DVD_PLUS_R_RECORDER
                 || type & NAUTILUS_BURN_DRIVE_TYPE_DVD_PLUS_R_DL_RECORDER);

      return can_write;
}

static gboolean
drive_door_is_open (int fd)
{
      if (fd < 0) {
            return FALSE;
      }

#ifdef __linux__
      {
            int status;

            status = ioctl (fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
            if (status < 0) {
                  return FALSE;
            }

            return status == CDS_TRAY_OPEN;
      }
#else
      return FALSE;
#endif
}

/**
 * nautilus_burn_drive_door_is_open:
 * @drive: #NautilusBurnDrive
 *
 * Report the whether the drive door or tray is open.
 *
 * Returns: %TRUE if the drive door is open, otherwise return %FALSE.
 *
 * Since: 2.12
 **/
gboolean
nautilus_burn_drive_door_is_open (NautilusBurnDrive *drive)
{
      gpointer ioctl_handle;
      int      fd;
      gboolean ret;

      g_return_val_if_fail (drive != NULL, FALSE);

      ioctl_handle = open_ioctl_handle (drive->priv->device);
      if (ioctl_handle == INVALID_HANDLE)
            return FALSE;

      fd = get_ioctl_handle_fd (ioctl_handle);

      ret = drive_door_is_open (fd);

      close_ioctl_handle (ioctl_handle);

      return ret;
}

/**
 * nautilus_burn_drive_get_media_type:
 * @drive: #NautilusBurnDrive
 *
 * Determine the type of the media in the drive @drive.
 *
 * Return value: The #NautilusBurnMediaType of the media in the drive or the
 * following special values:
 *
 *    %NAUTILUS_BURN_MEDIA_TYPE_ERROR   if the type can not be determined
 *    %NAUTILUS_BURN_MEDIA_TYPE_UNKNOWN if the type can not be determined
 *    %NAUTILUS_BURN_MEDIA_TYPE_BUSY    if the device is busy
 **/
NautilusBurnMediaType
nautilus_burn_drive_get_media_type (NautilusBurnDrive *drive)
{
      g_return_val_if_fail (drive != NULL, NAUTILUS_BURN_MEDIA_TYPE_ERROR);

      return nautilus_burn_drive_get_media_type_full (drive, NULL, NULL, NULL, NULL);
}

static NautilusBurnMediaType
nautilus_burn_drive_hal_get_media_type_full (NautilusBurnDrive *drive,
                                   gboolean          *is_rewritable,
                                   gboolean          *is_blank,
                                   gboolean          *has_data,
                                   gboolean          *has_audio)
{

      if (is_rewritable)
            *is_rewritable = FALSE;
      if (is_blank)
            *is_blank = FALSE;
      if (has_data)
            *has_data = FALSE;
      if (has_audio)
            *has_audio = FALSE;

      if (drive->priv->drive_udi == NULL) {
            goto fallback;
      }

      if (drive->priv->media_udi == NULL) {
            goto fallback;
      }

      if (is_rewritable)
            *is_rewritable = drive->priv->is_rewritable;
      if (is_blank)
            *is_blank = drive->priv->is_blank;
      if (has_data)
            *has_data = drive->priv->has_data;
      if (has_audio)
            *has_audio = drive->priv->has_audio;

      return drive->priv->media_type;

 fallback:
      return NAUTILUS_BURN_MEDIA_TYPE_ERROR;
}

/**
 * nautilus_burn_drive_get_media_type_full:
 * @drive: #NautilusBurnDrive
 * @is_rewritable: set to TRUE if media is rewritable
 * @is_blank: set to TRUE if media is blank
 * @has_data: set to TRUE if media has data
 * @has_audio: set to TRUE if media has audio
 *
 * Determine the type of the media in the drive @drive
 *
 * Return value: See nautilus_burn_drive_get_media_type() for details.
 **/
NautilusBurnMediaType
nautilus_burn_drive_get_media_type_full (NautilusBurnDrive *drive,
                               gboolean          *is_rewritable,
                               gboolean          *is_blank,
                               gboolean          *has_data,
                               gboolean          *has_audio)
{
      g_return_val_if_fail (drive != NULL, NAUTILUS_BURN_MEDIA_TYPE_ERROR);

      return nautilus_burn_drive_hal_get_media_type_full (drive,
                                              is_rewritable,
                                              is_blank,
                                              has_data,
                                              has_audio);
}

/**
 * nautilus_burn_drive_get_media_size:
 * @drive: #NautilusBurnDrive
 *
 * Determine the size of the media (i.e. amount of data that the disc
 * contains) in the specified drive.
 *
 * Return value: The size of the media in bytes or the
 * following special values:
 *
 *    %NAUTILUS_BURN_MEDIA_SIZE_UNKNOWN if the type can not be determined
 *    %0                                if the disc is blank
 **/
gint64
nautilus_burn_drive_get_media_size (NautilusBurnDrive *drive)
{
      return drive->priv->media_size;
}

/**
 * nautilus_burn_drive_get_media_capacity:
 * @drive: #NautilusBurnDrive
 *
 * Determine the capacity of the media (i.e. amount of data that the disc
 * can hold) in the specified drive.
 *
 * Return value: The capacity of the media in bytes or the
 * following special values:
 *
 *    %NAUTILUS_BURN_MEDIA_SIZE_UNKNOWN if the type can not be determined
 *    %NAUTILUS_BURN_MEDIA_SIZE_NA      if the device type is not recognized
 *    %NAUTILUS_BURN_MEDIA_SIZE_BUSY    if the device is busy
 **/
gint64
nautilus_burn_drive_get_media_capacity (NautilusBurnDrive *drive)
{
      g_return_val_if_fail (drive != NULL, NAUTILUS_BURN_MEDIA_SIZE_UNKNOWN);

      return drive->priv->media_capacity;
}

/**
 * nautilus_burn_drive_get_media_label:
 * @drive: #NautilusBurnDrive
 *
 * Determine the label of the media in the specified drive.
 *
 * Return value: The label of the media.
 *
 * Since: 2.14
 **/
char *
nautilus_burn_drive_get_media_label (NautilusBurnDrive *drive)
{
      g_return_val_if_fail (drive != NULL, NULL);

      return g_strdup (drive->priv->media_label);
}

typedef struct {
      gboolean    timeout;
      gboolean    unmount_ok;
      guint       timeout_tag;
      GMainLoop  *loop;
      GPtrArray  *argv;
} UnmountData;

static void
free_unmount_data (UnmountData *unmount_data)
{
      g_ptr_array_foreach (unmount_data->argv, (GFunc)g_free, NULL);
      g_ptr_array_free (unmount_data->argv, TRUE);

      g_free (unmount_data);
}

static gboolean
unmount_done (gpointer data)
{
      UnmountData *unmount_data;
      unmount_data = data;

      if (unmount_data->timeout_tag != 0) {
            g_source_remove (unmount_data->timeout_tag);
      }

      if (unmount_data->loop != NULL &&
          g_main_loop_is_running (unmount_data->loop)) {
            g_main_loop_quit (unmount_data->loop);
      }

      if (unmount_data->timeout) {
            /* We timed out, so unmount_data wasn't freed
               at mainloop exit. */
            free_unmount_data (unmount_data);
      }

      return FALSE;
}

static gboolean
unmount_timeout (gpointer data)
{
      UnmountData *unmount_data;
      unmount_data = data;

      /* We're sure, the callback hasn't been run, so just say
         we were interrupted and return from the mainloop */

      unmount_data->unmount_ok = FALSE;
      unmount_data->timeout_tag = 0;
      unmount_data->timeout = TRUE;

      if (g_main_loop_is_running (unmount_data->loop)) {
            g_main_loop_quit (unmount_data->loop);
      }

      return FALSE;
}

#ifndef USE_GNOME_MOUNT
static const char *umount_known_locations [] = {
      "/sbin/umount",
      "/bin/umount",
      "/usr/sbin/umount",
      "/usr/bin/umount",
      NULL
};
#endif

/* Returns the full command */
static GPtrArray *
create_command (const char *device)
{
      GPtrArray *argv;
      char      *str;

      argv = g_ptr_array_new ();

#ifdef USE_GNOME_MOUNT
      str = g_strdup (BINDIR "/gnome-mount");
      g_ptr_array_add (argv, str);
      str = g_strdup_printf ("--device=%s", device);
      g_ptr_array_add (argv, str);
      str = g_strdup ("--unmount");
      g_ptr_array_add (argv, str);
      str = g_strdup ("--block");
      g_ptr_array_add (argv, str);
      str = g_strdup ("--no-ui");
      g_ptr_array_add (argv, str);
#else
      {
            int   i;

            str = NULL;
            for (i = 0; umount_known_locations [i]; i++){
                  if (g_file_test (umount_known_locations [i], G_FILE_TEST_EXISTS)) {
                        str = g_strdup (umount_known_locations [i]);
                        break;
                  }
            }

            /* no path then try just command */
            if (str == NULL) {
                  str = g_strdup ("umount");
            }

            g_ptr_array_add (argv, str);
            str = g_strdup_printf ("%s", device);
            g_ptr_array_add (argv, str);
      }
#endif

      g_ptr_array_add (argv, NULL);

      return argv;
}

static void *
unmount_thread_start (void *arg)
{
      GError      *error;
      UnmountData *data;
      gint         exit_status;
      char        *envp [] = {
            "LC_ALL=C",
            NULL
      };

      data = arg;

      data->unmount_ok = TRUE;

      error = NULL;
      if (g_spawn_sync (NULL,
                    (char **)data->argv->pdata,
                    envp,
                    G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
                    NULL, NULL,
                    NULL,
                    NULL,
                    &exit_status,
                    &error)) {
            if (exit_status == 0) {
                  data->unmount_ok = TRUE;
            } else {
                  data->unmount_ok = FALSE;
            }

            /* Delay a bit to make sure unmount finishes */
            sleep (1);
      } else {
            /* spawn failure */
            if (error) {
                  g_warning ("Unable to unmount: %s", error->message);
                  g_error_free (error);
            }
            data->unmount_ok = FALSE;
      }

      g_idle_add (unmount_done, data);

      g_thread_exit (NULL);

      return NULL;
}

/**
 * nautilus_burn_drive_unmount:
 * @drive: #NautilusBurnDrive
 *
 * Unmount the media in a #NautilusBurnDrive.
 *
 * Return value: %TRUE if the media was sucessfully unmounted, %FALSE otherwise.
 *
 * Since: 2.10
 **/
gboolean
nautilus_burn_drive_unmount (NautilusBurnDrive *drive)
{
      UnmountData *data;
      gboolean     unmount_ok;

      g_return_val_if_fail (drive != NULL, FALSE);

      if (drive->priv->device == NULL)
            return FALSE;

      unmount_ok = FALSE;

      data = g_new0 (UnmountData, 1);
      data->loop = g_main_loop_new (NULL, FALSE);

      data->timeout_tag = g_timeout_add (5 * 1000,
                                 unmount_timeout,
                                 data);
      data->argv = create_command (drive->priv->device);

      g_thread_create (unmount_thread_start, data, FALSE, NULL);

      GDK_THREADS_LEAVE ();
      g_main_loop_run (data->loop);
      GDK_THREADS_ENTER ();

      g_main_loop_unref (data->loop);
      data->loop = NULL;

      unmount_ok = data->unmount_ok;

      if (!data->timeout) {
            /* Don't free data if mount operation still running. */
            free_unmount_data (data);
      }

      return unmount_ok;
}

/**
 * nautilus_burn_drive_is_mounted:
 * @drive: #NautilusBurnDrive
 *
 * Determine if media in the specified drive is mounted.
 *
 * Return value: %TRUE if the media is mounted, %FALSE otherwise.
 *
 * Since: 2.14
 **/
gboolean
nautilus_burn_drive_is_mounted (NautilusBurnDrive *drive)
{
      g_return_val_if_fail (drive != NULL, FALSE);

      return drive->priv->media_is_mounted;
}

/**
 * nautilus_burn_drive_eject:
 * @drive: #NautilusBurnDrive
 *
 * Eject media from a #NautilusBurnDrive.
 *
 * Return value: %TRUE if the media was sucessfully ejected, %FALSE otherwise.
 *
 * Since: 2.12
 **/
gboolean
nautilus_burn_drive_eject (NautilusBurnDrive *drive)
{
      char    *cmd;
      gboolean res;

      g_return_val_if_fail (drive != NULL, FALSE);

      if (drive->priv->device == NULL) {
            return FALSE;
      }

#ifdef USE_GNOME_MOUNT
      cmd = g_strdup_printf ("gnome-mount --block --eject --no-ui --device=%s", drive->priv->device);
#else
      cmd = g_strdup_printf ("eject %s", drive->priv->device);
#endif

      res = g_spawn_command_line_sync (cmd, NULL, NULL, NULL, NULL);
      g_free (cmd);

      /* delay a bit to make sure eject finishes */
      sleep (1);

      return res;
}

/**
 * nautilus_burn_drive_unref:
 * @drive: #NautilusBurnDrive
 *
 * Decrement the refcount of @drive.
 *
 * Since: 2.14
 **/
void
nautilus_burn_drive_unref (NautilusBurnDrive *drive)
{
      if (drive == NULL) {
            return;
      }

      g_object_unref (drive);
}

/**
 * nautilus_burn_drive_ref:
 * @drive: #NautilusBurnDrive
 *
 * Increment the refcount of @drive.
 *
 * Return value: #NautilusBurnDrive
 *
 * Since: 2.14
 **/
NautilusBurnDrive *
nautilus_burn_drive_ref (NautilusBurnDrive *drive)
{
      if (drive == NULL) {
            return NULL;
      }

      g_object_ref (drive);

      return drive;
}

static LibHalContext *
get_hal_context (void)
{
      static LibHalContext *ctx = NULL;
      DBusError         error;
      DBusConnection         *dbus_conn;

      if (ctx == NULL) {
            ctx = libhal_ctx_new ();
            if (ctx == NULL) {
                  g_warning ("Could not create a HAL context");
            } else {
                  dbus_error_init (&error);
                  dbus_conn = dbus_bus_get (DBUS_BUS_SYSTEM, &error);

                  if (dbus_error_is_set (&error)) {
                        g_warning ("Could not connect to system bus: %s", error.message);
                        dbus_error_free (&error);
                        return NULL;
                  }

                  libhal_ctx_set_dbus_connection (ctx, dbus_conn);

                  if (! libhal_ctx_init (ctx, &error)) {
                        g_warning ("Could not initalize the HAL context: %s",
                                 error.message);

                        if (dbus_error_is_set (&error))
                              dbus_error_free (&error);

                        libhal_ctx_free (ctx);
                        ctx = NULL;
                  }
            }
      }

      return ctx;
}

/**
 * nautilus_burn_drive_lock:
 * @drive: Pointer to a #NautilusBurnDrive
 * @reason:
 * @reason_for_failure:
 *
 * Lock a #NautilusBurnDrive
 *
 * Return value: %TRUE if the drive was sucessfully locked, %FALSE otherwise.
 *
 * Since: 2.8
 **/
gboolean
nautilus_burn_drive_lock (NautilusBurnDrive *drive,
                    const char        *reason,
                    char             **reason_for_failure)
{
      gboolean res;

      if (reason_for_failure != NULL)
            *reason_for_failure = NULL;

      res = TRUE;
      if (drive->priv->drive_udi != NULL) {
            LibHalContext *ctx;
            char          *dbus_reason;
            DBusError      error;

            dbus_error_init (&error);
            ctx = get_hal_context ();

            if (ctx != NULL) {
                  res = libhal_device_lock (ctx,
                                      drive->priv->drive_udi,
                                      reason,
                                      &dbus_reason,
                                      &error);

                  if (dbus_error_is_set (&error))
                        dbus_error_free (&error);

                  if (dbus_reason != NULL &&
                      reason_for_failure != NULL)
                        *reason_for_failure = g_strdup (dbus_reason);
                  if (dbus_reason != NULL)
                        dbus_free (dbus_reason);
            }
      }

      return res;
}

/**
 * nautilus_burn_drive_unlock:
 * @drive: Pointer to a #NautilusBurnDrive
 *
 * Unlock a #NautilusBurnDrive
 *
 * Return value: %TRUE if the drive was sucessfully unlocked, %FALSE otherwise.
 *
 * Since: 2.8
 **/
gboolean
nautilus_burn_drive_unlock (NautilusBurnDrive *drive)
{
      gboolean res;

      res = TRUE;

      if (drive->priv->drive_udi != NULL) {
            LibHalContext *ctx;
            DBusError      error;

            dbus_error_init (&error);
            ctx = get_hal_context ();

            if (ctx != NULL) {
                  res = libhal_device_unlock (ctx,
                                        drive->priv->drive_udi,
                                        &error);

                  if (dbus_error_is_set (&error))
                        dbus_error_free (&error);
            }
      }

      return res;
}

void
_nautilus_burn_drive_media_added (NautilusBurnDrive *drive)
{
      g_signal_emit (drive, nautilus_burn_drive_table_signals [MEDIA_ADDED], 0);
}

void
_nautilus_burn_drive_media_removed (NautilusBurnDrive *drive)
{
      g_signal_emit (drive, nautilus_burn_drive_table_signals [MEDIA_REMOVED], 0);
}

void
_nautilus_burn_drive_disconnected (NautilusBurnDrive *drive)
{
      g_signal_emit (drive, nautilus_burn_drive_table_signals [DISCONNECTED], 0);
}

static void
nautilus_burn_drive_finalize (GObject *object)
{
      NautilusBurnDrive *drive = NAUTILUS_BURN_DRIVE (object);

      g_return_if_fail (object != NULL);

      g_free (drive->priv->drive_udi);
      g_free (drive->priv->media_udi);

      g_free (drive->priv->media_label);

      g_free (drive->priv->write_speeds);
      g_free (drive->priv->display_name);
      g_free (drive->priv->device);

      if (G_OBJECT_CLASS (nautilus_burn_drive_parent_class)->finalize != NULL) {
            (* G_OBJECT_CLASS (nautilus_burn_drive_parent_class)->finalize) (object);
      }
}

static void
nautilus_burn_drive_init (NautilusBurnDrive *drive)
{
      drive->priv = NAUTILUS_BURN_DRIVE_GET_PRIVATE (drive);

      drive->priv->type            = 0;
      drive->priv->display_name    = NULL;
      drive->priv->max_speed_write = 0;
      drive->priv->max_speed_read  = 0;
      drive->priv->write_speeds    = NULL;
      drive->priv->device          = NULL;
}

/**
 * _nautilus_burn_drive_new:
 *
 * Create a new #NautilusBurnDrive.
 *
 * Return value: The new drive.
 *
 * Since: 2.8
 **/
NautilusBurnDrive *
_nautilus_burn_drive_new (void)
{
      return g_object_new (NAUTILUS_BURN_TYPE_DRIVE, NULL);
}

/**
 * nautilus_burn_drive_equal:
 * @a: First #NautilusBurnDrive struct to compare
 * @b: Second #NautilusBurnDrive struct to compare
 *
 * Compare the two cd drives, return %TRUE if they match exactly
 * the same drive.
 *
 * Returns: %TRUE if the two #NautilusBurnDrives are equal, otherwise return %FALSE.
 *
 * Since: 2.8
 **/
gboolean
nautilus_burn_drive_equal (NautilusBurnDrive *a,
                     NautilusBurnDrive *b)
{
      if (!a || !b)
            return FALSE;

      if ((a->priv->type & NAUTILUS_BURN_DRIVE_TYPE_FILE)
          && (b->priv->type & NAUTILUS_BURN_DRIVE_TYPE_FILE))
            return TRUE;

      if (!a->priv->device || !b->priv->device)
            return FALSE;

      return strcmp (a->priv->device, b->priv->device) == 0;
}

static void
add_desc (GString    *string,
        const char *addition)
{
      if (strcmp (string->str, "") == 0) {
            g_string_append_printf (string, "%s", addition);
      } else {
            g_string_append_printf (string, ", %s", addition);
      }
}

#define NCBD_ADD_TYPE_DESC(_t_, _desc_) if (type & _t_) add_desc (string, _desc_)

/**
 * nautilus_burn_drive_get_supported_media_string:
 * @drive: A #NautilusBurnDrive
 * @writable_only: Set to %TRUE if only writable media should be displayed
 *
 * Get a string description of the supported media types.  The
 * returned string should be freed when no longer needed.
 *
 * Returns: a string description of the supported media types
 *
 * Since: 2.14
 **/
char *
nautilus_burn_drive_get_supported_media_string (NautilusBurnDrive *drive,
                                    gboolean           writable_only)
{
      GString *string;
      int      type;

      type = drive->priv->type;

      string = g_string_new (NULL);

      NCBD_ADD_TYPE_DESC (NAUTILUS_BURN_DRIVE_TYPE_FILE, "File");

      NCBD_ADD_TYPE_DESC (NAUTILUS_BURN_DRIVE_TYPE_CD_RECORDER, "CD-R");
      NCBD_ADD_TYPE_DESC (NAUTILUS_BURN_DRIVE_TYPE_CDRW_RECORDER, "CD-RW");
      NCBD_ADD_TYPE_DESC (NAUTILUS_BURN_DRIVE_TYPE_DVD_RAM_RECORDER, "DVD-RAM");
      NCBD_ADD_TYPE_DESC (NAUTILUS_BURN_DRIVE_TYPE_DVD_RW_RECORDER, "DVD-R, DVD-RW");
      NCBD_ADD_TYPE_DESC (NAUTILUS_BURN_DRIVE_TYPE_DVD_PLUS_R_RECORDER, "DVD+R");
      NCBD_ADD_TYPE_DESC (NAUTILUS_BURN_DRIVE_TYPE_DVD_PLUS_R_DL_RECORDER, "DVD+R DL");
      NCBD_ADD_TYPE_DESC (NAUTILUS_BURN_DRIVE_TYPE_DVD_PLUS_RW_RECORDER, "DVD+RW");

      if (! writable_only) {
            NCBD_ADD_TYPE_DESC (NAUTILUS_BURN_DRIVE_TYPE_CD_DRIVE, "CD");
            NCBD_ADD_TYPE_DESC (NAUTILUS_BURN_DRIVE_TYPE_DVD_DRIVE, "DVD");
      }

      return g_string_free (string, FALSE);
}

static guint64
nautilus_burn_drive_media_type_get_capacity (NautilusBurnMediaType type)
{
      int         i;
      int         size;
      gboolean    found  = FALSE;

      size = sizeof (media_capacity);

      for (i = 0; i < size && ! found; i++) {

            if (media_capacity[i].type == type) {
                  found = TRUE;

                  break;
            }
      }

      return found ? media_capacity[i].capacity : 0;
}

/* Adds decription _desc_ to @string if _is_big_enough is TRUE
 * else it returns @string */
#define NCBD_ADD_TYPE_DESC_IF_FITS(_t_, _is_big_enough_, _desc_)                                \
                                          do                                        \
                                          {                                         \
                                          if (type & (_t_)) {                             \
                                              if ((_is_big_enough_)) add_desc (string, (_desc_));     \
                                              else return g_string_free (string, FALSE);        \
                                          }                                         \
                                          }                                         \
                                          while (0)                                 \

/**
 * nautilus_burn_drive_get_supported_media_string_for_size:
 * @drive: A #NautilusBurnDrive
 * @size: Data size
 *
 * Get a string description of the suiting media types for the given
 * data size. The returned string should be freed when no longer needed.
 *
 * Returns: a string description of the supported media types
 *
 * Since: 2.16
 **/
char *
nautilus_burn_drive_get_supported_media_string_for_size (NautilusBurnDrive *drive,
                                           guint64        size)
{
      GString *string;
      int      type;

/* Reserve some space for the filesystem and stuff. */
#define MARGIN  (1024 * 1024)

      size += MARGIN;

      type = nautilus_burn_drive_get_drive_type (drive);

      string = g_string_new (NULL);

      /* Check bigger media types first, in decreasing order:
       * NCBD_ADD_TYPE_IF_FITS () make us return if the media
       * is not big enough. */

      NCBD_ADD_TYPE_DESC_IF_FITS (NAUTILUS_BURN_DRIVE_TYPE_FILE, TRUE, "File");

      /* DVDs DL */
      NCBD_ADD_TYPE_DESC_IF_FITS (NAUTILUS_BURN_DRIVE_TYPE_DVD_PLUS_R_DL_RECORDER,
                            size < nautilus_burn_drive_media_type_get_capacity (NAUTILUS_BURN_MEDIA_TYPE_DVD_PLUS_R_DL),
                            "DVD+R DL");

      /* DVDs */
      NCBD_ADD_TYPE_DESC_IF_FITS (NAUTILUS_BURN_DRIVE_TYPE_DVD_RAM_RECORDER,
                            size < nautilus_burn_drive_media_type_get_capacity (NAUTILUS_BURN_MEDIA_TYPE_DVD),
                            "DVD-RAM");
      NCBD_ADD_TYPE_DESC_IF_FITS (NAUTILUS_BURN_DRIVE_TYPE_DVD_RW_RECORDER,
                            size < nautilus_burn_drive_media_type_get_capacity (NAUTILUS_BURN_MEDIA_TYPE_DVD),
                            "DVD-R, DVD-RW");
      NCBD_ADD_TYPE_DESC_IF_FITS (NAUTILUS_BURN_DRIVE_TYPE_DVD_PLUS_R_RECORDER,
                            size < nautilus_burn_drive_media_type_get_capacity (NAUTILUS_BURN_MEDIA_TYPE_DVD),
                            "DVD+R");
      NCBD_ADD_TYPE_DESC_IF_FITS (NAUTILUS_BURN_DRIVE_TYPE_DVD_PLUS_RW_RECORDER,
                            size < nautilus_burn_drive_media_type_get_capacity (NAUTILUS_BURN_MEDIA_TYPE_DVD),
                            "DVD+RW");

      /* CDs */
      NCBD_ADD_TYPE_DESC_IF_FITS (NAUTILUS_BURN_DRIVE_TYPE_CD_RECORDER,
                            size < nautilus_burn_drive_media_type_get_capacity (NAUTILUS_BURN_MEDIA_TYPE_CD),
                            "CD-R");
      NCBD_ADD_TYPE_DESC_IF_FITS (NAUTILUS_BURN_DRIVE_TYPE_CDRW_RECORDER,
                            size < nautilus_burn_drive_media_type_get_capacity (NAUTILUS_BURN_MEDIA_TYPE_CD),
                            "CD-RW");


      return g_string_free (string, FALSE);
}

/**
 * nautilus_burn_drive_media_type_get_string:
 * @type: A #NautilusBurnMediaType
 *
 * Get a string description of the specified media type.
 *
 * Returns: a string description for the media type.
 *
 * Since: 2.12
 **/
const char *
nautilus_burn_drive_media_type_get_string (NautilusBurnMediaType type)
{
      switch (type) {
      case NAUTILUS_BURN_MEDIA_TYPE_BUSY:
            return _("Could not determine media type because CD drive is busy");
      case NAUTILUS_BURN_MEDIA_TYPE_ERROR:
            return _("Couldn't open media");
      case NAUTILUS_BURN_MEDIA_TYPE_UNKNOWN:
            return _("Unknown Media");
      case NAUTILUS_BURN_MEDIA_TYPE_CD:
            return _("Commercial CD or Audio CD");
      case NAUTILUS_BURN_MEDIA_TYPE_CDR:
            return _("CD-R");
      case NAUTILUS_BURN_MEDIA_TYPE_CDRW:
            return _("CD-RW");
      case NAUTILUS_BURN_MEDIA_TYPE_DVD:
            return _("DVD");
      case NAUTILUS_BURN_MEDIA_TYPE_DVDR:
            return _("DVD-R, or DVD-RAM");
      case NAUTILUS_BURN_MEDIA_TYPE_DVDRW:
            return _("DVD-RW");
      case NAUTILUS_BURN_MEDIA_TYPE_DVD_RAM:
            return _("DVD-RAM");
      case NAUTILUS_BURN_MEDIA_TYPE_DVD_PLUS_R:
            return _("DVD+R");
      case NAUTILUS_BURN_MEDIA_TYPE_DVD_PLUS_RW:
            return _("DVD+RW");
      case NAUTILUS_BURN_MEDIA_TYPE_DVD_PLUS_R_DL:
            return _("DVD+R DL");
      default:
            break;
      }

      return _("Broken media type");
}

/**
 * nautilus_burn_drive_media_type_is_writable
 * @type: A #NautilusBurnMediaType
 * @is_blank: if the media type is blank or not
 *
 * Determine if a media type is writable
 *
 * Returns: %TRUE if the media type can be written to, otherwise return %FALSE.
 *
 * Since: 2.14
 **/
gboolean
nautilus_burn_drive_media_type_is_writable (NautilusBurnMediaType type,
                                  gboolean              is_blank)
{
      gboolean can_write;

      can_write = FALSE;

      switch (type) {
      case NAUTILUS_BURN_MEDIA_TYPE_BUSY:
      case NAUTILUS_BURN_MEDIA_TYPE_ERROR:
      case NAUTILUS_BURN_MEDIA_TYPE_UNKNOWN:
      case NAUTILUS_BURN_MEDIA_TYPE_CD:
      case NAUTILUS_BURN_MEDIA_TYPE_DVD:
      case NAUTILUS_BURN_MEDIA_TYPE_DVD_RAM:
            can_write = FALSE;
            break;
      case NAUTILUS_BURN_MEDIA_TYPE_CDR:
      case NAUTILUS_BURN_MEDIA_TYPE_DVDR:
      case NAUTILUS_BURN_MEDIA_TYPE_DVD_PLUS_R:
      case NAUTILUS_BURN_MEDIA_TYPE_DVD_PLUS_R_DL:
            if (is_blank) {
                  can_write = TRUE;
            } else {
                  can_write = FALSE;
            }
            break;
      case NAUTILUS_BURN_MEDIA_TYPE_CDRW:
      case NAUTILUS_BURN_MEDIA_TYPE_DVDRW:
      case NAUTILUS_BURN_MEDIA_TYPE_DVD_PLUS_RW:
            can_write = TRUE;
            break;
      default:
            g_warning ("Unknown media type: %d", type);
            can_write = FALSE;
            break;
      }

      return can_write;
}

/**
 * nautilus_burn_drive_media_is_appendable
 * @drive: #NautilusBurnDrive
 *
 * Determine if the media in the specified drive is appendable
 *
 * Returns: %TRUE if there is a media and it can be appended, otherwise returns %FALSE.
 *
 * Since: 2.16
 **/
gboolean
nautilus_burn_drive_media_is_appendable (NautilusBurnDrive *drive)
{
      g_return_val_if_fail (NAUTILUS_BURN_IS_DRIVE (drive), FALSE);

      return drive->priv->media_is_appendable;
}

static void
nautilus_burn_drive_set_property (GObject      *object,
                          guint                 prop_id,
                          const GValue         *value,
                          GParamSpec           *pspec)
{
      NautilusBurnDrive *self;

      self = NAUTILUS_BURN_DRIVE (object);

      switch (prop_id) {
      case PROP_MONITOR_ENABLED:
            g_warning ("the enable-monitor property is deprecated and will be removed in the next version");
            break;
      default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
            break;
      }
}

static void
nautilus_burn_drive_get_property (GObject      *object,
                          guint                 prop_id,
                          GValue         *value,
                          GParamSpec           *pspec)
{
      NautilusBurnDrive *self;

      self = NAUTILUS_BURN_DRIVE (object);

      switch (prop_id) {
      case PROP_MONITOR_ENABLED:
            g_warning ("the enable-monitor property is deprecated and will be removed in the next version");
      default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
            break;
      }
}

static void
nautilus_burn_drive_class_init (NautilusBurnDriveClass *klass)
{
      GObjectClass *object_class;

      object_class = (GObjectClass *) klass;

      object_class->finalize = nautilus_burn_drive_finalize;
      object_class->get_property = nautilus_burn_drive_get_property;
      object_class->set_property = nautilus_burn_drive_set_property;

      g_type_class_add_private (klass, sizeof (NautilusBurnDrivePrivate));

      /* Signals */
      nautilus_burn_drive_table_signals [MEDIA_ADDED] =
            g_signal_new ("media-added",
                        G_TYPE_FROM_CLASS (klass),
                        G_SIGNAL_RUN_LAST,
                        G_STRUCT_OFFSET (NautilusBurnDriveClass,
                                     media_added),
                        NULL, NULL,
                        g_cclosure_marshal_VOID__VOID,
                        G_TYPE_NONE, 0);
      nautilus_burn_drive_table_signals [MEDIA_REMOVED] =
            g_signal_new ("media-removed",
                        G_TYPE_FROM_CLASS (klass),
                        G_SIGNAL_RUN_LAST,
                        G_STRUCT_OFFSET (NautilusBurnDriveClass,
                                     media_removed),
                        NULL, NULL,
                        g_cclosure_marshal_VOID__VOID,
                        G_TYPE_NONE, 0);
      nautilus_burn_drive_table_signals [DISCONNECTED] =
            g_signal_new ("disconnected",
                        G_TYPE_FROM_CLASS (klass),
                        G_SIGNAL_RUN_LAST,
                        G_STRUCT_OFFSET (NautilusBurnDriveClass,
                                     disconnected),
                        NULL, NULL,
                        g_cclosure_marshal_VOID__VOID,
                        G_TYPE_NONE, 0);

      /* Properties */

      /* this property is deprecated and will be removed in the next version */
        g_object_class_install_property (object_class,
                                         PROP_MONITOR_ENABLED,
                                         g_param_spec_boolean ("enable-monitor",
                                                               NULL,
                                                               NULL,
                                                               FALSE,
                                                               G_PARAM_READWRITE));
}

Generated by  Doxygen 1.6.0   Back to index