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