// This file was generated by the Gtk# code generator.
// Any changes made will be lost if regenerated.

namespace Gst {

	using System;
	using System.Collections;
	using System.Collections.Generic;
	using System.Runtime.InteropServices;

#region Autogenerated code
	public partial class TaskPool : Gst.Object {

		public TaskPool (IntPtr raw) : base(raw) {}

		[DllImport("gstreamer-1.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
		static extern IntPtr gst_task_pool_new();

		public TaskPool () : base (IntPtr.Zero)
		{
			if (GetType () != typeof (TaskPool)) {
				CreateNativeObject (new string [0], new GLib.Value[0]);
				return;
			}
			Raw = gst_task_pool_new();
		}

		static PrepareNativeDelegate Prepare_cb_delegate;
		static PrepareNativeDelegate PrepareVMCallback {
			get {
				if (Prepare_cb_delegate == null)
					Prepare_cb_delegate = new PrepareNativeDelegate (Prepare_cb);
				return Prepare_cb_delegate;
			}
		}

		static void OverridePrepare (GLib.GType gtype)
		{
			OverridePrepare (gtype, PrepareVMCallback);
		}

		static void OverridePrepare (GLib.GType gtype, PrepareNativeDelegate callback)
		{
			unsafe {
				IntPtr* raw_ptr = (IntPtr*)(((long) gtype.GetClassPtr()) + (long) class_abi.GetFieldOffset("prepare"));
				*raw_ptr = Marshal.GetFunctionPointerForDelegate((Delegate) callback);
			}
		}

		[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
		delegate void PrepareNativeDelegate (IntPtr inst, out IntPtr error);

		static void Prepare_cb (IntPtr inst, out IntPtr error)
		{
			error = IntPtr.Zero;

			try {
				TaskPool __obj = GLib.Object.GetObject (inst, false) as TaskPool;
				__obj.OnPrepare ();
			} catch (Exception e) {
				GLib.ExceptionManager.RaiseUnhandledException (e, true);
				// NOTREACHED: above call does not return.
				throw e;
			}
		}

		[GLib.DefaultSignalHandler(Type=typeof(Gst.TaskPool), ConnectionMethod="OverridePrepare")]
		protected virtual void OnPrepare ()
		{
			InternalPrepare ();
		}

		private void InternalPrepare ()
		{
			PrepareNativeDelegate unmanaged = null;
			unsafe {
				IntPtr* raw_ptr = (IntPtr*)(((long) this.LookupGType().GetThresholdType().GetClassPtr()) + (long) class_abi.GetFieldOffset("prepare"));
				unmanaged = (PrepareNativeDelegate) Marshal.GetDelegateForFunctionPointer(*raw_ptr, typeof(PrepareNativeDelegate));
			}
			if (unmanaged == null) throw new InvalidOperationException ("No base method to invoke");

			IntPtr error = IntPtr.Zero;
			unmanaged (this.Handle, out error);
		}

		static CleanupNativeDelegate Cleanup_cb_delegate;
		static CleanupNativeDelegate CleanupVMCallback {
			get {
				if (Cleanup_cb_delegate == null)
					Cleanup_cb_delegate = new CleanupNativeDelegate (Cleanup_cb);
				return Cleanup_cb_delegate;
			}
		}

		static void OverrideCleanup (GLib.GType gtype)
		{
			OverrideCleanup (gtype, CleanupVMCallback);
		}

		static void OverrideCleanup (GLib.GType gtype, CleanupNativeDelegate callback)
		{
			unsafe {
				IntPtr* raw_ptr = (IntPtr*)(((long) gtype.GetClassPtr()) + (long) class_abi.GetFieldOffset("cleanup"));
				*raw_ptr = Marshal.GetFunctionPointerForDelegate((Delegate) callback);
			}
		}

		[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
		delegate void CleanupNativeDelegate (IntPtr inst);

		static void Cleanup_cb (IntPtr inst)
		{
			try {
				TaskPool __obj = GLib.Object.GetObject (inst, false) as TaskPool;
				__obj.OnCleanup ();
			} catch (Exception e) {
				GLib.ExceptionManager.RaiseUnhandledException (e, false);
			}
		}

		[GLib.DefaultSignalHandler(Type=typeof(Gst.TaskPool), ConnectionMethod="OverrideCleanup")]
		protected virtual void OnCleanup ()
		{
			InternalCleanup ();
		}

		private void InternalCleanup ()
		{
			CleanupNativeDelegate unmanaged = null;
			unsafe {
				IntPtr* raw_ptr = (IntPtr*)(((long) this.LookupGType().GetThresholdType().GetClassPtr()) + (long) class_abi.GetFieldOffset("cleanup"));
				unmanaged = (CleanupNativeDelegate) Marshal.GetDelegateForFunctionPointer(*raw_ptr, typeof(CleanupNativeDelegate));
			}
			if (unmanaged == null) return;

			unmanaged (this.Handle);
		}

		static PushNativeDelegate Push_cb_delegate;
		static PushNativeDelegate PushVMCallback {
			get {
				if (Push_cb_delegate == null)
					Push_cb_delegate = new PushNativeDelegate (Push_cb);
				return Push_cb_delegate;
			}
		}

		static void OverridePush (GLib.GType gtype)
		{
			OverridePush (gtype, PushVMCallback);
		}

		static void OverridePush (GLib.GType gtype, PushNativeDelegate callback)
		{
			unsafe {
				IntPtr* raw_ptr = (IntPtr*)(((long) gtype.GetClassPtr()) + (long) class_abi.GetFieldOffset("push"));
				*raw_ptr = Marshal.GetFunctionPointerForDelegate((Delegate) callback);
			}
		}

		[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
		delegate IntPtr PushNativeDelegate (IntPtr inst, GstSharp.TaskPoolFunctionNative func, IntPtr user_data, out IntPtr error);

		static IntPtr Push_cb (IntPtr inst, GstSharp.TaskPoolFunctionNative func, IntPtr user_data, out IntPtr error)
		{
			error = IntPtr.Zero;

			try {
				TaskPool __obj = GLib.Object.GetObject (inst, false) as TaskPool;
				IntPtr __result;
				GstSharp.TaskPoolFunctionInvoker func_invoker = new GstSharp.TaskPoolFunctionInvoker (func, user_data);
				__result = __obj.OnPush (func_invoker.Handler);
				return __result;
			} catch (Exception e) {
				GLib.ExceptionManager.RaiseUnhandledException (e, true);
				// NOTREACHED: above call does not return.
				throw e;
			}
		}

		[GLib.DefaultSignalHandler(Type=typeof(Gst.TaskPool), ConnectionMethod="OverridePush")]
		protected virtual IntPtr OnPush (Gst.TaskPoolFunction func)
		{
			return InternalPush (func);
		}

		private IntPtr InternalPush (Gst.TaskPoolFunction func)
		{
			PushNativeDelegate unmanaged = null;
			unsafe {
				IntPtr* raw_ptr = (IntPtr*)(((long) this.LookupGType().GetThresholdType().GetClassPtr()) + (long) class_abi.GetFieldOffset("push"));
				unmanaged = (PushNativeDelegate) Marshal.GetDelegateForFunctionPointer(*raw_ptr, typeof(PushNativeDelegate));
			}
			if (unmanaged == null) throw new InvalidOperationException ("No base method to invoke");

			GstSharp.TaskPoolFunctionWrapper func_wrapper = new GstSharp.TaskPoolFunctionWrapper (func);
			func_wrapper.PersistUntilCalled ();
			IntPtr error = IntPtr.Zero;
			IntPtr __result = unmanaged (this.Handle, func_wrapper.NativeDelegate, IntPtr.Zero, out error);
			return __result;
		}

		static JoinNativeDelegate Join_cb_delegate;
		static JoinNativeDelegate JoinVMCallback {
			get {
				if (Join_cb_delegate == null)
					Join_cb_delegate = new JoinNativeDelegate (Join_cb);
				return Join_cb_delegate;
			}
		}

		static void OverrideJoin (GLib.GType gtype)
		{
			OverrideJoin (gtype, JoinVMCallback);
		}

		static void OverrideJoin (GLib.GType gtype, JoinNativeDelegate callback)
		{
			unsafe {
				IntPtr* raw_ptr = (IntPtr*)(((long) gtype.GetClassPtr()) + (long) class_abi.GetFieldOffset("join"));
				*raw_ptr = Marshal.GetFunctionPointerForDelegate((Delegate) callback);
			}
		}

		[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
		delegate void JoinNativeDelegate (IntPtr inst, IntPtr id);

		static void Join_cb (IntPtr inst, IntPtr id)
		{
			try {
				TaskPool __obj = GLib.Object.GetObject (inst, false) as TaskPool;
				__obj.OnJoin (id);
			} catch (Exception e) {
				GLib.ExceptionManager.RaiseUnhandledException (e, false);
			}
		}

		[GLib.DefaultSignalHandler(Type=typeof(Gst.TaskPool), ConnectionMethod="OverrideJoin")]
		protected virtual void OnJoin (IntPtr id)
		{
			InternalJoin (id);
		}

		private void InternalJoin (IntPtr id)
		{
			JoinNativeDelegate unmanaged = null;
			unsafe {
				IntPtr* raw_ptr = (IntPtr*)(((long) this.LookupGType().GetThresholdType().GetClassPtr()) + (long) class_abi.GetFieldOffset("join"));
				unmanaged = (JoinNativeDelegate) Marshal.GetDelegateForFunctionPointer(*raw_ptr, typeof(JoinNativeDelegate));
			}
			if (unmanaged == null) return;

			unmanaged (this.Handle, id);
		}

		static DisposeHandleNativeDelegate DisposeHandle_cb_delegate;
		static DisposeHandleNativeDelegate DisposeHandleVMCallback {
			get {
				if (DisposeHandle_cb_delegate == null)
					DisposeHandle_cb_delegate = new DisposeHandleNativeDelegate (DisposeHandle_cb);
				return DisposeHandle_cb_delegate;
			}
		}

		static void OverrideDisposeHandle (GLib.GType gtype)
		{
			OverrideDisposeHandle (gtype, DisposeHandleVMCallback);
		}

		static void OverrideDisposeHandle (GLib.GType gtype, DisposeHandleNativeDelegate callback)
		{
			unsafe {
				IntPtr* raw_ptr = (IntPtr*)(((long) gtype.GetClassPtr()) + (long) class_abi.GetFieldOffset("dispose_handle"));
				*raw_ptr = Marshal.GetFunctionPointerForDelegate((Delegate) callback);
			}
		}

		[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
		delegate void DisposeHandleNativeDelegate (IntPtr inst, IntPtr id);

		static void DisposeHandle_cb (IntPtr inst, IntPtr id)
		{
			try {
				TaskPool __obj = GLib.Object.GetObject (inst, false) as TaskPool;
				__obj.OnDisposeHandle (id);
			} catch (Exception e) {
				GLib.ExceptionManager.RaiseUnhandledException (e, false);
			}
		}

		[GLib.DefaultSignalHandler(Type=typeof(Gst.TaskPool), ConnectionMethod="OverrideDisposeHandle")]
		protected virtual void OnDisposeHandle (IntPtr id)
		{
			InternalDisposeHandle (id);
		}

		private void InternalDisposeHandle (IntPtr id)
		{
			DisposeHandleNativeDelegate unmanaged = null;
			unsafe {
				IntPtr* raw_ptr = (IntPtr*)(((long) this.LookupGType().GetThresholdType().GetClassPtr()) + (long) class_abi.GetFieldOffset("dispose_handle"));
				unmanaged = (DisposeHandleNativeDelegate) Marshal.GetDelegateForFunctionPointer(*raw_ptr, typeof(DisposeHandleNativeDelegate));
			}
			if (unmanaged == null) return;

			unmanaged (this.Handle, id);
		}


		// Internal representation of the wrapped structure ABI.
		static GLib.AbiStruct _class_abi = null;
		static public new GLib.AbiStruct class_abi {
			get {
				if (_class_abi == null)
					_class_abi = new GLib.AbiStruct (new List<GLib.AbiField>{ 
						new GLib.AbiField("prepare"
							, Gst.Object.class_abi.Fields
							, (uint) Marshal.SizeOf(typeof(IntPtr)) // prepare
							, null
							, "cleanup"
							, (uint) Marshal.SizeOf(typeof(IntPtr))
							, 0
							),
						new GLib.AbiField("cleanup"
							, -1
							, (uint) Marshal.SizeOf(typeof(IntPtr)) // cleanup
							, "prepare"
							, "push"
							, (uint) Marshal.SizeOf(typeof(IntPtr))
							, 0
							),
						new GLib.AbiField("push"
							, -1
							, (uint) Marshal.SizeOf(typeof(IntPtr)) // push
							, "cleanup"
							, "join"
							, (uint) Marshal.SizeOf(typeof(IntPtr))
							, 0
							),
						new GLib.AbiField("join"
							, -1
							, (uint) Marshal.SizeOf(typeof(IntPtr)) // join
							, "push"
							, "dispose_handle"
							, (uint) Marshal.SizeOf(typeof(IntPtr))
							, 0
							),
						new GLib.AbiField("dispose_handle"
							, -1
							, (uint) Marshal.SizeOf(typeof(IntPtr)) // dispose_handle
							, "join"
							, "_gst_reserved"
							, (uint) Marshal.SizeOf(typeof(IntPtr))
							, 0
							),
						new GLib.AbiField("_gst_reserved"
							, -1
							, (uint) Marshal.SizeOf(typeof(IntPtr)) * 3 // _gst_reserved
							, "dispose_handle"
							, null
							, (uint) Marshal.SizeOf(typeof(IntPtr))
							, 0
							),
					});

				return _class_abi;
			}
		}


		// End of the ABI representation.

		[DllImport("gstreamer-1.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
		static extern IntPtr gst_task_pool_get_type();

		public static new GLib.GType GType { 
			get {
				IntPtr raw_ret = gst_task_pool_get_type();
				GLib.GType ret = new GLib.GType(raw_ret);
				return ret;
			}
		}

		[DllImport("gstreamer-1.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
		static extern void gst_task_pool_cleanup(IntPtr raw);

		public void Cleanup() {
			gst_task_pool_cleanup(Handle);
		}

		[DllImport("gstreamer-1.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
		static extern void gst_task_pool_dispose_handle(IntPtr raw, IntPtr id);

		public void DisposeHandle(IntPtr id) {
			gst_task_pool_dispose_handle(Handle, id);
		}

		public void DisposeHandle() {
			DisposeHandle (IntPtr.Zero);
		}

		[DllImport("gstreamer-1.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
		static extern void gst_task_pool_join(IntPtr raw, IntPtr id);

		public void Join(IntPtr id) {
			gst_task_pool_join(Handle, id);
		}

		public void Join() {
			Join (IntPtr.Zero);
		}

		[DllImport("gstreamer-1.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
		static extern unsafe void gst_task_pool_prepare(IntPtr raw, out IntPtr error);

		public unsafe void Prepare() {
			IntPtr error = IntPtr.Zero;
			gst_task_pool_prepare(Handle, out error);
			if (error != IntPtr.Zero) throw new GLib.GException (error);
		}

		[DllImport("gstreamer-1.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
		static extern unsafe IntPtr gst_task_pool_push(IntPtr raw, GstSharp.TaskPoolFunctionNative func, IntPtr user_data, out IntPtr error);

		public unsafe IntPtr Push(Gst.TaskPoolFunction func) {
			GstSharp.TaskPoolFunctionWrapper func_wrapper = new GstSharp.TaskPoolFunctionWrapper (func);
			func_wrapper.PersistUntilCalled ();
			IntPtr error = IntPtr.Zero;
			IntPtr raw_ret = gst_task_pool_push(Handle, func_wrapper.NativeDelegate, IntPtr.Zero, out error);
			IntPtr ret = raw_ret;
			if (error != IntPtr.Zero) throw new GLib.GException (error);
			return ret;
		}


		// Internal representation of the wrapped structure ABI.
		static GLib.AbiStruct _abi_info = null;
		static public new GLib.AbiStruct abi_info {
			get {
				if (_abi_info == null)
					_abi_info = new GLib.AbiStruct (new List<GLib.AbiField>{ 
						new GLib.AbiField("pool"
							, Gst.Object.abi_info.Fields
							, (uint) Marshal.SizeOf(typeof(IntPtr)) // pool
							, null
							, "_gst_reserved"
							, (uint) Marshal.SizeOf(typeof(IntPtr))
							, 0
							),
						new GLib.AbiField("_gst_reserved"
							, -1
							, (uint) Marshal.SizeOf(typeof(IntPtr)) * 4 // _gst_reserved
							, "pool"
							, null
							, (uint) Marshal.SizeOf(typeof(IntPtr))
							, 0
							),
					});

				return _abi_info;
			}
		}


		// End of the ABI representation.

#endregion
	}
}
