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