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.ObjectGst;
26 
27 private import glib.ErrorG;
28 private import glib.ListG;
29 private import glib.Str;
30 private import gobject.ObjectG;
31 private import gobject.ParamSpec;
32 private import gobject.Signals;
33 private import gobject.Value;
34 private import gstreamer.ControlBinding;
35 private import gstreamerc.gstreamer;
36 public  import gstreamerc.gstreamertypes;
37 private import std.algorithm;
38 
39 
40 /**
41  * #GstObject provides a root for the object hierarchy tree filed in by the
42  * GStreamer library.  It is currently a thin wrapper on top of
43  * #GInitiallyUnowned. It is an abstract class that is not very usable on its own.
44  * 
45  * #GstObject gives us basic refcounting, parenting functionality and locking.
46  * Most of the functions are just extended for special GStreamer needs and can be
47  * found under the same name in the base class of #GstObject which is #GObject
48  * (e.g. g_object_ref() becomes gst_object_ref()).
49  * 
50  * Since #GstObject derives from #GInitiallyUnowned, it also inherits the
51  * floating reference. Be aware that functions such as gst_bin_add() and
52  * gst_element_add_pad() take ownership of the floating reference.
53  * 
54  * In contrast to #GObject instances, #GstObject adds a name property. The functions
55  * gst_object_set_name() and gst_object_get_name() are used to set/get the name
56  * of the object.
57  * 
58  * ## controlled properties
59  * 
60  * Controlled properties offers a lightweight way to adjust gobject properties
61  * over stream-time. It works by using time-stamped value pairs that are queued
62  * for element-properties. At run-time the elements continuously pull value
63  * changes for the current stream-time.
64  * 
65  * What needs to be changed in a #GstElement?
66  * Very little - it is just two steps to make a plugin controllable!
67  * 
68  * * mark gobject-properties paramspecs that make sense to be controlled,
69  * by GST_PARAM_CONTROLLABLE.
70  * 
71  * * when processing data (get, chain, loop function) at the beginning call
72  * gst_object_sync_values(element,timestamp).
73  * This will make the controller update all GObject properties that are
74  * under its control with the current values based on the timestamp.
75  * 
76  * What needs to be done in applications? Again it's not a lot to change.
77  * 
78  * * create a #GstControlSource.
79  * csource = gst_interpolation_control_source_new ();
80  * g_object_set (csource, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL);
81  * 
82  * * Attach the #GstControlSource on the controller to a property.
83  * gst_object_add_control_binding (object, gst_direct_control_binding_new (object, "prop1", csource));
84  * 
85  * * Set the control values
86  * gst_timed_value_control_source_set ((GstTimedValueControlSource *)csource,0 * GST_SECOND, value1);
87  * gst_timed_value_control_source_set ((GstTimedValueControlSource *)csource,1 * GST_SECOND, value2);
88  * 
89  * * start your pipeline
90  */
91 public class ObjectGst : ObjectG
92 {
93 	/** the main Gtk struct */
94 	protected GstObject* gstObject;
95 
96 	/** Get the main Gtk struct */
97 	public GstObject* getObjectGstStruct()
98 	{
99 		return gstObject;
100 	}
101 
102 	/** the main Gtk struct as a void* */
103 	protected override void* getStruct()
104 	{
105 		return cast(void*)gstObject;
106 	}
107 
108 	protected override void setStruct(GObject* obj)
109 	{
110 		gstObject = cast(GstObject*)obj;
111 		super.setStruct(obj);
112 	}
113 
114 	/**
115 	 * Sets our main struct and passes it to the parent class.
116 	 */
117 	public this (GstObject* gstObject, bool ownedRef = false)
118 	{
119 		this.gstObject = gstObject;
120 		super(cast(GObject*)gstObject, ownedRef);
121 	}
122 
123 
124 	/** */
125 	public static GType getType()
126 	{
127 		return gst_object_get_type();
128 	}
129 
130 	/**
131 	 * Checks to see if there is any object named @name in @list. This function
132 	 * does not do any locking of any kind. You might want to protect the
133 	 * provided list with the lock of the owner of the list. This function
134 	 * will lock each #GstObject in the list to compare the name, so be
135 	 * careful when passing a list with a locked object.
136 	 *
137 	 * Params:
138 	 *     list = a list of #GstObject to
139 	 *         check through
140 	 *     name = the name to search for
141 	 *
142 	 * Returns: %TRUE if a #GstObject named @name does not appear in @list,
143 	 *     %FALSE if it does.
144 	 *
145 	 *     MT safe. Grabs and releases the LOCK of each object in the list.
146 	 */
147 	public static bool checkUniqueness(ListG list, string name)
148 	{
149 		return gst_object_check_uniqueness((list is null) ? null : list.getListGStruct(), Str.toStringz(name)) != 0;
150 	}
151 
152 	/**
153 	 * A default deep_notify signal callback for an object. The user data
154 	 * should contain a pointer to an array of strings that should be excluded
155 	 * from the notify. The default handler will print the new value of the property
156 	 * using g_print.
157 	 *
158 	 * MT safe. This function grabs and releases @object's LOCK for getting its
159 	 * path string.
160 	 *
161 	 * Params:
162 	 *     object = the #GObject that signalled the notify.
163 	 *     orig = a #GstObject that initiated the notify.
164 	 *     pspec = a #GParamSpec of the property.
165 	 *     excludedProps = a set of user-specified properties to exclude or %NULL to show
166 	 *         all changes.
167 	 */
168 	public static void defaultDeepNotify(ObjectG object, ObjectGst orig, ParamSpec pspec, string[] excludedProps)
169 	{
170 		gst_object_default_deep_notify((object is null) ? null : object.getObjectGStruct(), (orig is null) ? null : orig.getObjectGstStruct(), (pspec is null) ? null : pspec.getParamSpecStruct(), Str.toStringzArray(excludedProps));
171 	}
172 
173 	/**
174 	 * Increase the reference count of @object, and possibly remove the floating
175 	 * reference, if @object has a floating reference.
176 	 *
177 	 * In other words, if the object is floating, then this call "assumes ownership"
178 	 * of the floating reference, converting it to a normal reference by clearing
179 	 * the floating flag while leaving the reference count unchanged. If the object
180 	 * is not floating, then this call adds a new normal reference increasing the
181 	 * reference count by one.
182 	 *
183 	 * Params:
184 	 *     object = a #GstObject to sink
185 	 */
186 	public static void* refSink(void* object)
187 	{
188 		return gst_object_ref_sink(object);
189 	}
190 
191 	/**
192 	 * Atomically modifies a pointer to point to a new object.
193 	 * The reference count of @oldobj is decreased and the reference count of
194 	 * @newobj is increased.
195 	 *
196 	 * Either @newobj and the value pointed to by @oldobj may be %NULL.
197 	 *
198 	 * Params:
199 	 *     oldobj = pointer to a place of
200 	 *         a #GstObject to replace
201 	 *     newobj = a new #GstObject
202 	 *
203 	 * Returns: %TRUE if @newobj was different from @oldobj
204 	 */
205 	public static bool replace(ref ObjectGst oldobj, ObjectGst newobj)
206 	{
207 		GstObject* outoldobj = oldobj.getObjectGstStruct();
208 		
209 		auto p = gst_object_replace(&outoldobj, (newobj is null) ? null : newobj.getObjectGstStruct()) != 0;
210 		
211 		oldobj = ObjectG.getDObject!(ObjectGst)(outoldobj);
212 		
213 		return p;
214 	}
215 
216 	/**
217 	 * Attach the #GstControlBinding to the object. If there already was a
218 	 * #GstControlBinding for this property it will be replaced.
219 	 *
220 	 * The @object will take ownership of the @binding.
221 	 *
222 	 * Params:
223 	 *     binding = the #GstControlBinding that should be used
224 	 *
225 	 * Returns: %FALSE if the given @binding has not been setup for this object or
226 	 *     has been setup for a non suitable property, %TRUE otherwise.
227 	 */
228 	public bool addControlBinding(ControlBinding binding)
229 	{
230 		return gst_object_add_control_binding(gstObject, (binding is null) ? null : binding.getControlBindingStruct()) != 0;
231 	}
232 
233 	/**
234 	 * A default error function that uses g_printerr() to display the error message
235 	 * and the optional debug sting..
236 	 *
237 	 * The default handler will simply print the error string using g_print.
238 	 *
239 	 * Params:
240 	 *     error = the GError.
241 	 *     dbg = an additional debug information string, or %NULL
242 	 */
243 	public void defaultError(ErrorG error, string dbg)
244 	{
245 		gst_object_default_error(gstObject, (error is null) ? null : error.getErrorGStruct(), Str.toStringz(dbg));
246 	}
247 
248 	/**
249 	 * Gets the corresponding #GstControlBinding for the property. This should be
250 	 * unreferenced again after use.
251 	 *
252 	 * Params:
253 	 *     propertyName = name of the property
254 	 *
255 	 * Returns: the #GstControlBinding for
256 	 *     @property_name or %NULL if the property is not controlled.
257 	 */
258 	public ControlBinding getControlBinding(string propertyName)
259 	{
260 		auto p = gst_object_get_control_binding(gstObject, Str.toStringz(propertyName));
261 		
262 		if(p is null)
263 		{
264 			return null;
265 		}
266 		
267 		return ObjectG.getDObject!(ControlBinding)(cast(GstControlBinding*) p, true);
268 	}
269 
270 	/**
271 	 * Obtain the control-rate for this @object. Audio processing #GstElement
272 	 * objects will use this rate to sub-divide their processing loop and call
273 	 * gst_object_sync_values() inbetween. The length of the processing segment
274 	 * should be up to @control-rate nanoseconds.
275 	 *
276 	 * If the @object is not under property control, this will return
277 	 * %GST_CLOCK_TIME_NONE. This allows the element to avoid the sub-dividing.
278 	 *
279 	 * The control-rate is not expected to change if the element is in
280 	 * %GST_STATE_PAUSED or %GST_STATE_PLAYING.
281 	 *
282 	 * Returns: the control rate in nanoseconds
283 	 */
284 	public GstClockTime getControlRate()
285 	{
286 		return gst_object_get_control_rate(gstObject);
287 	}
288 
289 	/**
290 	 * Gets a number of #GValues for the given controlled property starting at the
291 	 * requested time. The array @values need to hold enough space for @n_values of
292 	 * #GValue.
293 	 *
294 	 * This function is useful if one wants to e.g. draw a graph of the control
295 	 * curve or apply a control curve sample by sample.
296 	 *
297 	 * Params:
298 	 *     propertyName = the name of the property to get
299 	 *     timestamp = the time that should be processed
300 	 *     interval = the time spacing between subsequent values
301 	 *     nValues = the number of values
302 	 *     values = array to put control-values in
303 	 *
304 	 * Returns: %TRUE if the given array could be filled, %FALSE otherwise
305 	 */
306 	public bool getGValueArray(string propertyName, GstClockTime timestamp, GstClockTime interval, uint nValues, Value values)
307 	{
308 		return gst_object_get_g_value_array(gstObject, Str.toStringz(propertyName), timestamp, interval, nValues, (values is null) ? null : values.getValueStruct()) != 0;
309 	}
310 
311 	/**
312 	 * Returns a copy of the name of @object.
313 	 * Caller should g_free() the return value after usage.
314 	 * For a nameless object, this returns %NULL, which you can safely g_free()
315 	 * as well.
316 	 *
317 	 * Free-function: g_free
318 	 *
319 	 * Returns: the name of @object. g_free()
320 	 *     after usage.
321 	 *
322 	 *     MT safe. This function grabs and releases @object's LOCK.
323 	 */
324 	public string getName()
325 	{
326 		auto retStr = gst_object_get_name(gstObject);
327 		
328 		scope(exit) Str.freeString(retStr);
329 		return Str.toString(retStr);
330 	}
331 
332 	/**
333 	 * Returns the parent of @object. This function increases the refcount
334 	 * of the parent object so you should gst_object_unref() it after usage.
335 	 *
336 	 * Returns: parent of @object, this can be
337 	 *     %NULL if @object has no parent. unref after usage.
338 	 *
339 	 *     MT safe. Grabs and releases @object's LOCK.
340 	 */
341 	public ObjectGst getParent()
342 	{
343 		auto p = gst_object_get_parent(gstObject);
344 		
345 		if(p is null)
346 		{
347 			return null;
348 		}
349 		
350 		return ObjectG.getDObject!(ObjectGst)(cast(GstObject*) p, true);
351 	}
352 
353 	/**
354 	 * Generates a string describing the path of @object in
355 	 * the object hierarchy. Only useful (or used) for debugging.
356 	 *
357 	 * Free-function: g_free
358 	 *
359 	 * Returns: a string describing the path of @object. You must
360 	 *     g_free() the string after usage.
361 	 *
362 	 *     MT safe. Grabs and releases the #GstObject's LOCK for all objects
363 	 *     in the hierarchy.
364 	 */
365 	public string getPathString()
366 	{
367 		auto retStr = gst_object_get_path_string(gstObject);
368 		
369 		scope(exit) Str.freeString(retStr);
370 		return Str.toString(retStr);
371 	}
372 
373 	/**
374 	 * Gets the value for the given controlled property at the requested time.
375 	 *
376 	 * Params:
377 	 *     propertyName = the name of the property to get
378 	 *     timestamp = the time the control-change should be read from
379 	 *
380 	 * Returns: the GValue of the property at the given time,
381 	 *     or %NULL if the property isn't controlled.
382 	 */
383 	public Value getValue(string propertyName, GstClockTime timestamp)
384 	{
385 		auto p = gst_object_get_value(gstObject, Str.toStringz(propertyName), timestamp);
386 		
387 		if(p is null)
388 		{
389 			return null;
390 		}
391 		
392 		return ObjectG.getDObject!(Value)(cast(GValue*) p, true);
393 	}
394 
395 	/**
396 	 * Gets a number of values for the given controlled property starting at the
397 	 * requested time. The array @values need to hold enough space for @n_values of
398 	 * the same type as the objects property's type.
399 	 *
400 	 * This function is useful if one wants to e.g. draw a graph of the control
401 	 * curve or apply a control curve sample by sample.
402 	 *
403 	 * The values are unboxed and ready to be used. The similar function
404 	 * gst_object_get_g_value_array() returns the array as #GValues and is
405 	 * better suites for bindings.
406 	 *
407 	 * Params:
408 	 *     propertyName = the name of the property to get
409 	 *     timestamp = the time that should be processed
410 	 *     interval = the time spacing between subsequent values
411 	 *     nValues = the number of values
412 	 *     values = array to put control-values in
413 	 *
414 	 * Returns: %TRUE if the given array could be filled, %FALSE otherwise
415 	 */
416 	public bool getValueArray(string propertyName, GstClockTime timestamp, GstClockTime interval, uint nValues, void* values)
417 	{
418 		return gst_object_get_value_array(gstObject, Str.toStringz(propertyName), timestamp, interval, nValues, values) != 0;
419 	}
420 
421 	/**
422 	 * Check if the @object has active controlled properties.
423 	 *
424 	 * Returns: %TRUE if the object has active controlled properties
425 	 */
426 	public bool hasActiveControlBindings()
427 	{
428 		return gst_object_has_active_control_bindings(gstObject) != 0;
429 	}
430 
431 	/**
432 	 * Check if @object has an ancestor @ancestor somewhere up in
433 	 * the hierarchy. One can e.g. check if a #GstElement is inside a #GstPipeline.
434 	 *
435 	 * Deprecated: Use gst_object_has_as_ancestor() instead.
436 	 *
437 	 * MT safe. Grabs and releases @object's locks.
438 	 *
439 	 * Params:
440 	 *     ancestor = a #GstObject to check as ancestor
441 	 *
442 	 * Returns: %TRUE if @ancestor is an ancestor of @object.
443 	 */
444 	public bool hasAncestor(ObjectGst ancestor)
445 	{
446 		return gst_object_has_ancestor(gstObject, (ancestor is null) ? null : ancestor.getObjectGstStruct()) != 0;
447 	}
448 
449 	/**
450 	 * Check if @object has an ancestor @ancestor somewhere up in
451 	 * the hierarchy. One can e.g. check if a #GstElement is inside a #GstPipeline.
452 	 *
453 	 * Params:
454 	 *     ancestor = a #GstObject to check as ancestor
455 	 *
456 	 * Returns: %TRUE if @ancestor is an ancestor of @object.
457 	 *
458 	 *     MT safe. Grabs and releases @object's locks.
459 	 */
460 	public bool hasAsAncestor(ObjectGst ancestor)
461 	{
462 		return gst_object_has_as_ancestor(gstObject, (ancestor is null) ? null : ancestor.getObjectGstStruct()) != 0;
463 	}
464 
465 	/**
466 	 * Check if @parent is the parent of @object.
467 	 * E.g. a #GstElement can check if it owns a given #GstPad.
468 	 *
469 	 * Params:
470 	 *     parent = a #GstObject to check as parent
471 	 *
472 	 * Returns: %FALSE if either @object or @parent is %NULL. %TRUE if @parent is
473 	 *     the parent of @object. Otherwise %FALSE.
474 	 *
475 	 *     MT safe. Grabs and releases @object's locks.
476 	 *
477 	 * Since: 1.6
478 	 */
479 	public bool hasAsParent(ObjectGst parent)
480 	{
481 		return gst_object_has_as_parent(gstObject, (parent is null) ? null : parent.getObjectGstStruct()) != 0;
482 	}
483 
484 	/**
485 	 * Increments the reference count on @object. This function
486 	 * does not take the lock on @object because it relies on
487 	 * atomic refcounting.
488 	 *
489 	 * This object returns the input parameter to ease writing
490 	 * constructs like :
491 	 * result = gst_object_ref (object->parent);
492 	 *
493 	 * Returns: A pointer to @object
494 	 */
495 	public override ObjectGst doref()
496 	{
497 		auto p = gst_object_ref(gstObject);
498 		
499 		if(p is null)
500 		{
501 			return null;
502 		}
503 		
504 		return ObjectG.getDObject!(ObjectGst)(cast(GstObject*) p, true);
505 	}
506 
507 	/**
508 	 * Removes the corresponding #GstControlBinding. If it was the
509 	 * last ref of the binding, it will be disposed.
510 	 *
511 	 * Params:
512 	 *     binding = the binding
513 	 *
514 	 * Returns: %TRUE if the binding could be removed.
515 	 */
516 	public bool removeControlBinding(ControlBinding binding)
517 	{
518 		return gst_object_remove_control_binding(gstObject, (binding is null) ? null : binding.getControlBindingStruct()) != 0;
519 	}
520 
521 	/**
522 	 * This function is used to disable the control bindings on a property for
523 	 * some time, i.e. gst_object_sync_values() will do nothing for the
524 	 * property.
525 	 *
526 	 * Params:
527 	 *     propertyName = property to disable
528 	 *     disabled = boolean that specifies whether to disable the controller
529 	 *         or not.
530 	 */
531 	public void setControlBindingDisabled(string propertyName, bool disabled)
532 	{
533 		gst_object_set_control_binding_disabled(gstObject, Str.toStringz(propertyName), disabled);
534 	}
535 
536 	/**
537 	 * This function is used to disable all controlled properties of the @object for
538 	 * some time, i.e. gst_object_sync_values() will do nothing.
539 	 *
540 	 * Params:
541 	 *     disabled = boolean that specifies whether to disable the controller
542 	 *         or not.
543 	 */
544 	public void setControlBindingsDisabled(bool disabled)
545 	{
546 		gst_object_set_control_bindings_disabled(gstObject, disabled);
547 	}
548 
549 	/**
550 	 * Change the control-rate for this @object. Audio processing #GstElement
551 	 * objects will use this rate to sub-divide their processing loop and call
552 	 * gst_object_sync_values() inbetween. The length of the processing segment
553 	 * should be up to @control-rate nanoseconds.
554 	 *
555 	 * The control-rate should not change if the element is in %GST_STATE_PAUSED or
556 	 * %GST_STATE_PLAYING.
557 	 *
558 	 * Params:
559 	 *     controlRate = the new control-rate in nanoseconds.
560 	 */
561 	public void setControlRate(GstClockTime controlRate)
562 	{
563 		gst_object_set_control_rate(gstObject, controlRate);
564 	}
565 
566 	/**
567 	 * Sets the name of @object, or gives @object a guaranteed unique
568 	 * name (if @name is %NULL).
569 	 * This function makes a copy of the provided name, so the caller
570 	 * retains ownership of the name it sent.
571 	 *
572 	 * Params:
573 	 *     name = new name of object
574 	 *
575 	 * Returns: %TRUE if the name could be set. Since Objects that have
576 	 *     a parent cannot be renamed, this function returns %FALSE in those
577 	 *     cases.
578 	 *
579 	 *     MT safe.  This function grabs and releases @object's LOCK.
580 	 */
581 	public bool setName(string name)
582 	{
583 		return gst_object_set_name(gstObject, Str.toStringz(name)) != 0;
584 	}
585 
586 	/**
587 	 * Sets the parent of @object to @parent. The object's reference count will
588 	 * be incremented, and any floating reference will be removed (see gst_object_ref_sink()).
589 	 *
590 	 * Params:
591 	 *     parent = new parent of object
592 	 *
593 	 * Returns: %TRUE if @parent could be set or %FALSE when @object
594 	 *     already had a parent or @object and @parent are the same.
595 	 *
596 	 *     MT safe. Grabs and releases @object's LOCK.
597 	 */
598 	public bool setParent(ObjectGst parent)
599 	{
600 		return gst_object_set_parent(gstObject, (parent is null) ? null : parent.getObjectGstStruct()) != 0;
601 	}
602 
603 	/**
604 	 * Returns a suggestion for timestamps where buffers should be split
605 	 * to get best controller results.
606 	 *
607 	 * Returns: Returns the suggested timestamp or %GST_CLOCK_TIME_NONE
608 	 *     if no control-rate was set.
609 	 */
610 	public GstClockTime suggestNextSync()
611 	{
612 		return gst_object_suggest_next_sync(gstObject);
613 	}
614 
615 	/**
616 	 * Sets the properties of the object, according to the #GstControlSources that
617 	 * (maybe) handle them and for the given timestamp.
618 	 *
619 	 * If this function fails, it is most likely the application developers fault.
620 	 * Most probably the control sources are not setup correctly.
621 	 *
622 	 * Params:
623 	 *     timestamp = the time that should be processed
624 	 *
625 	 * Returns: %TRUE if the controller values could be applied to the object
626 	 *     properties, %FALSE otherwise
627 	 */
628 	public bool syncValues(GstClockTime timestamp)
629 	{
630 		return gst_object_sync_values(gstObject, timestamp) != 0;
631 	}
632 
633 	/**
634 	 * Clear the parent of @object, removing the associated reference.
635 	 * This function decreases the refcount of @object.
636 	 *
637 	 * MT safe. Grabs and releases @object's lock.
638 	 */
639 	public void unparent()
640 	{
641 		gst_object_unparent(gstObject);
642 	}
643 
644 	/**
645 	 * Decrements the reference count on @object.  If reference count hits
646 	 * zero, destroy @object. This function does not take the lock
647 	 * on @object as it relies on atomic refcounting.
648 	 *
649 	 * The unref method should never be called with the LOCK held since
650 	 * this might deadlock the dispose function.
651 	 */
652 	public override void unref()
653 	{
654 		gst_object_unref(gstObject);
655 	}
656 
657 	protected class OnDeepNotifyDelegateWrapper
658 	{
659 		static OnDeepNotifyDelegateWrapper[] listeners;
660 		void delegate(ObjectGst, ParamSpec, ObjectGst) dlg;
661 		gulong handlerId;
662 		
663 		this(void delegate(ObjectGst, ParamSpec, ObjectGst) dlg)
664 		{
665 			this.dlg = dlg;
666 			this.listeners ~= this;
667 		}
668 		
669 		void remove(OnDeepNotifyDelegateWrapper source)
670 		{
671 			foreach(index, wrapper; listeners)
672 			{
673 				if (wrapper.handlerId == source.handlerId)
674 				{
675 					listeners[index] = null;
676 					listeners = std.algorithm.remove(listeners, index);
677 					break;
678 				}
679 			}
680 		}
681 	}
682 
683 	/**
684 	 * The deep notify signal is used to be notified of property changes. It is
685 	 * typically attached to the toplevel bin to receive notifications from all
686 	 * the elements contained in that bin.
687 	 *
688 	 * Params:
689 	 *     propObject = the object that originated the signal
690 	 *     prop = the property that changed
691 	 */
692 	gulong addOnDeepNotify(void delegate(ObjectGst, ParamSpec, ObjectGst) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
693 	{
694 		auto wrapper = new OnDeepNotifyDelegateWrapper(dlg);
695 		wrapper.handlerId = Signals.connectData(
696 			this,
697 			"deep-notify",
698 			cast(GCallback)&callBackDeepNotify,
699 			cast(void*)wrapper,
700 			cast(GClosureNotify)&callBackDeepNotifyDestroy,
701 			connectFlags);
702 		return wrapper.handlerId;
703 	}
704 	
705 	extern(C) static void callBackDeepNotify(GstObject* objectgstStruct, GstObject* propObject, GParamSpec* prop, OnDeepNotifyDelegateWrapper wrapper)
706 	{
707 		wrapper.dlg(ObjectG.getDObject!(ObjectGst)(propObject), ObjectG.getDObject!(ParamSpec)(prop), wrapper.outer);
708 	}
709 	
710 	extern(C) static void callBackDeepNotifyDestroy(OnDeepNotifyDelegateWrapper wrapper, GClosure* closure)
711 	{
712 		wrapper.remove(wrapper);
713 	}
714 }