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