1 /* GIO - GLib Input, Output and Streaming Library 2 * 3 * Copyright (C) 2006-2007 Red Hat, Inc. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General 16 * Public License along with this library; if not, write to the 17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, 18 * Boston, MA 02111-1307, USA. 19 * 20 * Author: Alexander Larsson <alexl (at) redhat.com> 21 * David Zeuthen <davidz (at) redhat.com> 22 */ 23 24 #include "config.h" 25 #include "gdrive.h" 26 #include "gsimpleasyncresult.h" 27 #include "gasyncresult.h" 28 #include "gioerror.h" 29 #include "glibintl.h" 30 31 #include "gioalias.h" 32 33 /** 34 * SECTION:gdrive 35 * @short_description: Virtual File System drive management 36 * @include: gio/gio.h 37 * 38 * #GDrive - this represent a piece of hardware connected to the machine. 39 * It's generally only created for removable hardware or hardware with 40 * removable media. 41 * 42 * #GDrive is a container class for #GVolume objects that stem from 43 * the same piece of media. As such, #GDrive abstracts a drive with 44 * (or without) removable media and provides operations for querying 45 * whether media is available, determing whether media change is 46 * automatically detected and ejecting the media. 47 * 48 * If the #GDrive reports that media isn't automatically detected, one 49 * can poll for media; typically one should not do this periodically 50 * as a poll for media operation is potententially expensive and may 51 * spin up the drive creating noise. 52 * 53 * For porting from GnomeVFS note that there is no equivalent of 54 * #GDrive in that API. 55 **/ 56 57 static void g_drive_base_init (gpointer g_class); 58 static void g_drive_class_init (gpointer g_class, 59 gpointer class_data); 60 61 GType 62 g_drive_get_type (void) 63 { 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 sizeof (GDriveIface), /* class_size */ 71 g_drive_base_init, /* base_init */ 72 NULL, /* base_finalize */ 73 g_drive_class_init, 74 NULL, /* class_finalize */ 75 NULL, /* class_data */ 76 0, 77 0, /* n_preallocs */ 78 NULL 79 }; 80 GType g_define_type_id = 81 g_type_register_static (G_TYPE_INTERFACE, I_("GDrive"), 82 &drive_info, 0); 83 84 g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT); 85 86 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 static void 93 g_drive_class_init (gpointer g_class, 94 gpointer class_data) 95 { 96 } 97 98 static void 99 g_drive_base_init (gpointer g_class) 100 { 101 static gboolean initialized = FALSE; 102 103 if (! initialized) 104 { 105 /** 106 * GDrive::changed: 107 * @drive: a #GDrive. 108 * 109 * Emitted when the drive's state has changed. 110 **/ 111 g_signal_new (I_("changed"), 112 G_TYPE_DRIVE, 113 G_SIGNAL_RUN_LAST, 114 G_STRUCT_OFFSET (GDriveIface, changed), 115 NULL, NULL, 116 g_cclosure_marshal_VOID__VOID, 117 G_TYPE_NONE, 0); 118 119 /** 120 * GDrive::disconnected: 121 * @drive: a #GDrive. 122 * 123 * This signal is emitted when the #GDrive have been 124 * disconnected. If the recipient is holding references to the 125 * object they should release them so the object can be 126 * finalized. 127 **/ 128 g_signal_new (I_("disconnected"), 129 G_TYPE_DRIVE, 130 G_SIGNAL_RUN_LAST, 131 G_STRUCT_OFFSET (GDriveIface, disconnected), 132 NULL, NULL, 133 g_cclosure_marshal_VOID__VOID, 134 G_TYPE_NONE, 0); 135 136 /** 137 * GDrive::eject-button: 138 * @drive: a #GDrive. 139 * 140 * Emitted when the physical eject button (if any) of a drive has 141 * been pressed. 142 **/ 143 g_signal_new (I_("eject-button"), 144 G_TYPE_DRIVE, 145 G_SIGNAL_RUN_LAST, 146 G_STRUCT_OFFSET (GDriveIface, eject_button), 147 NULL, NULL, 148 g_cclosure_marshal_VOID__VOID, 149 G_TYPE_NONE, 0); 150 151 initialized = TRUE; 152 } 153 } 154 155 /** 156 * g_drive_get_name: 157 * @drive: a #GDrive. 158 * 159 * Gets the name of @drive. 160 * 161 * Returns: a string containing @drive's name. The returned 162 * string should be freed when no longer needed. 163 **/ 164 char * 165 g_drive_get_name (GDrive *drive) 166 { 167 GDriveIface *iface; 168 169 g_return_val_if_fail (G_IS_DRIVE (drive), NULL); 170 171 iface = G_DRIVE_GET_IFACE (drive); 172 173 return (* iface->get_name) (drive); 174 } 175 176 /** 177 * g_drive_get_icon: 178 * @drive: a #GDrive. 179 * 180 * Gets the icon for @drive. 181 * 182 * Returns: #GIcon for the @drive. 183 * Free the returned object with g_object_unref(). 184 **/ 185 GIcon * 186 g_drive_get_icon (GDrive *drive) 187 { 188 GDriveIface *iface; 189 190 g_return_val_if_fail (G_IS_DRIVE (drive), NULL); 191 192 iface = G_DRIVE_GET_IFACE (drive); 193 194 return (* iface->get_icon) (drive); 195 } 196 197 /** 198 * g_drive_has_volumes: 199 * @drive: a #GDrive. 200 * 201 * Check if @drive has any mountable volumes. 202 * 203 * Returns: %TRUE if the @drive contains volumes, %FALSE otherwise. 204 **/ 205 gboolean 206 g_drive_has_volumes (GDrive *drive) 207 { 208 GDriveIface *iface; 209 210 g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); 211 212 iface = G_DRIVE_GET_IFACE (drive); 213 214 return (* iface->has_volumes) (drive); 215 } 216 217 /** 218 * g_drive_get_volumes: 219 * @drive: a #GDrive. 220 * 221 * Get a list of mountable volumes for @drive. 222 * 223 * The returned list should be freed with g_list_free(), after 224 * its elements have been unreffed with g_object_unref(). 225 * 226 * Returns: #GList containing any #GVolume objects on the given @drive. 227 **/ 228 GList * 229 g_drive_get_volumes (GDrive *drive) 230 { 231 GDriveIface *iface; 232 233 g_return_val_if_fail (G_IS_DRIVE (drive), NULL); 234 235 iface = G_DRIVE_GET_IFACE (drive); 236 237 return (* iface->get_volumes) (drive); 238 } 239 240 /** 241 * g_drive_is_media_check_automatic: 242 * @drive: a #GDrive. 243 * 244 * Checks if @drive is capabable of automatically detecting media changes. 245 * 246 * Returns: %TRUE if the @drive is capabable of automatically detecting 247 * media changes, %FALSE otherwise. 248 **/ 249 gboolean 250 g_drive_is_media_check_automatic (GDrive *drive) 251 { 252 GDriveIface *iface; 253 254 g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); 255 256 iface = G_DRIVE_GET_IFACE (drive); 257 258 return (* iface->is_media_check_automatic) (drive); 259 } 260 261 /** 262 * g_drive_is_media_removable: 263 * @drive: a #GDrive. 264 * 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 GDriveIface *iface; 273 274 g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); 275 276 iface = G_DRIVE_GET_IFACE (drive); 277 278 return (* iface->is_media_removable) (drive); 279 } 280 281 /** 282 * g_drive_has_media: 283 * @drive: a #GDrive. 284 * 285 * Checks if the @drive has media. Note that the OS may not be polling 286 * the drive for media changes; see g_drive_is_media_check_automatic() 287 * for more details. 288 * 289 * Returns: %TRUE if @drive has media, %FALSE otherwise. 290 **/ 291 gboolean 292 g_drive_has_media (GDrive *drive) 293 { 294 GDriveIface *iface; 295 296 g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); 297 298 iface = G_DRIVE_GET_IFACE (drive); 299 300 return (* iface->has_media) (drive); 301 } 302 303 /** 304 * g_drive_can_eject: 305 * @drive: a #GDrive. 306 * 307 * Checks if a drive can be ejected. 308 * 309 * Returns: %TRUE if the @drive can be ejected, %FALSE otherwise. 310 **/ 311 gboolean 312 g_drive_can_eject (GDrive *drive) 313 { 314 GDriveIface *iface; 315 316 g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); 317 318 iface = G_DRIVE_GET_IFACE (drive); 319 320 if (iface->can_eject == NULL) 321 return FALSE; 322 323 return (* iface->can_eject) (drive); 324 } 325 326 /** 327 * g_drive_can_poll_for_media: 328 * @drive: a #GDrive. 329 * 330 * Checks if a drive can be polled for media changes. 331 * 332 * Returns: %TRUE if the @drive can be polled for media changes, 333 * %FALSE otherwise. 334 **/ 335 gboolean 336 g_drive_can_poll_for_media (GDrive *drive) 337 { 338 GDriveIface *iface; 339 340 g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); 341 342 iface = G_DRIVE_GET_IFACE (drive); 343 344 if (iface->poll_for_media == NULL) 345 return FALSE; 346 347 return (* iface->can_poll_for_media) (drive); 348 } 349 350 /** 351 * 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. 356 * @user_data: user data to pass to @callback 357 * 358 * Asynchronously ejects a drive. 359 * 360 * When the operation is finished, @callback will be called. 361 * You can then call g_drive_eject_finish() to obtain the 362 * result of the operation. 363 **/ 364 void 365 g_drive_eject (GDrive *drive, 366 GMountUnmountFlags flags, 367 GCancellable *cancellable, 368 GAsyncReadyCallback callback, 369 gpointer user_data) 370 { 371 GDriveIface *iface; 372 373 g_return_if_fail (G_IS_DRIVE (drive)); 374 375 iface = G_DRIVE_GET_IFACE (drive); 376 377 if (iface->eject == NULL) 378 { 379 g_simple_async_report_error_in_idle (G_OBJECT (drive), callback, user_data, 380 G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, 381 _("drive doesn't implement eject")); 382 383 return; 384 } 385 386 (* iface->eject) (drive, flags, cancellable, callback, user_data); 387 } 388 389 /** 390 * g_drive_eject_finish: 391 * @drive: a #GDrive. 392 * @result: a #GAsyncResult. 393 * @error: a #GError, or %NULL 394 * 395 * Finishes ejecting a drive. 396 * 397 * Returns: %TRUE if the drive has been ejected successfully, 398 * %FALSE otherwise. 399 **/ 400 gboolean 401 g_drive_eject_finish (GDrive *drive, 402 GAsyncResult *result, 403 GError **error) 404 { 405 GDriveIface *iface; 406 407 g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); 408 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); 409 410 if (G_IS_SIMPLE_ASYNC_RESULT (result)) 411 { 412 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); 413 if (g_simple_async_result_propagate_error (simple, error)) 414 return FALSE; 415 } 416 417 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. 427 * @user_data: user data to pass to @callback 428 * 429 * Asynchronously polls @drive to see if media has been inserted or removed. 430 * 431 * When the operation is finished, @callback will be called. 432 * You can then call g_drive_poll_for_media_finish() to obtain the 433 * result of the operation. 434 **/ 435 void 436 g_drive_poll_for_media (GDrive *drive, 437 GCancellable *cancellable, 438 GAsyncReadyCallback callback, 439 gpointer user_data) 440 { 441 GDriveIface *iface; 442 443 g_return_if_fail (G_IS_DRIVE (drive)); 444 445 iface = G_DRIVE_GET_IFACE (drive); 446 447 if (iface->poll_for_media == NULL) 448 { 449 g_simple_async_report_error_in_idle (G_OBJECT (drive), callback, user_data, 450 G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, 451 _("drive doesn't implement polling for media")); 452 453 return; 454 } 455 456 (* iface->poll_for_media) (drive, cancellable, callback, user_data); 457 } 458 459 /** 460 * g_drive_poll_for_media_finish: 461 * @drive: a #GDrive. 462 * @result: a #GAsyncResult. 463 * @error: a #GError, or %NULL 464 * 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, 468 * %FALSE otherwise. 469 **/ 470 gboolean 471 g_drive_poll_for_media_finish (GDrive *drive, 472 GAsyncResult *result, 473 GError **error) 474 { 475 GDriveIface *iface; 476 477 g_return_val_if_fail (G_IS_DRIVE (drive), FALSE); 478 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); 479 480 if (G_IS_SIMPLE_ASYNC_RESULT (result)) 481 { 482 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); 483 if (g_simple_async_result_propagate_error (simple, error)) 484 return FALSE; 485 } 486 487 iface = G_DRIVE_GET_IFACE (drive); 488 489 return (* iface->poll_for_media_finish) (drive, result, error); 490 } 491 492 /** 493 * g_drive_get_identifier: 494 * @drive: a #GDrive 495 * @kind: the kind of identifier to return 496 * 497 * Gets the identifier of the given kind for @drive. 498 * 499 * Returns: a newly allocated string containing the 500 * requested identfier, or %NULL if the #GDrive 501 * doesn't have this kind of identifier. 502 */ 503 char * 504 g_drive_get_identifier (GDrive *drive, 505 const char *kind) 506 { 507 GDriveIface *iface; 508 509 g_return_val_if_fail (G_IS_DRIVE (drive), NULL); 510 g_return_val_if_fail (kind != NULL, NULL); 511 512 iface = G_DRIVE_GET_IFACE (drive); 513 514 if (iface->get_identifier == NULL) 515 return NULL; 516 517 return (* iface->get_identifier) (drive, kind); 518 } 519 520 /** 521 * g_drive_enumerate_identifiers: 522 * @drive: a #GDrive 523 * 524 * Gets the kinds of identifiers that @drive has. 525 * Use g_drive_get_identifer() to obtain the identifiers 526 * themselves. 527 * 528 * Returns: a %NULL-terminated array of strings containing 529 * kinds of identifiers. Use g_strfreev() to free. 530 */ 531 char ** 532 g_drive_enumerate_identifiers (GDrive *drive) 533 { 534 GDriveIface *iface; 535 536 g_return_val_if_fail (G_IS_DRIVE (drive), NULL); 537 iface = G_DRIVE_GET_IFACE (drive); 538 539 if (iface->enumerate_identifiers == NULL) 540 return NULL; 541 542 return (* iface->enumerate_identifiers) (drive); 543 } 544 545 546 #define __G_DRIVE_C__ 547 #include "gioaliasdef.c" 548