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 gstreamer.Bin; 26 27 private import glib.ConstructionException; 28 private import glib.Str; 29 private import gobject.ObjectG; 30 private import gobject.Signals; 31 private import gstreamer.ChildProxyIF; 32 private import gstreamer.ChildProxyT; 33 private import gstreamer.Element; 34 private import gstreamer.Iterator; 35 private import gstreamer.Pad; 36 private import gstreamerc.gstreamer; 37 public import gstreamerc.gstreamertypes; 38 private import std.algorithm; 39 40 41 /** 42 * #GstBin is an element that can contain other #GstElement, allowing them to be 43 * managed as a group. 44 * Pads from the child elements can be ghosted to the bin, see #GstGhostPad. 45 * This makes the bin look like any other elements and enables creation of 46 * higher-level abstraction elements. 47 * 48 * A new #GstBin is created with gst_bin_new(). Use a #GstPipeline instead if you 49 * want to create a toplevel bin because a normal bin doesn't have a bus or 50 * handle clock distribution of its own. 51 * 52 * After the bin has been created you will typically add elements to it with 53 * gst_bin_add(). You can remove elements with gst_bin_remove(). 54 * 55 * An element can be retrieved from a bin with gst_bin_get_by_name(), using the 56 * elements name. gst_bin_get_by_name_recurse_up() is mainly used for internal 57 * purposes and will query the parent bins when the element is not found in the 58 * current bin. 59 * 60 * An iterator of elements in a bin can be retrieved with 61 * gst_bin_iterate_elements(). Various other iterators exist to retrieve the 62 * elements in a bin. 63 * 64 * gst_object_unref() is used to drop your reference to the bin. 65 * 66 * The #GstBin::element-added signal is fired whenever a new element is added to 67 * the bin. Likewise the #GstBin::element-removed signal is fired whenever an 68 * element is removed from the bin. 69 * 70 * ## Notes 71 * 72 * A #GstBin internally intercepts every #GstMessage posted by its children and 73 * implements the following default behaviour for each of them: 74 * 75 * * GST_MESSAGE_EOS: This message is only posted by sinks in the PLAYING 76 * state. If all sinks posted the EOS message, this bin will post and EOS 77 * message upwards. 78 * 79 * * GST_MESSAGE_SEGMENT_START: Just collected and never forwarded upwards. 80 * The messages are used to decide when all elements have completed playback 81 * of their segment. 82 * 83 * * GST_MESSAGE_SEGMENT_DONE: Is posted by #GstBin when all elements that posted 84 * a SEGMENT_START have posted a SEGMENT_DONE. 85 * 86 * * GST_MESSAGE_DURATION_CHANGED: Is posted by an element that detected a change 87 * in the stream duration. The default bin behaviour is to clear any 88 * cached duration values so that the next duration query will perform 89 * a full duration recalculation. The duration change is posted to the 90 * application so that it can refetch the new duration with a duration 91 * query. Note that these messages can be posted before the bin is 92 * prerolled, in which case the duration query might fail. 93 * 94 * * GST_MESSAGE_CLOCK_LOST: This message is posted by an element when it 95 * can no longer provide a clock. The default bin behaviour is to 96 * check if the lost clock was the one provided by the bin. If so and 97 * the bin is currently in the PLAYING state, the message is forwarded to 98 * the bin parent. 99 * This message is also generated when a clock provider is removed from 100 * the bin. If this message is received by the application, it should 101 * PAUSE the pipeline and set it back to PLAYING to force a new clock 102 * distribution. 103 * 104 * * GST_MESSAGE_CLOCK_PROVIDE: This message is generated when an element 105 * can provide a clock. This mostly happens when a new clock 106 * provider is added to the bin. The default behaviour of the bin is to 107 * mark the currently selected clock as dirty, which will perform a clock 108 * recalculation the next time the bin is asked to provide a clock. 109 * This message is never sent tot the application but is forwarded to 110 * the parent of the bin. 111 * 112 * * OTHERS: posted upwards. 113 * 114 * A #GstBin implements the following default behaviour for answering to a 115 * #GstQuery: 116 * 117 * * GST_QUERY_DURATION:If the query has been asked before with the same format 118 * and the bin is a toplevel bin (ie. has no parent), 119 * use the cached previous value. If no previous value was cached, the 120 * query is sent to all sink elements in the bin and the MAXIMUM of all 121 * values is returned. If the bin is a toplevel bin the value is cached. 122 * If no sinks are available in the bin, the query fails. 123 * 124 * * GST_QUERY_POSITION:The query is sent to all sink elements in the bin and the 125 * MAXIMUM of all values is returned. If no sinks are available in the bin, 126 * the query fails. 127 * 128 * * OTHERS:the query is forwarded to all sink elements, the result 129 * of the first sink that answers the query successfully is returned. If no 130 * sink is in the bin, the query fails. 131 * 132 * A #GstBin will by default forward any event sent to it to all sink 133 * (#GST_EVENT_TYPE_DOWNSTREAM) or source (#GST_EVENT_TYPE_UPSTREAM) elements 134 * depending on the event type. 135 * If all the elements return %TRUE, the bin will also return %TRUE, else %FALSE 136 * is returned. If no elements of the required type are in the bin, the event 137 * handler will return %TRUE. 138 */ 139 public class Bin : Element, ChildProxyIF 140 { 141 /** the main Gtk struct */ 142 protected GstBin* gstBin; 143 144 /** Get the main Gtk struct */ 145 public GstBin* getBinStruct(bool transferOwnership = false) 146 { 147 if (transferOwnership) 148 ownedRef = false; 149 return gstBin; 150 } 151 152 /** the main Gtk struct as a void* */ 153 protected override void* getStruct() 154 { 155 return cast(void*)gstBin; 156 } 157 158 protected override void setStruct(GObject* obj) 159 { 160 gstBin = cast(GstBin*)obj; 161 super.setStruct(obj); 162 } 163 164 /** 165 * Sets our main struct and passes it to the parent class. 166 */ 167 public this (GstBin* gstBin, bool ownedRef = false) 168 { 169 this.gstBin = gstBin; 170 super(cast(GstElement*)gstBin, ownedRef); 171 } 172 173 // add the ChildProxy capabilities 174 mixin ChildProxyT!(GstBin); 175 176 /** */ 177 public this(Element elem) 178 { 179 super( elem.getElementStruct(), true ); 180 this.gstBin = cast(GstBin*)elem.getElementStruct(); 181 } 182 183 /** 184 * Adds a list of elements to a bin. 185 * This function is equivalent to calling add() for each member of the list. 186 * The return value of each add() is ignored. 187 */ 188 public void addMany( Element[] elems... ) 189 { 190 foreach( e; elems ) add( e ); 191 } 192 193 /** 194 * Remove a list of elements from a bin. 195 * This function is equivalent to calling remove() with each member of the list. 196 */ 197 public void removeMany( Element[] elems... ) 198 { 199 foreach( e; elems ) remove( e ); 200 } 201 202 /** 203 */ 204 205 /** */ 206 public static GType getType() 207 { 208 return gst_bin_get_type(); 209 } 210 211 /** 212 * Creates a new bin with the given name. 213 * 214 * Params: 215 * name = the name of the new bin 216 * 217 * Returns: a new #GstBin 218 * 219 * Throws: ConstructionException GTK+ fails to create the object. 220 */ 221 public this(string name) 222 { 223 auto p = gst_bin_new(Str.toStringz(name)); 224 225 if(p is null) 226 { 227 throw new ConstructionException("null returned by new"); 228 } 229 230 this(cast(GstBin*) p); 231 } 232 233 /** 234 * Adds the given element to the bin. Sets the element's parent, and thus 235 * takes ownership of the element. An element can only be added to one bin. 236 * 237 * If the element's pads are linked to other pads, the pads will be unlinked 238 * before the element is added to the bin. 239 * 240 * > When you add an element to an already-running pipeline, you will have to 241 * > take care to set the state of the newly-added element to the desired 242 * > state (usually PLAYING or PAUSED, same you set the pipeline to originally) 243 * > with gst_element_set_state(), or use gst_element_sync_state_with_parent(). 244 * > The bin or pipeline will not take care of this for you. 245 * 246 * MT safe. 247 * 248 * Params: 249 * element = the #GstElement to add 250 * 251 * Returns: %TRUE if the element could be added, %FALSE if 252 * the bin does not want to accept the element. 253 */ 254 public bool add(Element element) 255 { 256 return gst_bin_add(gstBin, (element is null) ? null : element.getElementStruct()) != 0; 257 } 258 259 /** 260 * Recursively looks for elements with an unlinked pad of the given 261 * direction within the specified bin and returns an unlinked pad 262 * if one is found, or %NULL otherwise. If a pad is found, the caller 263 * owns a reference to it and should use gst_object_unref() on the 264 * pad when it is not needed any longer. 265 * 266 * Params: 267 * direction = whether to look for an unlinked source or sink pad 268 * 269 * Returns: unlinked pad of the given 270 * direction, %NULL. 271 */ 272 public Pad findUnlinkedPad(GstPadDirection direction) 273 { 274 auto p = gst_bin_find_unlinked_pad(gstBin, direction); 275 276 if(p is null) 277 { 278 return null; 279 } 280 281 return ObjectG.getDObject!(Pad)(cast(GstPad*) p, true); 282 } 283 284 /** 285 * Looks for an element inside the bin that implements the given 286 * interface. If such an element is found, it returns the element. 287 * You can cast this element to the given interface afterwards. If you want 288 * all elements that implement the interface, use 289 * gst_bin_iterate_all_by_interface(). This function recurses into child bins. 290 * 291 * MT safe. Caller owns returned reference. 292 * 293 * Params: 294 * iface = the #GType of an interface 295 * 296 * Returns: A #GstElement inside the bin implementing the interface 297 */ 298 public Element getByInterface(GType iface) 299 { 300 auto p = gst_bin_get_by_interface(gstBin, iface); 301 302 if(p is null) 303 { 304 return null; 305 } 306 307 return ObjectG.getDObject!(Element)(cast(GstElement*) p, true); 308 } 309 310 /** 311 * Gets the element with the given name from a bin. This 312 * function recurses into child bins. 313 * 314 * Returns %NULL if no element with the given name is found in the bin. 315 * 316 * MT safe. Caller owns returned reference. 317 * 318 * Params: 319 * name = the element name to search for 320 * 321 * Returns: the #GstElement with the given 322 * name, or %NULL 323 */ 324 public Element getByName(string name) 325 { 326 auto p = gst_bin_get_by_name(gstBin, Str.toStringz(name)); 327 328 if(p is null) 329 { 330 return null; 331 } 332 333 return ObjectG.getDObject!(Element)(cast(GstElement*) p, true); 334 } 335 336 /** 337 * Gets the element with the given name from this bin. If the 338 * element is not found, a recursion is performed on the parent bin. 339 * 340 * Returns %NULL if: 341 * - no element with the given name is found in the bin 342 * 343 * MT safe. Caller owns returned reference. 344 * 345 * Params: 346 * name = the element name to search for 347 * 348 * Returns: the #GstElement with the given 349 * name, or %NULL 350 */ 351 public Element getByNameRecurseUp(string name) 352 { 353 auto p = gst_bin_get_by_name_recurse_up(gstBin, Str.toStringz(name)); 354 355 if(p is null) 356 { 357 return null; 358 } 359 360 return ObjectG.getDObject!(Element)(cast(GstElement*) p, true); 361 } 362 363 /** 364 * Return the suppressed flags of the bin. 365 * 366 * MT safe. 367 * 368 * Returns: the bin's suppressed #GstElementFlags. 369 * 370 * Since: 1.10 371 */ 372 public GstElementFlags getSuppressedFlags() 373 { 374 return gst_bin_get_suppressed_flags(gstBin); 375 } 376 377 /** 378 * Looks for all elements inside the bin that implements the given 379 * interface. You can safely cast all returned elements to the given interface. 380 * The function recurses inside child bins. The iterator will yield a series 381 * of #GstElement that should be unreffed after use. 382 * 383 * MT safe. Caller owns returned value. 384 * 385 * Params: 386 * iface = the #GType of an interface 387 * 388 * Returns: a #GstIterator of #GstElement 389 * for all elements in the bin implementing the given interface, 390 * or %NULL 391 */ 392 public Iterator iterateAllByInterface(GType iface) 393 { 394 auto p = gst_bin_iterate_all_by_interface(gstBin, iface); 395 396 if(p is null) 397 { 398 return null; 399 } 400 401 return ObjectG.getDObject!(Iterator)(cast(GstIterator*) p, true); 402 } 403 404 /** 405 * Gets an iterator for the elements in this bin. 406 * 407 * MT safe. Caller owns returned value. 408 * 409 * Returns: a #GstIterator of #GstElement, 410 * or %NULL 411 */ 412 public Iterator iterateElements() 413 { 414 auto p = gst_bin_iterate_elements(gstBin); 415 416 if(p is null) 417 { 418 return null; 419 } 420 421 return ObjectG.getDObject!(Iterator)(cast(GstIterator*) p, true); 422 } 423 424 /** 425 * Gets an iterator for the elements in this bin. 426 * This iterator recurses into GstBin children. 427 * 428 * MT safe. Caller owns returned value. 429 * 430 * Returns: a #GstIterator of #GstElement, 431 * or %NULL 432 */ 433 public Iterator iterateRecurse() 434 { 435 auto p = gst_bin_iterate_recurse(gstBin); 436 437 if(p is null) 438 { 439 return null; 440 } 441 442 return ObjectG.getDObject!(Iterator)(cast(GstIterator*) p, true); 443 } 444 445 /** 446 * Gets an iterator for all elements in the bin that have the 447 * #GST_ELEMENT_FLAG_SINK flag set. 448 * 449 * MT safe. Caller owns returned value. 450 * 451 * Returns: a #GstIterator of #GstElement, 452 * or %NULL 453 */ 454 public Iterator iterateSinks() 455 { 456 auto p = gst_bin_iterate_sinks(gstBin); 457 458 if(p is null) 459 { 460 return null; 461 } 462 463 return ObjectG.getDObject!(Iterator)(cast(GstIterator*) p, true); 464 } 465 466 /** 467 * Gets an iterator for the elements in this bin in topologically 468 * sorted order. This means that the elements are returned from 469 * the most downstream elements (sinks) to the sources. 470 * 471 * This function is used internally to perform the state changes 472 * of the bin elements and for clock selection. 473 * 474 * MT safe. Caller owns returned value. 475 * 476 * Returns: a #GstIterator of #GstElement, 477 * or %NULL 478 */ 479 public Iterator iterateSorted() 480 { 481 auto p = gst_bin_iterate_sorted(gstBin); 482 483 if(p is null) 484 { 485 return null; 486 } 487 488 return ObjectG.getDObject!(Iterator)(cast(GstIterator*) p, true); 489 } 490 491 /** 492 * Gets an iterator for all elements in the bin that have the 493 * #GST_ELEMENT_FLAG_SOURCE flag set. 494 * 495 * MT safe. Caller owns returned value. 496 * 497 * Returns: a #GstIterator of #GstElement, 498 * or %NULL 499 */ 500 public Iterator iterateSources() 501 { 502 auto p = gst_bin_iterate_sources(gstBin); 503 504 if(p is null) 505 { 506 return null; 507 } 508 509 return ObjectG.getDObject!(Iterator)(cast(GstIterator*) p, true); 510 } 511 512 /** 513 * Query @bin for the current latency using and reconfigures this latency to all the 514 * elements with a LATENCY event. 515 * 516 * This method is typically called on the pipeline when a #GST_MESSAGE_LATENCY 517 * is posted on the bus. 518 * 519 * This function simply emits the 'do-latency' signal so any custom latency 520 * calculations will be performed. 521 * 522 * Returns: %TRUE if the latency could be queried and reconfigured. 523 */ 524 public bool recalculateLatency() 525 { 526 return gst_bin_recalculate_latency(gstBin) != 0; 527 } 528 529 /** 530 * Removes the element from the bin, unparenting it as well. 531 * Unparenting the element means that the element will be dereferenced, 532 * so if the bin holds the only reference to the element, the element 533 * will be freed in the process of removing it from the bin. If you 534 * want the element to still exist after removing, you need to call 535 * gst_object_ref() before removing it from the bin. 536 * 537 * If the element's pads are linked to other pads, the pads will be unlinked 538 * before the element is removed from the bin. 539 * 540 * MT safe. 541 * 542 * Params: 543 * element = the #GstElement to remove 544 * 545 * Returns: %TRUE if the element could be removed, %FALSE if 546 * the bin does not want to remove the element. 547 */ 548 public bool remove(Element element) 549 { 550 return gst_bin_remove(gstBin, (element is null) ? null : element.getElementStruct()) != 0; 551 } 552 553 /** 554 * Suppress the given flags on the bin. #GstElementFlags of a 555 * child element are propagated when it is added to the bin. 556 * When suppressed flags are set, those specified flags will 557 * not be propagated to the bin. 558 * 559 * MT safe. 560 * 561 * Params: 562 * flags = the #GstElementFlags to suppress 563 * 564 * Since: 1.10 565 */ 566 public void setSuppressedFlags(GstElementFlags flags) 567 { 568 gst_bin_set_suppressed_flags(gstBin, flags); 569 } 570 571 /** 572 * Synchronizes the state of every child of @bin with the state 573 * of @bin. See also gst_element_sync_state_with_parent(). 574 * 575 * Returns: %TRUE if syncing the state was successful for all children, 576 * otherwise %FALSE. 577 * 578 * Since: 1.6 579 */ 580 public bool syncChildrenStates() 581 { 582 return gst_bin_sync_children_states(gstBin) != 0; 583 } 584 585 protected class OnDeepElementAddedDelegateWrapper 586 { 587 static OnDeepElementAddedDelegateWrapper[] listeners; 588 void delegate(Bin, Element, Bin) dlg; 589 gulong handlerId; 590 591 this(void delegate(Bin, Element, Bin) dlg) 592 { 593 this.dlg = dlg; 594 this.listeners ~= this; 595 } 596 597 void remove(OnDeepElementAddedDelegateWrapper source) 598 { 599 foreach(index, wrapper; listeners) 600 { 601 if (wrapper.handlerId == source.handlerId) 602 { 603 listeners[index] = null; 604 listeners = std.algorithm.remove(listeners, index); 605 break; 606 } 607 } 608 } 609 } 610 611 /** 612 * Will be emitted after the element was added to sub_bin. 613 * 614 * Params: 615 * subBin = the #GstBin the element was added to 616 * element = the #GstElement that was added to @sub_bin 617 * 618 * Since: 1.10 619 */ 620 gulong addOnDeepElementAdded(void delegate(Bin, Element, Bin) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 621 { 622 auto wrapper = new OnDeepElementAddedDelegateWrapper(dlg); 623 wrapper.handlerId = Signals.connectData( 624 this, 625 "deep-element-added", 626 cast(GCallback)&callBackDeepElementAdded, 627 cast(void*)wrapper, 628 cast(GClosureNotify)&callBackDeepElementAddedDestroy, 629 connectFlags); 630 return wrapper.handlerId; 631 } 632 633 extern(C) static void callBackDeepElementAdded(GstBin* binStruct, GstBin* subBin, GstElement* element, OnDeepElementAddedDelegateWrapper wrapper) 634 { 635 wrapper.dlg(ObjectG.getDObject!(Bin)(subBin), ObjectG.getDObject!(Element)(element), wrapper.outer); 636 } 637 638 extern(C) static void callBackDeepElementAddedDestroy(OnDeepElementAddedDelegateWrapper wrapper, GClosure* closure) 639 { 640 wrapper.remove(wrapper); 641 } 642 643 protected class OnDeepElementRemovedDelegateWrapper 644 { 645 static OnDeepElementRemovedDelegateWrapper[] listeners; 646 void delegate(Bin, Element, Bin) dlg; 647 gulong handlerId; 648 649 this(void delegate(Bin, Element, Bin) dlg) 650 { 651 this.dlg = dlg; 652 this.listeners ~= this; 653 } 654 655 void remove(OnDeepElementRemovedDelegateWrapper source) 656 { 657 foreach(index, wrapper; listeners) 658 { 659 if (wrapper.handlerId == source.handlerId) 660 { 661 listeners[index] = null; 662 listeners = std.algorithm.remove(listeners, index); 663 break; 664 } 665 } 666 } 667 } 668 669 /** 670 * Will be emitted after the element was removed from sub_bin. 671 * 672 * Params: 673 * subBin = the #GstBin the element was removed from 674 * element = the #GstElement that was removed from @sub_bin 675 * 676 * Since: 1.10 677 */ 678 gulong addOnDeepElementRemoved(void delegate(Bin, Element, Bin) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 679 { 680 auto wrapper = new OnDeepElementRemovedDelegateWrapper(dlg); 681 wrapper.handlerId = Signals.connectData( 682 this, 683 "deep-element-removed", 684 cast(GCallback)&callBackDeepElementRemoved, 685 cast(void*)wrapper, 686 cast(GClosureNotify)&callBackDeepElementRemovedDestroy, 687 connectFlags); 688 return wrapper.handlerId; 689 } 690 691 extern(C) static void callBackDeepElementRemoved(GstBin* binStruct, GstBin* subBin, GstElement* element, OnDeepElementRemovedDelegateWrapper wrapper) 692 { 693 wrapper.dlg(ObjectG.getDObject!(Bin)(subBin), ObjectG.getDObject!(Element)(element), wrapper.outer); 694 } 695 696 extern(C) static void callBackDeepElementRemovedDestroy(OnDeepElementRemovedDelegateWrapper wrapper, GClosure* closure) 697 { 698 wrapper.remove(wrapper); 699 } 700 701 protected class OnDoLatencyDelegateWrapper 702 { 703 static OnDoLatencyDelegateWrapper[] listeners; 704 bool delegate(Bin) dlg; 705 gulong handlerId; 706 707 this(bool delegate(Bin) dlg) 708 { 709 this.dlg = dlg; 710 this.listeners ~= this; 711 } 712 713 void remove(OnDoLatencyDelegateWrapper source) 714 { 715 foreach(index, wrapper; listeners) 716 { 717 if (wrapper.handlerId == source.handlerId) 718 { 719 listeners[index] = null; 720 listeners = std.algorithm.remove(listeners, index); 721 break; 722 } 723 } 724 } 725 } 726 727 /** 728 * Will be emitted when the bin needs to perform latency calculations. This 729 * signal is only emitted for toplevel bins or when async-handling is 730 * enabled. 731 * 732 * Only one signal handler is invoked. If no signals are connected, the 733 * default handler is invoked, which will query and distribute the lowest 734 * possible latency to all sinks. 735 * 736 * Connect to this signal if the default latency calculations are not 737 * sufficient, like when you need different latencies for different sinks in 738 * the same pipeline. 739 */ 740 gulong addOnDoLatency(bool delegate(Bin) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 741 { 742 auto wrapper = new OnDoLatencyDelegateWrapper(dlg); 743 wrapper.handlerId = Signals.connectData( 744 this, 745 "do-latency", 746 cast(GCallback)&callBackDoLatency, 747 cast(void*)wrapper, 748 cast(GClosureNotify)&callBackDoLatencyDestroy, 749 connectFlags); 750 return wrapper.handlerId; 751 } 752 753 extern(C) static int callBackDoLatency(GstBin* binStruct, OnDoLatencyDelegateWrapper wrapper) 754 { 755 return wrapper.dlg(wrapper.outer); 756 } 757 758 extern(C) static void callBackDoLatencyDestroy(OnDoLatencyDelegateWrapper wrapper, GClosure* closure) 759 { 760 wrapper.remove(wrapper); 761 } 762 763 protected class OnElementAddedDelegateWrapper 764 { 765 static OnElementAddedDelegateWrapper[] listeners; 766 void delegate(Element, Bin) dlg; 767 gulong handlerId; 768 769 this(void delegate(Element, Bin) dlg) 770 { 771 this.dlg = dlg; 772 this.listeners ~= this; 773 } 774 775 void remove(OnElementAddedDelegateWrapper source) 776 { 777 foreach(index, wrapper; listeners) 778 { 779 if (wrapper.handlerId == source.handlerId) 780 { 781 listeners[index] = null; 782 listeners = std.algorithm.remove(listeners, index); 783 break; 784 } 785 } 786 } 787 } 788 789 /** 790 * Will be emitted after the element was added to the bin. 791 * 792 * Params: 793 * element = the #GstElement that was added to the bin 794 */ 795 gulong addOnElementAdded(void delegate(Element, Bin) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 796 { 797 auto wrapper = new OnElementAddedDelegateWrapper(dlg); 798 wrapper.handlerId = Signals.connectData( 799 this, 800 "element-added", 801 cast(GCallback)&callBackElementAdded, 802 cast(void*)wrapper, 803 cast(GClosureNotify)&callBackElementAddedDestroy, 804 connectFlags); 805 return wrapper.handlerId; 806 } 807 808 extern(C) static void callBackElementAdded(GstBin* binStruct, GstElement* element, OnElementAddedDelegateWrapper wrapper) 809 { 810 wrapper.dlg(ObjectG.getDObject!(Element)(element), wrapper.outer); 811 } 812 813 extern(C) static void callBackElementAddedDestroy(OnElementAddedDelegateWrapper wrapper, GClosure* closure) 814 { 815 wrapper.remove(wrapper); 816 } 817 818 protected class OnElementRemovedDelegateWrapper 819 { 820 static OnElementRemovedDelegateWrapper[] listeners; 821 void delegate(Element, Bin) dlg; 822 gulong handlerId; 823 824 this(void delegate(Element, Bin) dlg) 825 { 826 this.dlg = dlg; 827 this.listeners ~= this; 828 } 829 830 void remove(OnElementRemovedDelegateWrapper source) 831 { 832 foreach(index, wrapper; listeners) 833 { 834 if (wrapper.handlerId == source.handlerId) 835 { 836 listeners[index] = null; 837 listeners = std.algorithm.remove(listeners, index); 838 break; 839 } 840 } 841 } 842 } 843 844 /** 845 * Will be emitted after the element was removed from the bin. 846 * 847 * Params: 848 * element = the #GstElement that was removed from the bin 849 */ 850 gulong addOnElementRemoved(void delegate(Element, Bin) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 851 { 852 auto wrapper = new OnElementRemovedDelegateWrapper(dlg); 853 wrapper.handlerId = Signals.connectData( 854 this, 855 "element-removed", 856 cast(GCallback)&callBackElementRemoved, 857 cast(void*)wrapper, 858 cast(GClosureNotify)&callBackElementRemovedDestroy, 859 connectFlags); 860 return wrapper.handlerId; 861 } 862 863 extern(C) static void callBackElementRemoved(GstBin* binStruct, GstElement* element, OnElementRemovedDelegateWrapper wrapper) 864 { 865 wrapper.dlg(ObjectG.getDObject!(Element)(element), wrapper.outer); 866 } 867 868 extern(C) static void callBackElementRemovedDestroy(OnElementRemovedDelegateWrapper wrapper, GClosure* closure) 869 { 870 wrapper.remove(wrapper); 871 } 872 }