gdrive.c 13.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/* GIO - GLib Input, Output and Streaming Library
 * 
 * Copyright (C) 2006-2007 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * Author: Alexander Larsson <alexl@redhat.com>
21
 *         David Zeuthen <davidz@redhat.com>
22 23
 */

24
#include "config.h"
25 26
#include "gdrive.h"
#include "gsimpleasyncresult.h"
27 28
#include "gasyncresult.h"
#include "gioerror.h"
29 30
#include "glibintl.h"

31 32
#include "gioalias.h"

33 34
/**
 * SECTION:gdrive
35
 * @short_description: Virtual File System drive management
Matthias Clasen's avatar
Matthias Clasen committed
36
 * @include: gio/gio.h
37
 * 
38 39 40 41
 * #GDrive - this represent a piece of hardware connected to the machine.
 * Its generally only created for removable hardware or hardware with
 * removable media. 
 *
42 43 44 45 46 47 48 49 50 51 52 53 54
 * #GDrive is a container class for #GVolume objects that stem from
 * the same piece of media. As such, #GDrive abstracts a drive with
 * (or without) removable media and provides operations for querying
 * whether media is available, determing whether media change is
 * automatically detected and ejecting the media.
 *
 * If the #GDrive reports that media isn't automatically detected, one
 * can poll for media; typically one should not do this periodically
 * as a poll for media operation is potententially expensive and may
 * spin up the drive creating noise.
 *
 * For porting from GnomeVFS note that there is no equivalent of
 * #GDrive in that API.
55 56
 **/

57 58 59 60 61 62 63
static void g_drive_base_init (gpointer g_class);
static void g_drive_class_init (gpointer g_class,
				 gpointer class_data);

GType
g_drive_get_type (void)
{
64
  static volatile gsize g_define_type_id__volatile = 0;
65

66
  if (g_once_init_enter (&g_define_type_id__volatile))
67
    {
68
      const GTypeInfo drive_info =
69 70 71 72 73 74 75 76 77 78 79
      {
        sizeof (GDriveIface), /* class_size */
	g_drive_base_init,   /* base_init */
	NULL,		/* base_finalize */
	g_drive_class_init,
	NULL,		/* class_finalize */
	NULL,		/* class_data */
	0,
	0,              /* n_preallocs */
	NULL
      };
80
      GType g_define_type_id =
81 82 83
	g_type_register_static (G_TYPE_INTERFACE, I_("GDrive"),
				&drive_info, 0);

84 85 86
      g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT);

      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
87 88
    }

89
  return g_define_type_id__volatile;
90 91 92 93
}

static void
g_drive_class_init (gpointer g_class,
Matthias Clasen's avatar
Matthias Clasen committed
94
                    gpointer class_data)
95 96 97 98 99 100 101 102 103 104
{
}

static void
g_drive_base_init (gpointer g_class)
{
  static gboolean initialized = FALSE;

  if (! initialized)
    {
105 106
      /**
      * GDrive::changed:
107
      * @drive: a #GDrive.
108 109 110
      * 
      * Emitted when the drive's state has changed.
      **/
111 112 113 114 115 116 117 118
      g_signal_new (I_("changed"),
                    G_TYPE_DRIVE,
                    G_SIGNAL_RUN_LAST,
                    G_STRUCT_OFFSET (GDriveIface, changed),
                    NULL, NULL,
                    g_cclosure_marshal_VOID__VOID,
                    G_TYPE_NONE, 0);

119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
      /**
      * GDrive::disconnected:
      * @drive: a #GDrive.
      * 
      * This signal is emitted when the #GDrive have been
      * disconnected. If the recipient is holding references to the
      * object they should release them so the object can be
      * finalized.
      **/
      g_signal_new (I_("disconnected"),
                    G_TYPE_DRIVE,
                    G_SIGNAL_RUN_LAST,
                    G_STRUCT_OFFSET (GDriveIface, disconnected),
                    NULL, NULL,
                    g_cclosure_marshal_VOID__VOID,
                    G_TYPE_NONE, 0);

      /**
      * GDrive::eject-button:
      * @drive: a #GDrive.
      * 
Matthias Clasen's avatar
Matthias Clasen committed
140 141
      * Emitted when the physical eject button (if any) of a drive has
      * been pressed.
142 143 144 145 146 147 148 149 150
      **/
      g_signal_new (I_("eject-button"),
                    G_TYPE_DRIVE,
                    G_SIGNAL_RUN_LAST,
                    G_STRUCT_OFFSET (GDriveIface, eject_button),
                    NULL, NULL,
                    g_cclosure_marshal_VOID__VOID,
                    G_TYPE_NONE, 0);

151 152 153 154 155 156 157 158
      initialized = TRUE;
    }
}

/**
 * g_drive_get_name:
 * @drive: a #GDrive.
 * 
Matthias Clasen's avatar
Matthias Clasen committed
159
 * Gets the name of @drive.
160
 *
Matthias Clasen's avatar
Matthias Clasen committed
161 162
 * Returns: a string containing @drive's name. The returned 
 *     string should be freed when no longer needed.
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
 **/
char *
g_drive_get_name (GDrive *drive)
{
  GDriveIface *iface;

  g_return_val_if_fail (G_IS_DRIVE (drive), NULL);

  iface = G_DRIVE_GET_IFACE (drive);

  return (* iface->get_name) (drive);
}

/**
 * g_drive_get_icon:
 * @drive: a #GDrive.
 * 
 * Gets the icon for @drive.
 * 
 * Returns: #GIcon for the @drive.
Matthias Clasen's avatar
Matthias Clasen committed
183
 *    Free the returned object with g_object_unref().
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
 **/
GIcon *
g_drive_get_icon (GDrive *drive)
{
  GDriveIface *iface;
  
  g_return_val_if_fail (G_IS_DRIVE (drive), NULL);

  iface = G_DRIVE_GET_IFACE (drive);

  return (* iface->get_icon) (drive);
}

/**
 * g_drive_has_volumes:
 * @drive: a #GDrive.
 * 
201
 * Check if @drive has any mountable volumes.
202
 * 
203
 * Returns: %TRUE if the @drive contains volumes, %FALSE otherwise.
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
 **/
gboolean
g_drive_has_volumes (GDrive *drive)
{
  GDriveIface *iface;

  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);

  iface = G_DRIVE_GET_IFACE (drive);

  return (* iface->has_volumes) (drive);
}

/**
 * g_drive_get_volumes:
 * @drive: a #GDrive.
 * 
221
 * Get a list of mountable volumes for @drive.
Matthias Clasen's avatar
Matthias Clasen committed
222 223 224
 *
 * The returned list should be freed with g_list_free(), after
 * its elements have been unreffed with g_object_unref().
225
 * 
Matthias Clasen's avatar
Matthias Clasen committed
226
 * Returns: #GList containing any #GVolume objects on the given @drive.
227 228 229 230 231 232 233 234 235 236 237 238 239 240
 **/
GList *
g_drive_get_volumes (GDrive *drive)
{
  GDriveIface *iface;

  g_return_val_if_fail (G_IS_DRIVE (drive), NULL);

  iface = G_DRIVE_GET_IFACE (drive);

  return (* iface->get_volumes) (drive);
}

/**
241
 * g_drive_is_media_check_automatic:
242 243
 * @drive: a #GDrive.
 * 
244
 * Checks if @drive is capabable of automatically detecting media changes.
245
 * 
Matthias Clasen's avatar
Matthias Clasen committed
246 247
 * Returns: %TRUE if the @drive is capabable of automatically detecting 
 *     media changes, %FALSE otherwise.
248 249
 **/
gboolean
250
g_drive_is_media_check_automatic (GDrive *drive)
251 252 253 254 255 256 257
{
  GDriveIface *iface;

  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);

  iface = G_DRIVE_GET_IFACE (drive);

258
  return (* iface->is_media_check_automatic) (drive);
259 260 261
}

/**
262
 * g_drive_is_media_removable:
263 264
 * @drive: a #GDrive.
 * 
265
 * Checks if the @drive supports removable media.
266
 * 
267
 * Returns: %TRUE if @drive supports removable media, %FALSE otherwise.
268 269
 **/
gboolean
270
g_drive_is_media_removable (GDrive *drive)
271 272 273 274 275 276 277
{
  GDriveIface *iface;

  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);

  iface = G_DRIVE_GET_IFACE (drive);

278 279
  return (* iface->is_media_removable) (drive);
}
280

281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
/**
 * g_drive_has_media:
 * @drive: a #GDrive.
 * 
 * Checks if the @drive has media. Note that the OS may not be polling
 * the drive for media changes; see g_drive_is_media_check_automatic()
 * for more details.
 * 
 * Returns: %TRUE if @drive has media, %FALSE otherwise.
 **/
gboolean
g_drive_has_media (GDrive *drive)
{
  GDriveIface *iface;

  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);

  iface = G_DRIVE_GET_IFACE (drive);

  return (* iface->has_media) (drive);
301 302 303 304
}

/**
 * g_drive_can_eject:
Matthias Clasen's avatar
Matthias Clasen committed
305
 * @drive: a #GDrive.
306
 * 
307 308
 * Checks if a drive can be ejected.
 * 
Matthias Clasen's avatar
Matthias Clasen committed
309
 * Returns: %TRUE if the @drive can be ejected, %FALSE otherwise.
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
 **/
gboolean
g_drive_can_eject (GDrive *drive)
{
  GDriveIface *iface;

  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);

  iface = G_DRIVE_GET_IFACE (drive);

  if (iface->can_eject == NULL)
    return FALSE;

  return (* iface->can_eject) (drive);
}

/**
327 328 329 330 331
 * g_drive_can_poll_for_media:
 * @drive: a #GDrive.
 * 
 * Checks if a drive can be polled for media changes.
 * 
Matthias Clasen's avatar
Matthias Clasen committed
332 333
 * Returns: %TRUE if the @drive can be polled for media changes,
 *     %FALSE otherwise.
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
 **/
gboolean
g_drive_can_poll_for_media (GDrive *drive)
{
  GDriveIface *iface;

  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);

  iface = G_DRIVE_GET_IFACE (drive);

  if (iface->poll_for_media == NULL)
    return FALSE;

  return (* iface->can_poll_for_media) (drive);
}

/**
 * g_drive_eject:
352
 * @drive: a #GDrive.
353
 * @flags: flags affecting the unmount if required for eject
354
 * @cancellable: optional #GCancellable object, %NULL to ignore.
355
 * @callback: a #GAsyncReadyCallback, or %NULL.
Matthias Clasen's avatar
Matthias Clasen committed
356
 * @user_data: user data to pass to @callback
357
 * 
Matthias Clasen's avatar
Matthias Clasen committed
358 359 360 361 362
 * Asynchronously ejects a drive.
 *
 * When the operation is finished, @callback will be called.
 * You can then call g_drive_eject_finish() to obtain the
 * result of the operation.
363 364
 **/
void
365
g_drive_eject (GDrive              *drive,
366
	       GMountUnmountFlags   flags,
Matthias Clasen's avatar
Matthias Clasen committed
367 368 369
	       GCancellable        *cancellable,
	       GAsyncReadyCallback  callback,
	       gpointer             user_data)
370 371 372 373 374 375 376
{
  GDriveIface *iface;

  g_return_if_fail (G_IS_DRIVE (drive));

  iface = G_DRIVE_GET_IFACE (drive);

377
  if (iface->eject == NULL)
378 379 380
    {
      g_simple_async_report_error_in_idle (G_OBJECT (drive), callback, user_data,
					   G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
381
					   _("drive doesn't implement eject"));
382 383 384 385
      
      return;
    }
  
386
  (* iface->eject) (drive, flags, cancellable, callback, user_data);
387 388 389
}

/**
Matthias Clasen's avatar
Matthias Clasen committed
390
 * g_drive_eject_finish:
391
 * @drive: a #GDrive.
392
 * @result: a #GAsyncResult.
Matthias Clasen's avatar
Matthias Clasen committed
393
 * @error: a #GError, or %NULL
394
 * 
395
 * Finishes ejecting a drive.
396
 * 
397
 * Returns: %TRUE if the drive has been ejected successfully,
Matthias Clasen's avatar
Matthias Clasen committed
398
 *     %FALSE otherwise.
399 400
 **/
gboolean
401
g_drive_eject_finish (GDrive        *drive,
Matthias Clasen's avatar
Matthias Clasen committed
402 403
		      GAsyncResult  *result,
		      GError       **error)
404 405 406 407 408 409 410 411 412 413 414 415 416 417
{
  GDriveIface *iface;

  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);

  if (G_IS_SIMPLE_ASYNC_RESULT (result))
    {
      GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
      if (g_simple_async_result_propagate_error (simple, error))
	return FALSE;
    }
  
  iface = G_DRIVE_GET_IFACE (drive);
418 419
  
  return (* iface->eject_finish) (drive, result, error);
420 421 422
}

/**
423
 * g_drive_poll_for_media:
424
 * @drive: a #GDrive.
425
 * @cancellable: optional #GCancellable object, %NULL to ignore.
426
 * @callback: a #GAsyncReadyCallback, or %NULL.
Matthias Clasen's avatar
Matthias Clasen committed
427
 * @user_data: user data to pass to @callback
428
 * 
Matthias Clasen's avatar
Matthias Clasen committed
429
 * Asynchronously polls @drive to see if media has been inserted or removed.
430
 * 
Matthias Clasen's avatar
Matthias Clasen committed
431 432 433
 * When the operation is finished, @callback will be called.
 * You can then call g_drive_poll_for_media_finish() to obtain the
 * result of the operation.
434 435
 **/
void
436 437 438 439
g_drive_poll_for_media (GDrive              *drive,
                        GCancellable        *cancellable,
                        GAsyncReadyCallback  callback,
                        gpointer             user_data)
440 441 442 443 444 445 446
{
  GDriveIface *iface;

  g_return_if_fail (G_IS_DRIVE (drive));

  iface = G_DRIVE_GET_IFACE (drive);

447
  if (iface->poll_for_media == NULL)
448 449 450
    {
      g_simple_async_report_error_in_idle (G_OBJECT (drive), callback, user_data,
					   G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
451
					   _("drive doesn't implement polling for media"));
452 453 454 455
      
      return;
    }
  
456
  (* iface->poll_for_media) (drive, cancellable, callback, user_data);
457 458 459
}

/**
Matthias Clasen's avatar
Matthias Clasen committed
460
 * g_drive_poll_for_media_finish:
461 462
 * @drive: a #GDrive.
 * @result: a #GAsyncResult.
Matthias Clasen's avatar
Matthias Clasen committed
463
 * @error: a #GError, or %NULL
464
 * 
Matthias Clasen's avatar
Matthias Clasen committed
465
 * Finishes an operation started with g_drive_poll_for_media() on a drive.
466
 * 
467
 * Returns: %TRUE if the drive has been poll_for_mediaed successfully,
Matthias Clasen's avatar
Matthias Clasen committed
468
 *     %FALSE otherwise.
469 470
 **/
gboolean
471 472 473
g_drive_poll_for_media_finish (GDrive        *drive,
                               GAsyncResult  *result,
                               GError       **error)
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
{
  GDriveIface *iface;

  g_return_val_if_fail (G_IS_DRIVE (drive), FALSE);
  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);

  if (G_IS_SIMPLE_ASYNC_RESULT (result))
    {
      GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
      if (g_simple_async_result_propagate_error (simple, error))
	return FALSE;
    }
  
  iface = G_DRIVE_GET_IFACE (drive);
  
489
  return (* iface->poll_for_media_finish) (drive, result, error);
490
}
491

Matthias Clasen's avatar
Matthias Clasen committed
492 493 494 495 496 497 498 499
/**
 * g_drive_get_identifier:
 * @drive: a #GDrive
 * @kind: the kind of identifier to return
 *
 * Gets the identifier of the given kind for @drive.
 *
 * Returns: a newly allocated string containing the
Matthias Clasen's avatar
Matthias Clasen committed
500 501
 *     requested identfier, or %NULL if the #GDrive
 *     doesn't have this kind of identifier.
Matthias Clasen's avatar
Matthias Clasen committed
502
 */
503
char *
Matthias Clasen's avatar
Matthias Clasen committed
504 505
g_drive_get_identifier (GDrive     *drive,
			const char *kind)
506 507 508 509 510 511 512 513 514 515 516 517 518 519
{
  GDriveIface *iface;

  g_return_val_if_fail (G_IS_DRIVE (drive), NULL);
  g_return_val_if_fail (kind != NULL, NULL);

  iface = G_DRIVE_GET_IFACE (drive);

  if (iface->get_identifier == NULL)
    return NULL;
  
  return (* iface->get_identifier) (drive, kind);
}

Matthias Clasen's avatar
Matthias Clasen committed
520 521 522 523 524 525 526 527 528
/**
 * g_drive_enumerate_identifiers:
 * @drive: a #GDrive
 *
 * Gets the kinds of identifiers that @drive has. 
 * Use g_drive_get_identifer() to obtain the identifiers
 * themselves.
 *
 * Returns: a %NULL-terminated array of strings containing
Matthias Clasen's avatar
Matthias Clasen committed
529
 *     kinds of identifiers. Use g_strfreev() to free.
Matthias Clasen's avatar
Matthias Clasen committed
530
 */
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
char **
g_drive_enumerate_identifiers (GDrive *drive)
{
  GDriveIface *iface;

  g_return_val_if_fail (G_IS_DRIVE (drive), NULL);
  iface = G_DRIVE_GET_IFACE (drive);

  if (iface->enumerate_identifiers == NULL)
    return NULL;
  
  return (* iface->enumerate_identifiers) (drive);
}


546 547
#define __G_DRIVE_C__
#include "gioaliasdef.c"