1 /* 2 * This file is part of gtkD. 3 * 4 * gtkD is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License 6 * as published by the Free Software Foundation; either version 3 7 * of the License, or (at your option) any later version, with 8 * some exceptions, please read the COPYING file. 9 * 10 * gtkD 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 13 * GNU Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public License 16 * along with gtkD; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA 18 */ 19 20 // generated automatically - do not change 21 // find conversion definition on APILookup.txt 22 // implement new conversion functionalities on the wrap.utils pakage 23 24 25 module gio.DriveT; 26 27 public import gio.AsyncResultIF; 28 public import gio.Cancellable; 29 public import gio.Icon; 30 public import gio.IconIF; 31 public import gio.MountOperation; 32 public import glib.ErrorG; 33 public import glib.GException; 34 public import glib.ListG; 35 public import glib.Str; 36 public import gobject.ObjectG; 37 public import gobject.Signals; 38 public import gtkc.gdktypes; 39 public import gtkc.gio; 40 public import gtkc.giotypes; 41 public import std.algorithm; 42 43 44 /** 45 * #GDrive - this represent a piece of hardware connected to the machine. 46 * It's generally only created for removable hardware or hardware with 47 * removable media. 48 * 49 * #GDrive is a container class for #GVolume objects that stem from 50 * the same piece of media. As such, #GDrive abstracts a drive with 51 * (or without) removable media and provides operations for querying 52 * whether media is available, determining whether media change is 53 * automatically detected and ejecting the media. 54 * 55 * If the #GDrive reports that media isn't automatically detected, one 56 * can poll for media; typically one should not do this periodically 57 * as a poll for media operation is potententially expensive and may 58 * spin up the drive creating noise. 59 * 60 * #GDrive supports starting and stopping drives with authentication 61 * support for the former. This can be used to support a diverse set 62 * of use cases including connecting/disconnecting iSCSI devices, 63 * powering down external disk enclosures and starting/stopping 64 * multi-disk devices such as RAID devices. Note that the actual 65 * semantics and side-effects of starting/stopping a #GDrive may vary 66 * according to implementation. To choose the correct verbs in e.g. a 67 * file manager, use g_drive_get_start_stop_type(). 68 * 69 * For porting from GnomeVFS note that there is no equivalent of 70 * #GDrive in that API. 71 */ 72 public template DriveT(TStruct) 73 { 74 /** Get the main Gtk struct */ 75 public GDrive* getDriveStruct() 76 { 77 return cast(GDrive*)getStruct(); 78 } 79 80 81 /** 82 * Checks if a drive can be ejected. 83 * 84 * Return: %TRUE if the @drive can be ejected, %FALSE otherwise. 85 */ 86 public bool canEject() 87 { 88 return g_drive_can_eject(getDriveStruct()) != 0; 89 } 90 91 /** 92 * Checks if a drive can be polled for media changes. 93 * 94 * Return: %TRUE if the @drive can be polled for media changes, 95 * %FALSE otherwise. 96 */ 97 public bool canPollForMedia() 98 { 99 return g_drive_can_poll_for_media(getDriveStruct()) != 0; 100 } 101 102 /** 103 * Checks if a drive can be started. 104 * 105 * Return: %TRUE if the @drive can be started, %FALSE otherwise. 106 * 107 * Since: 2.22 108 */ 109 public bool canStart() 110 { 111 return g_drive_can_start(getDriveStruct()) != 0; 112 } 113 114 /** 115 * Checks if a drive can be started degraded. 116 * 117 * Return: %TRUE if the @drive can be started degraded, %FALSE otherwise. 118 * 119 * Since: 2.22 120 */ 121 public bool canStartDegraded() 122 { 123 return g_drive_can_start_degraded(getDriveStruct()) != 0; 124 } 125 126 /** 127 * Checks if a drive can be stopped. 128 * 129 * Return: %TRUE if the @drive can be stopped, %FALSE otherwise. 130 * 131 * Since: 2.22 132 */ 133 public bool canStop() 134 { 135 return g_drive_can_stop(getDriveStruct()) != 0; 136 } 137 138 /** 139 * Asynchronously ejects a drive. 140 * 141 * When the operation is finished, @callback will be called. 142 * You can then call g_drive_eject_finish() to obtain the 143 * result of the operation. 144 * 145 * Deprecated: Use g_drive_eject_with_operation() instead. 146 * 147 * Params: 148 * flags = flags affecting the unmount if required for eject 149 * cancellable = optional #GCancellable object, %NULL to ignore. 150 * callback = a #GAsyncReadyCallback, or %NULL. 151 * userData = user data to pass to @callback 152 */ 153 public void eject(GMountUnmountFlags flags, Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 154 { 155 g_drive_eject(getDriveStruct(), flags, (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 156 } 157 158 /** 159 * Finishes ejecting a drive. 160 * 161 * Deprecated: Use g_drive_eject_with_operation_finish() instead. 162 * 163 * Params: 164 * result = a #GAsyncResult. 165 * 166 * Return: %TRUE if the drive has been ejected successfully, 167 * %FALSE otherwise. 168 * 169 * Throws: GException on failure. 170 */ 171 public bool ejectFinish(AsyncResultIF result) 172 { 173 GError* err = null; 174 175 auto p = g_drive_eject_finish(getDriveStruct(), (result is null) ? null : result.getAsyncResultStruct(), &err) != 0; 176 177 if (err !is null) 178 { 179 throw new GException( new ErrorG(err) ); 180 } 181 182 return p; 183 } 184 185 /** 186 * Ejects a drive. This is an asynchronous operation, and is 187 * finished by calling g_drive_eject_with_operation_finish() with the @drive 188 * and #GAsyncResult data returned in the @callback. 189 * 190 * Params: 191 * flags = flags affecting the unmount if required for eject 192 * mountOperation = a #GMountOperation or %NULL to avoid 193 * user interaction. 194 * cancellable = optional #GCancellable object, %NULL to ignore. 195 * callback = a #GAsyncReadyCallback, or %NULL. 196 * userData = user data passed to @callback. 197 * 198 * Since: 2.22 199 */ 200 public void ejectWithOperation(GMountUnmountFlags flags, MountOperation mountOperation, Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 201 { 202 g_drive_eject_with_operation(getDriveStruct(), flags, (mountOperation is null) ? null : mountOperation.getMountOperationStruct(), (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 203 } 204 205 /** 206 * Finishes ejecting a drive. If any errors occurred during the operation, 207 * @error will be set to contain the errors and %FALSE will be returned. 208 * 209 * Params: 210 * result = a #GAsyncResult. 211 * 212 * Return: %TRUE if the drive was successfully ejected. %FALSE otherwise. 213 * 214 * Since: 2.22 215 * 216 * Throws: GException on failure. 217 */ 218 public bool ejectWithOperationFinish(AsyncResultIF result) 219 { 220 GError* err = null; 221 222 auto p = g_drive_eject_with_operation_finish(getDriveStruct(), (result is null) ? null : result.getAsyncResultStruct(), &err) != 0; 223 224 if (err !is null) 225 { 226 throw new GException( new ErrorG(err) ); 227 } 228 229 return p; 230 } 231 232 /** 233 * Gets the kinds of identifiers that @drive has. 234 * Use g_drive_get_identifier() to obtain the identifiers 235 * themselves. 236 * 237 * Return: a %NULL-terminated 238 * array of strings containing kinds of identifiers. Use g_strfreev() 239 * to free. 240 */ 241 public string[] enumerateIdentifiers() 242 { 243 auto retStr = g_drive_enumerate_identifiers(getDriveStruct()); 244 245 scope(exit) Str.freeStringArray(retStr); 246 return Str.toStringArray(retStr); 247 } 248 249 /** 250 * Gets the icon for @drive. 251 * 252 * Return: #GIcon for the @drive. 253 * Free the returned object with g_object_unref(). 254 */ 255 public IconIF getIcon() 256 { 257 auto p = g_drive_get_icon(getDriveStruct()); 258 259 if(p is null) 260 { 261 return null; 262 } 263 264 return ObjectG.getDObject!(Icon, IconIF)(cast(GIcon*) p, true); 265 } 266 267 /** 268 * Gets the identifier of the given kind for @drive. 269 * 270 * Params: 271 * kind = the kind of identifier to return 272 * 273 * Return: a newly allocated string containing the 274 * requested identfier, or %NULL if the #GDrive 275 * doesn't have this kind of identifier. 276 */ 277 public string getIdentifier(string kind) 278 { 279 auto retStr = g_drive_get_identifier(getDriveStruct(), Str.toStringz(kind)); 280 281 scope(exit) Str.freeString(retStr); 282 return Str.toString(retStr); 283 } 284 285 /** 286 * Gets the name of @drive. 287 * 288 * Return: a string containing @drive's name. The returned 289 * string should be freed when no longer needed. 290 */ 291 public string getName() 292 { 293 auto retStr = g_drive_get_name(getDriveStruct()); 294 295 scope(exit) Str.freeString(retStr); 296 return Str.toString(retStr); 297 } 298 299 /** 300 * Gets the sort key for @drive, if any. 301 * 302 * Return: Sorting key for @drive or %NULL if no such key is available. 303 * 304 * Since: 2.32 305 */ 306 public string getSortKey() 307 { 308 return Str.toString(g_drive_get_sort_key(getDriveStruct())); 309 } 310 311 /** 312 * Gets a hint about how a drive can be started/stopped. 313 * 314 * Return: A value from the #GDriveStartStopType enumeration. 315 * 316 * Since: 2.22 317 */ 318 public GDriveStartStopType getStartStopType() 319 { 320 return g_drive_get_start_stop_type(getDriveStruct()); 321 } 322 323 /** 324 * Gets the icon for @drive. 325 * 326 * Return: symbolic #GIcon for the @drive. 327 * Free the returned object with g_object_unref(). 328 * 329 * Since: 2.34 330 */ 331 public IconIF getSymbolicIcon() 332 { 333 auto p = g_drive_get_symbolic_icon(getDriveStruct()); 334 335 if(p is null) 336 { 337 return null; 338 } 339 340 return ObjectG.getDObject!(Icon, IconIF)(cast(GIcon*) p, true); 341 } 342 343 /** 344 * Get a list of mountable volumes for @drive. 345 * 346 * The returned list should be freed with g_list_free(), after 347 * its elements have been unreffed with g_object_unref(). 348 * 349 * Return: #GList containing any #GVolume objects on the given @drive. 350 */ 351 public ListG getVolumes() 352 { 353 auto p = g_drive_get_volumes(getDriveStruct()); 354 355 if(p is null) 356 { 357 return null; 358 } 359 360 return new ListG(cast(GList*) p, true); 361 } 362 363 /** 364 * Checks if the @drive has media. Note that the OS may not be polling 365 * the drive for media changes; see g_drive_is_media_check_automatic() 366 * for more details. 367 * 368 * Return: %TRUE if @drive has media, %FALSE otherwise. 369 */ 370 public bool hasMedia() 371 { 372 return g_drive_has_media(getDriveStruct()) != 0; 373 } 374 375 /** 376 * Check if @drive has any mountable volumes. 377 * 378 * Return: %TRUE if the @drive contains volumes, %FALSE otherwise. 379 */ 380 public bool hasVolumes() 381 { 382 return g_drive_has_volumes(getDriveStruct()) != 0; 383 } 384 385 /** 386 * Checks if @drive is capabable of automatically detecting media changes. 387 * 388 * Return: %TRUE if the @drive is capabable of automatically detecting 389 * media changes, %FALSE otherwise. 390 */ 391 public bool isMediaCheckAutomatic() 392 { 393 return g_drive_is_media_check_automatic(getDriveStruct()) != 0; 394 } 395 396 /** 397 * Checks if the @drive supports removable media. 398 * 399 * Return: %TRUE if @drive supports removable media, %FALSE otherwise. 400 */ 401 public bool isMediaRemovable() 402 { 403 return g_drive_is_media_removable(getDriveStruct()) != 0; 404 } 405 406 /** 407 * Checks if the #GDrive and/or its media is considered removable by the user. 408 * See g_drive_is_media_removable(). 409 * 410 * Return: %TRUE if @drive and/or its media is considered removable, %FALSE otherwise. 411 * 412 * Since: 2.50 413 */ 414 public bool isRemovable() 415 { 416 return g_drive_is_removable(getDriveStruct()) != 0; 417 } 418 419 /** 420 * Asynchronously polls @drive to see if media has been inserted or removed. 421 * 422 * When the operation is finished, @callback will be called. 423 * You can then call g_drive_poll_for_media_finish() to obtain the 424 * result of the operation. 425 * 426 * Params: 427 * cancellable = optional #GCancellable object, %NULL to ignore. 428 * callback = a #GAsyncReadyCallback, or %NULL. 429 * userData = user data to pass to @callback 430 */ 431 public void pollForMedia(Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 432 { 433 g_drive_poll_for_media(getDriveStruct(), (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 434 } 435 436 /** 437 * Finishes an operation started with g_drive_poll_for_media() on a drive. 438 * 439 * Params: 440 * result = a #GAsyncResult. 441 * 442 * Return: %TRUE if the drive has been poll_for_mediaed successfully, 443 * %FALSE otherwise. 444 * 445 * Throws: GException on failure. 446 */ 447 public bool pollForMediaFinish(AsyncResultIF result) 448 { 449 GError* err = null; 450 451 auto p = g_drive_poll_for_media_finish(getDriveStruct(), (result is null) ? null : result.getAsyncResultStruct(), &err) != 0; 452 453 if (err !is null) 454 { 455 throw new GException( new ErrorG(err) ); 456 } 457 458 return p; 459 } 460 461 /** 462 * Asynchronously starts a drive. 463 * 464 * When the operation is finished, @callback will be called. 465 * You can then call g_drive_start_finish() to obtain the 466 * result of the operation. 467 * 468 * Params: 469 * flags = flags affecting the start operation. 470 * mountOperation = a #GMountOperation or %NULL to avoid 471 * user interaction. 472 * cancellable = optional #GCancellable object, %NULL to ignore. 473 * callback = a #GAsyncReadyCallback, or %NULL. 474 * userData = user data to pass to @callback 475 * 476 * Since: 2.22 477 */ 478 public void start(GDriveStartFlags flags, MountOperation mountOperation, Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 479 { 480 g_drive_start(getDriveStruct(), flags, (mountOperation is null) ? null : mountOperation.getMountOperationStruct(), (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 481 } 482 483 /** 484 * Finishes starting a drive. 485 * 486 * Params: 487 * result = a #GAsyncResult. 488 * 489 * Return: %TRUE if the drive has been started successfully, 490 * %FALSE otherwise. 491 * 492 * Since: 2.22 493 * 494 * Throws: GException on failure. 495 */ 496 public bool startFinish(AsyncResultIF result) 497 { 498 GError* err = null; 499 500 auto p = g_drive_start_finish(getDriveStruct(), (result is null) ? null : result.getAsyncResultStruct(), &err) != 0; 501 502 if (err !is null) 503 { 504 throw new GException( new ErrorG(err) ); 505 } 506 507 return p; 508 } 509 510 /** 511 * Asynchronously stops a drive. 512 * 513 * When the operation is finished, @callback will be called. 514 * You can then call g_drive_stop_finish() to obtain the 515 * result of the operation. 516 * 517 * Params: 518 * flags = flags affecting the unmount if required for stopping. 519 * mountOperation = a #GMountOperation or %NULL to avoid 520 * user interaction. 521 * cancellable = optional #GCancellable object, %NULL to ignore. 522 * callback = a #GAsyncReadyCallback, or %NULL. 523 * userData = user data to pass to @callback 524 * 525 * Since: 2.22 526 */ 527 public void stop(GMountUnmountFlags flags, MountOperation mountOperation, Cancellable cancellable, GAsyncReadyCallback callback, void* userData) 528 { 529 g_drive_stop(getDriveStruct(), flags, (mountOperation is null) ? null : mountOperation.getMountOperationStruct(), (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData); 530 } 531 532 /** 533 * Finishes stopping a drive. 534 * 535 * Params: 536 * result = a #GAsyncResult. 537 * 538 * Return: %TRUE if the drive has been stopped successfully, 539 * %FALSE otherwise. 540 * 541 * Since: 2.22 542 * 543 * Throws: GException on failure. 544 */ 545 public bool stopFinish(AsyncResultIF result) 546 { 547 GError* err = null; 548 549 auto p = g_drive_stop_finish(getDriveStruct(), (result is null) ? null : result.getAsyncResultStruct(), &err) != 0; 550 551 if (err !is null) 552 { 553 throw new GException( new ErrorG(err) ); 554 } 555 556 return p; 557 } 558 559 protected class OnChangedDelegateWrapper 560 { 561 void delegate(DriveIF) dlg; 562 gulong handlerId; 563 ConnectFlags flags; 564 this(void delegate(DriveIF) dlg, gulong handlerId, ConnectFlags flags) 565 { 566 this.dlg = dlg; 567 this.handlerId = handlerId; 568 this.flags = flags; 569 } 570 } 571 protected OnChangedDelegateWrapper[] onChangedListeners; 572 573 /** 574 * Emitted when the drive's state has changed. 575 */ 576 gulong addOnChanged(void delegate(DriveIF) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 577 { 578 onChangedListeners ~= new OnChangedDelegateWrapper(dlg, 0, connectFlags); 579 onChangedListeners[onChangedListeners.length - 1].handlerId = Signals.connectData( 580 this, 581 "changed", 582 cast(GCallback)&callBackChanged, 583 cast(void*)onChangedListeners[onChangedListeners.length - 1], 584 cast(GClosureNotify)&callBackChangedDestroy, 585 connectFlags); 586 return onChangedListeners[onChangedListeners.length - 1].handlerId; 587 } 588 589 extern(C) static void callBackChanged(GDrive* driveStruct,OnChangedDelegateWrapper wrapper) 590 { 591 wrapper.dlg(wrapper.outer); 592 } 593 594 extern(C) static void callBackChangedDestroy(OnChangedDelegateWrapper wrapper, GClosure* closure) 595 { 596 wrapper.outer.internalRemoveOnChanged(wrapper); 597 } 598 599 protected void internalRemoveOnChanged(OnChangedDelegateWrapper source) 600 { 601 foreach(index, wrapper; onChangedListeners) 602 { 603 if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId) 604 { 605 onChangedListeners[index] = null; 606 onChangedListeners = std.algorithm.remove(onChangedListeners, index); 607 break; 608 } 609 } 610 } 611 612 613 protected class OnDisconnectedDelegateWrapper 614 { 615 void delegate(DriveIF) dlg; 616 gulong handlerId; 617 ConnectFlags flags; 618 this(void delegate(DriveIF) dlg, gulong handlerId, ConnectFlags flags) 619 { 620 this.dlg = dlg; 621 this.handlerId = handlerId; 622 this.flags = flags; 623 } 624 } 625 protected OnDisconnectedDelegateWrapper[] onDisconnectedListeners; 626 627 /** 628 * This signal is emitted when the #GDrive have been 629 * disconnected. If the recipient is holding references to the 630 * object they should release them so the object can be 631 * finalized. 632 */ 633 gulong addOnDisconnected(void delegate(DriveIF) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 634 { 635 onDisconnectedListeners ~= new OnDisconnectedDelegateWrapper(dlg, 0, connectFlags); 636 onDisconnectedListeners[onDisconnectedListeners.length - 1].handlerId = Signals.connectData( 637 this, 638 "disconnected", 639 cast(GCallback)&callBackDisconnected, 640 cast(void*)onDisconnectedListeners[onDisconnectedListeners.length - 1], 641 cast(GClosureNotify)&callBackDisconnectedDestroy, 642 connectFlags); 643 return onDisconnectedListeners[onDisconnectedListeners.length - 1].handlerId; 644 } 645 646 extern(C) static void callBackDisconnected(GDrive* driveStruct,OnDisconnectedDelegateWrapper wrapper) 647 { 648 wrapper.dlg(wrapper.outer); 649 } 650 651 extern(C) static void callBackDisconnectedDestroy(OnDisconnectedDelegateWrapper wrapper, GClosure* closure) 652 { 653 wrapper.outer.internalRemoveOnDisconnected(wrapper); 654 } 655 656 protected void internalRemoveOnDisconnected(OnDisconnectedDelegateWrapper source) 657 { 658 foreach(index, wrapper; onDisconnectedListeners) 659 { 660 if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId) 661 { 662 onDisconnectedListeners[index] = null; 663 onDisconnectedListeners = std.algorithm.remove(onDisconnectedListeners, index); 664 break; 665 } 666 } 667 } 668 669 670 protected class OnEjectButtonDelegateWrapper 671 { 672 void delegate(DriveIF) dlg; 673 gulong handlerId; 674 ConnectFlags flags; 675 this(void delegate(DriveIF) dlg, gulong handlerId, ConnectFlags flags) 676 { 677 this.dlg = dlg; 678 this.handlerId = handlerId; 679 this.flags = flags; 680 } 681 } 682 protected OnEjectButtonDelegateWrapper[] onEjectButtonListeners; 683 684 /** 685 * Emitted when the physical eject button (if any) of a drive has 686 * been pressed. 687 */ 688 gulong addOnEjectButton(void delegate(DriveIF) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 689 { 690 onEjectButtonListeners ~= new OnEjectButtonDelegateWrapper(dlg, 0, connectFlags); 691 onEjectButtonListeners[onEjectButtonListeners.length - 1].handlerId = Signals.connectData( 692 this, 693 "eject-button", 694 cast(GCallback)&callBackEjectButton, 695 cast(void*)onEjectButtonListeners[onEjectButtonListeners.length - 1], 696 cast(GClosureNotify)&callBackEjectButtonDestroy, 697 connectFlags); 698 return onEjectButtonListeners[onEjectButtonListeners.length - 1].handlerId; 699 } 700 701 extern(C) static void callBackEjectButton(GDrive* driveStruct,OnEjectButtonDelegateWrapper wrapper) 702 { 703 wrapper.dlg(wrapper.outer); 704 } 705 706 extern(C) static void callBackEjectButtonDestroy(OnEjectButtonDelegateWrapper wrapper, GClosure* closure) 707 { 708 wrapper.outer.internalRemoveOnEjectButton(wrapper); 709 } 710 711 protected void internalRemoveOnEjectButton(OnEjectButtonDelegateWrapper source) 712 { 713 foreach(index, wrapper; onEjectButtonListeners) 714 { 715 if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId) 716 { 717 onEjectButtonListeners[index] = null; 718 onEjectButtonListeners = std.algorithm.remove(onEjectButtonListeners, index); 719 break; 720 } 721 } 722 } 723 724 725 protected class OnStopButtonDelegateWrapper 726 { 727 void delegate(DriveIF) dlg; 728 gulong handlerId; 729 ConnectFlags flags; 730 this(void delegate(DriveIF) dlg, gulong handlerId, ConnectFlags flags) 731 { 732 this.dlg = dlg; 733 this.handlerId = handlerId; 734 this.flags = flags; 735 } 736 } 737 protected OnStopButtonDelegateWrapper[] onStopButtonListeners; 738 739 /** 740 * Emitted when the physical stop button (if any) of a drive has 741 * been pressed. 742 * 743 * Since: 2.22 744 */ 745 gulong addOnStopButton(void delegate(DriveIF) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 746 { 747 onStopButtonListeners ~= new OnStopButtonDelegateWrapper(dlg, 0, connectFlags); 748 onStopButtonListeners[onStopButtonListeners.length - 1].handlerId = Signals.connectData( 749 this, 750 "stop-button", 751 cast(GCallback)&callBackStopButton, 752 cast(void*)onStopButtonListeners[onStopButtonListeners.length - 1], 753 cast(GClosureNotify)&callBackStopButtonDestroy, 754 connectFlags); 755 return onStopButtonListeners[onStopButtonListeners.length - 1].handlerId; 756 } 757 758 extern(C) static void callBackStopButton(GDrive* driveStruct,OnStopButtonDelegateWrapper wrapper) 759 { 760 wrapper.dlg(wrapper.outer); 761 } 762 763 extern(C) static void callBackStopButtonDestroy(OnStopButtonDelegateWrapper wrapper, GClosure* closure) 764 { 765 wrapper.outer.internalRemoveOnStopButton(wrapper); 766 } 767 768 protected void internalRemoveOnStopButton(OnStopButtonDelegateWrapper source) 769 { 770 foreach(index, wrapper; onStopButtonListeners) 771 { 772 if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId) 773 { 774 onStopButtonListeners[index] = null; 775 onStopButtonListeners = std.algorithm.remove(onStopButtonListeners, index); 776 break; 777 } 778 } 779 } 780 781 }