diff options
Diffstat (limited to 'gstreamer-sharp/glib-sharp/Object.cs')
-rw-r--r-- | gstreamer-sharp/glib-sharp/Object.cs | 738 |
1 files changed, 738 insertions, 0 deletions
diff --git a/gstreamer-sharp/glib-sharp/Object.cs b/gstreamer-sharp/glib-sharp/Object.cs new file mode 100644 index 0000000..d210488 --- /dev/null +++ b/gstreamer-sharp/glib-sharp/Object.cs @@ -0,0 +1,738 @@ +// Object.cs - GObject class wrapper implementation +// +// Authors: Mike Kestner <mkestner@speakeasy.net> +// +// Copyright (c) 2001-2003 Mike Kestner +// Copyright (c) 2004-2005 Novell, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the Lesser GNU General +// Public License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + + +namespace GLib { + + using System; + using System.Collections; + using System.ComponentModel; + using System.Reflection; + using System.Runtime.InteropServices; + using System.Text; + + public class Object : IWrapper, IDisposable { + + IntPtr handle; + ToggleRef tref; + bool disposed = false; + Hashtable data; + static Hashtable Objects = new Hashtable(); + static ArrayList PendingDestroys = new ArrayList (); + static bool idle_queued; + + ~Object () + { + lock (PendingDestroys) { + lock (Objects) { + if (Objects[Handle] is ToggleRef) + PendingDestroys.Add (Objects [Handle]); + Objects.Remove (Handle); + } + if (!idle_queued){ + Timeout.Add (50, new TimeoutHandler (PerformQueuedUnrefs)); + idle_queued = true; + } + } + } + + [DllImport("libgobject-2.0-0.dll")] + static extern void g_object_unref (IntPtr raw); + + static bool PerformQueuedUnrefs () + { + object [] references; + + lock (PendingDestroys){ + references = new object [PendingDestroys.Count]; + PendingDestroys.CopyTo (references, 0); + PendingDestroys.Clear (); + idle_queued = false; + } + + foreach (ToggleRef r in references) + r.Free (); + + return false; + } + + public virtual void Dispose () + { + if (disposed) + return; + + disposed = true; + ToggleRef toggle_ref = Objects [Handle] as ToggleRef; + Objects.Remove (Handle); + try { + if (toggle_ref != null) + toggle_ref.Free (); + } catch (Exception e) { + Console.WriteLine ("Exception while disposing a " + this + " in Gtk#"); + throw e; + } + handle = IntPtr.Zero; + GC.SuppressFinalize (this); + } + + [DllImport("libgobject-2.0-0.dll")] + static extern IntPtr g_object_ref (IntPtr raw); + + public static Object GetObject(IntPtr o, bool owned_ref) + { + if (o == IntPtr.Zero) + return null; + + Object obj = null; + + if (Objects.Contains (o)) { + ToggleRef toggle_ref = Objects [o] as ToggleRef; + if (toggle_ref != null && toggle_ref.IsAlive) + obj = toggle_ref.Target; + } + + if (obj != null && obj.Handle == o) { + if (owned_ref) + g_object_unref (obj.Handle); + return obj; + } + + if (!owned_ref) + g_object_ref (o); + + obj = GLib.ObjectManager.CreateObject(o); + if (obj == null) { + g_object_unref (o); + return null; + } + + return obj; + } + + public static Object GetObject(IntPtr o) + { + return GetObject (o, false); + } + + private static void ConnectDefaultHandlers (GType gtype, System.Type t) + { + foreach (MethodInfo minfo in t.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly)) { + MethodInfo baseinfo = minfo.GetBaseDefinition (); + if (baseinfo == minfo) + continue; + + foreach (object attr in baseinfo.GetCustomAttributes (typeof (DefaultSignalHandlerAttribute), false)) { + DefaultSignalHandlerAttribute sigattr = attr as DefaultSignalHandlerAttribute; + MethodInfo connector = sigattr.Type.GetMethod (sigattr.ConnectionMethod, BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof (GType) }, new ParameterModifier [0]); + object[] parms = new object [1]; + parms [0] = gtype; + connector.Invoke (null, parms); + break; + } + } + + } + + private static void InvokeClassInitializers (GType gtype, System.Type t) + { + object[] parms = {gtype, t}; + + BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic; + + foreach (TypeInitializerAttribute tia in t.GetCustomAttributes (typeof (TypeInitializerAttribute), true)) { + MethodInfo m = tia.Type.GetMethod (tia.MethodName, flags); + if (m != null) + m.Invoke (null, parms); + } + + for (Type curr = t; curr != typeof(GLib.Object); curr = curr.BaseType) { + + if (curr.Assembly.IsDefined (typeof (IgnoreClassInitializersAttribute), false)) + continue; + + foreach (MethodInfo minfo in curr.GetMethods(flags)) + if (minfo.IsDefined (typeof (ClassInitializerAttribute), true)) + minfo.Invoke (null, parms); + } + } + + // Key: The pointer to the ParamSpec of the property + // Value: The corresponding PropertyInfo object + static Hashtable properties; + static Hashtable Properties { + get { + if (properties == null) + properties = new Hashtable (); + return properties; + } + } + + [StructLayout(LayoutKind.Sequential)] + struct GTypeClass { + public IntPtr gtype; + } + + [StructLayout(LayoutKind.Sequential)] + struct GObjectClass { + GTypeClass type_class; + IntPtr construct_props; + public ConstructorDelegate constructor_cb; + public SetPropertyDelegate set_prop_cb; + public GetPropertyDelegate get_prop_cb; + IntPtr dispose; + IntPtr finalize; + IntPtr dispatch_properties_changed; + IntPtr notify; + public ConstructedDelegate constructed_cb; + IntPtr dummy1; + IntPtr dummy2; + IntPtr dummy3; + IntPtr dummy4; + IntPtr dummy5; + IntPtr dummy6; + IntPtr dummy7; + } + + static Hashtable class_structs; + + static GObjectClass GetClassStruct (GLib.GType gtype, bool use_cache) + { + if (class_structs == null) + class_structs = new Hashtable (); + + if (use_cache && class_structs.Contains (gtype)) + return (GObjectClass) class_structs [gtype]; + else { + IntPtr class_ptr = gtype.ClassPtr; + GObjectClass class_struct = (GObjectClass) Marshal.PtrToStructure (class_ptr, typeof (GObjectClass)); + if (use_cache) + class_structs.Add (gtype, class_struct); + return class_struct; + } + } + + static void OverrideClassStruct (GLib.GType gtype, GObjectClass class_struct) + { + IntPtr class_ptr = gtype.ClassPtr; + Marshal.StructureToPtr (class_struct, class_ptr, false); + } + + static void OverridePropertyHandlers (GType gtype, GetPropertyDelegate get_cb, SetPropertyDelegate set_cb) + { + GObjectClass klass = GetClassStruct (gtype, false); + klass.get_prop_cb = get_cb; + klass.set_prop_cb = set_cb; + OverrideClassStruct (gtype, klass); + } + + [DllImport("libgobject-2.0-0.dll")] + static extern void g_object_class_install_property (IntPtr klass, uint prop_id, IntPtr param_spec); + + static IntPtr RegisterProperty (GType type, string name, string nick, string blurb, uint property_id, GType property_type, bool can_read, bool can_write) + { + IntPtr declaring_class = type.ClassPtr; + ParamSpec pspec = new ParamSpec (name, nick, blurb, property_type, can_read, can_write); + + g_object_class_install_property (declaring_class, property_id, pspec.Handle); + return pspec.Handle; + } + + static ConstructorDelegate Constructor_cb = new ConstructorDelegate (constructor_cb); + delegate IntPtr ConstructorDelegate (IntPtr gtype, uint n_construct_properties, IntPtr construct_properties); + + [StructLayout(LayoutKind.Sequential)] + struct GObjectConstructParam { + public IntPtr pspec; + public IntPtr value; + } + + static IntPtr constructor_cb (IntPtr gtype, uint n_construct_properties, IntPtr construct_properties) + { + GType type = new GLib.GType (gtype); + IntPtr instance = GetClassStruct (type.ThresholdType, false).constructor_cb (gtype, n_construct_properties, construct_properties); + for (int i = 0; i < n_construct_properties; i++) { + IntPtr p = new IntPtr ((long) construct_properties + i * Marshal.SizeOf (typeof (GObjectConstructParam))); + + GObjectConstructParam cparam = (GObjectConstructParam) Marshal.PtrToStructure (p, typeof (GObjectConstructParam)); + + ParamSpec pspec = new ParamSpec (cparam.pspec); + GLib.Value val = (Value) Marshal.PtrToStructure (cparam.value, typeof (Value)); + + if (pspec.Name == "gtk-sharp-managed-instance" && (IntPtr) val.Val != IntPtr.Zero) { + GCHandle gch = (GCHandle) (IntPtr) val.Val; + Object o = (GLib.Object) gch.Target; + o.Raw = instance; + } + } + + return instance; + } + + static ConstructedDelegate Constructed_cb = new ConstructedDelegate (constructed_cb); + [GLib.CDeclCallback] + delegate void ConstructedDelegate (IntPtr o); + + static void constructed_cb (IntPtr o) + { + GLib.Object __obj = GLib.Object.GetObject (o, false) as GLib.Object; + ConstructedDelegate unmanaged = GetClassStruct (__obj.LookupGType ().ThresholdType, true).constructed_cb; + if (unmanaged != null) + unmanaged (__obj.Handle); + } + + static SetPropertyDelegate Set_prop_dummy_cb = new SetPropertyDelegate (set_prop_dummy_cb); + static void set_prop_dummy_cb (IntPtr GObject, uint property_id, ref GLib.Value value, IntPtr pspec) {} + + static void AddProperties (GType gtype, System.Type t) + { + uint idx = 1; + + if (gtype.BaseType == gtype.ThresholdType) { + GObjectClass gobject_class = GetClassStruct (gtype, false); + gobject_class.constructor_cb = Constructor_cb; + gobject_class.constructed_cb = Constructed_cb; + gobject_class.set_prop_cb = Set_prop_dummy_cb; + OverrideClassStruct (gtype, gobject_class); + + IntPtr declaring_class = gtype.ClassPtr; + ParamSpec pspec = new ParamSpec ("gtk-sharp-managed-instance", "", "", GType.Pointer, ParamFlags.Writable | ParamFlags.ConstructOnly); + g_object_class_install_property (declaring_class, idx, pspec.Handle); + idx++; + } + + bool handlers_overridden = false; + foreach (PropertyInfo pinfo in t.GetProperties (BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)) { + foreach (object attr in pinfo.GetCustomAttributes (typeof (PropertyAttribute), false)) { + if(pinfo.GetIndexParameters().Length > 0) + throw(new InvalidOperationException(String.Format("GLib.RegisterPropertyAttribute cannot be applied to property {0} of type {1} because the property expects one or more indexed parameters", pinfo.Name, t.FullName))); + + PropertyAttribute property_attr = attr as PropertyAttribute; + if (!handlers_overridden) { + OverridePropertyHandlers (gtype, GetPropertyHandler, SetPropertyHandler); + handlers_overridden = true; + } + + try { + IntPtr param_spec = RegisterProperty (gtype, property_attr.Name, property_attr.Nickname, property_attr.Blurb, idx, (GType) pinfo.PropertyType, pinfo.CanRead, pinfo.CanWrite); + Properties.Add (param_spec, pinfo); + idx++; + } catch (ArgumentException) { + throw new InvalidOperationException (String.Format ("GLib.PropertyAttribute cannot be applied to property {0} of type {1} because the return type of the property is not supported", pinfo.Name, t.FullName)); + } + } + } + } + + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + delegate void GetPropertyDelegate (IntPtr GObject, uint property_id, ref GLib.Value value, IntPtr pspec); + + static void GetPropertyCallback (IntPtr handle, uint property_id, ref GLib.Value value, IntPtr param_spec) + { + if (!Properties.Contains (param_spec)) + return; + + GLib.Object obj = GLib.Object.GetObject (handle, false); + value.Val = (Properties [param_spec] as PropertyInfo).GetValue (obj, new object [0]); + } + + static GetPropertyDelegate get_property_handler; + static GetPropertyDelegate GetPropertyHandler { + get { + if (get_property_handler == null) + get_property_handler = new GetPropertyDelegate (GetPropertyCallback); + return get_property_handler; + } + } + + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + delegate void SetPropertyDelegate (IntPtr GObject, uint property_id, ref GLib.Value value, IntPtr pspec); + + static void SetPropertyCallback(IntPtr handle, uint property_id, ref GLib.Value value, IntPtr param_spec) + { + if (!Properties.Contains (param_spec)) + return; + + GLib.Object obj = GLib.Object.GetObject (handle, false); + (Properties [param_spec] as PropertyInfo).SetValue (obj, value.Val, new object [0]); + } + + static SetPropertyDelegate set_property_handler; + static SetPropertyDelegate SetPropertyHandler { + get { + if (set_property_handler == null) + set_property_handler = new SetPropertyDelegate (SetPropertyCallback); + return set_property_handler; + } + } + + [DllImport("libgobject-2.0-0.dll")] + static extern void g_type_add_interface_static (IntPtr gtype, IntPtr iface_type, ref GInterfaceInfo info); + + static void AddInterfaces (GType gtype, Type t) + { + foreach (Type iface in t.GetInterfaces ()) { + if (!iface.IsDefined (typeof (GInterfaceAttribute), true) || iface.IsAssignableFrom (t.BaseType)) + continue; + + GInterfaceAttribute attr = iface.GetCustomAttributes (typeof (GInterfaceAttribute), false) [0] as GInterfaceAttribute; + GInterfaceAdapter adapter = Activator.CreateInstance (attr.AdapterType, null) as GInterfaceAdapter; + + GInterfaceInfo info = adapter.Info; + g_type_add_interface_static (gtype.Val, adapter.GType.Val, ref info); + } + } + + protected internal static GType RegisterGType (System.Type t) + { + GType gtype = GType.RegisterGObjectType (t); + AddProperties (gtype, t); + ConnectDefaultHandlers (gtype, t); + InvokeClassInitializers (gtype, t); + AddInterfaces (gtype, t); + return gtype; + } + + + protected GType LookupGType () + { + if (Handle != IntPtr.Zero) { + GTypeInstance obj = (GTypeInstance) Marshal.PtrToStructure (Handle, typeof (GTypeInstance)); + GTypeClass klass = (GTypeClass) Marshal.PtrToStructure (obj.g_class, typeof (GTypeClass)); + return new GLib.GType (klass.gtype); + } else { + return LookupGType (GetType ()); + } + } + + protected internal static GType LookupGType (System.Type t) + { + return GType.LookupGObjectType (t); + } + + protected Object (IntPtr raw) + { + Raw = raw; + } + + protected Object () + { + CreateNativeObject (new string [0], new GLib.Value [0]); + } + + [DllImport("libgobject-2.0-0.dll")] + static extern IntPtr g_object_new (IntPtr gtype, IntPtr dummy); + + [Obsolete] + protected Object (GType gtype) + { + Raw = g_object_new (gtype.Val, IntPtr.Zero); + } + + struct GParameter { + public IntPtr name; + public GLib.Value val; + } + + [DllImport("libgobject-2.0-0.dll")] + static extern IntPtr g_object_newv (IntPtr gtype, int n_params, GParameter[] parms); + + protected virtual void CreateNativeObject (string[] names, GLib.Value[] vals) + { + GLib.GType gtype = LookupGType (); + bool managed_type = gtype.ToString().StartsWith ("__gtksharp_"); + + GParameter[] parms = new GParameter [names.Length + ((managed_type) ? 1 : 0)]; + + for (int i = 0; i < names.Length; i++) { + parms [i].name = GLib.Marshaller.StringToPtrGStrdup (names [i]); + parms [i].val = vals [i]; + } + + if (managed_type) { + GCHandle gch = GCHandle.Alloc (this); + parms[names.Length].name = GLib.Marshaller.StringToPtrGStrdup ("gtk-sharp-managed-instance"); + parms[names.Length].val = new GLib.Value ((IntPtr) gch); + + Raw = g_object_newv (gtype.Val, parms.Length, parms); + + gch.Free (); + } else { + Raw = g_object_newv (gtype.Val, parms.Length, parms); + } + + foreach (GParameter p in parms) + GLib.Marshaller.Free (p.name); + } + + protected virtual IntPtr Raw { + get { + return handle; + } + set { + if (handle == value) + return; + + if (handle != IntPtr.Zero) { + Objects.Remove (handle); + if (tref != null) { + tref.Free (); + tref = null; + } + } + handle = value; + if (value != IntPtr.Zero) { + tref = new ToggleRef (this); + Objects [value] = tref; + } + } + } + + public static GLib.GType GType { + get { + return GType.Object; + } + } + + protected string TypeName { + get { + return NativeType.ToString (); + } + } + + internal GLib.GType NativeType { + get { + return LookupGType (); + } + } + + internal ToggleRef ToggleRef { + get { + return tref; + } + } + + public IntPtr Handle { + get { + return handle; + } + } + + public IntPtr OwnedHandle { + get { + return g_object_ref (handle); + } + } + + Hashtable before_signals; + [Obsolete ("Replaced by GLib.Signal marshaling mechanism.")] + protected internal Hashtable BeforeSignals { + get { + if (before_signals == null) + before_signals = new Hashtable (); + return before_signals; + } + } + + Hashtable after_signals; + [Obsolete ("Replaced by GLib.Signal marshaling mechanism.")] + protected internal Hashtable AfterSignals { + get { + if (after_signals == null) + after_signals = new Hashtable (); + return after_signals; + } + } + + EventHandlerList before_handlers; + [Obsolete ("Replaced by GLib.Signal marshaling mechanism.")] + protected EventHandlerList BeforeHandlers { + get { + if (before_handlers == null) + before_handlers = new EventHandlerList (); + return before_handlers; + } + } + + EventHandlerList after_handlers; + [Obsolete ("Replaced by GLib.Signal marshaling mechanism.")] + protected EventHandlerList AfterHandlers { + get { + if (after_handlers == null) + after_handlers = new EventHandlerList (); + return after_handlers; + } + } + + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] + delegate void NotifyDelegate (IntPtr handle, IntPtr pspec, IntPtr gch); + + void NotifyCallback (IntPtr handle, IntPtr pspec, IntPtr gch) + { + try { + GLib.Signal sig = ((GCHandle) gch).Target as GLib.Signal; + if (sig == null) + throw new Exception("Unknown signal GC handle received " + gch); + + NotifyArgs args = new NotifyArgs (); + args.Args = new object[1]; + args.Args[0] = pspec; + NotifyHandler handler = (NotifyHandler) sig.Handler; + handler (GLib.Object.GetObject (handle), args); + } catch (Exception e) { + ExceptionManager.RaiseUnhandledException (e, false); + } + } + + void ConnectNotification (string signal, NotifyHandler handler) + { + Signal sig = Signal.Lookup (this, signal, new NotifyDelegate (NotifyCallback)); + sig.AddDelegate (handler); + } + + public void AddNotification (string property, NotifyHandler handler) + { + ConnectNotification ("notify::" + property, handler); + } + + public void AddNotification (NotifyHandler handler) + { + ConnectNotification ("notify", handler); + } + + void DisconnectNotification (string signal, NotifyHandler handler) + { + Signal sig = Signal.Lookup (this, signal, new NotifyDelegate (NotifyCallback)); + sig.RemoveDelegate (handler); + } + + public void RemoveNotification (string property, NotifyHandler handler) + { + DisconnectNotification ("notify::" + property, handler); + } + + public void RemoveNotification (NotifyHandler handler) + { + DisconnectNotification ("notify", handler); + } + + public override int GetHashCode () + { + return Handle.GetHashCode (); + } + + public Hashtable Data { + get { + if (data == null) + data = new Hashtable (); + + return data; + } + } + + Hashtable persistent_data; + protected Hashtable PersistentData { + get { + if (persistent_data == null) + persistent_data = new Hashtable (); + + return persistent_data; + } + } + + [DllImport("libgobject-2.0-0.dll")] + static extern void g_object_get_property (IntPtr obj, IntPtr name, ref GLib.Value val); + + protected GLib.Value GetProperty (string name) + { + Value val = new Value (this, name); + IntPtr native_name = GLib.Marshaller.StringToPtrGStrdup (name); + g_object_get_property (Raw, native_name, ref val); + GLib.Marshaller.Free (native_name); + return val; + } + + [DllImport("libgobject-2.0-0.dll")] + static extern void g_object_set_property (IntPtr obj, IntPtr name, ref GLib.Value val); + + protected void SetProperty (string name, GLib.Value val) + { + IntPtr native_name = GLib.Marshaller.StringToPtrGStrdup (name); + g_object_set_property (Raw, native_name, ref val); + GLib.Marshaller.Free (native_name); + } + + [DllImport("libgobject-2.0-0.dll")] + static extern void g_object_notify (IntPtr obj, IntPtr property_name); + + protected void Notify (string property_name) + { + IntPtr native_name = GLib.Marshaller.StringToPtrGStrdup (property_name); + g_object_notify (Handle, native_name); + GLib.Marshaller.Free (native_name); + } + + protected static void OverrideVirtualMethod (GType gtype, string name, Delegate cb) + { + Signal.OverrideDefaultHandler (gtype, name, cb); + } + + [DllImport("libgobject-2.0-0.dll")] + protected static extern void g_signal_chain_from_overridden (IntPtr args, ref GLib.Value retval); + + [DllImport("libgobject-2.0-0.dll")] + static extern bool g_type_check_instance_is_a (IntPtr obj, IntPtr gtype); + + internal static bool IsObject (IntPtr obj) + { + return g_type_check_instance_is_a (obj, GType.Object.Val); + } + + [StructLayout(LayoutKind.Sequential)] + struct GTypeInstance { + public IntPtr g_class; + } + + [StructLayout(LayoutKind.Sequential)] + struct GObject { + public GTypeInstance type_instance; + public uint ref_count; + public IntPtr qdata; + } + + protected int RefCount { + get { + GObject native = (GObject) Marshal.PtrToStructure (Handle, typeof (GObject)); + return (int) native.ref_count; + } + } + + internal void Harden () + { + tref.Harden (); + } + + static Object () + { + if (Environment.GetEnvironmentVariable ("GTK_SHARP_DEBUG") != null) + GLib.Log.SetLogHandler ("GLib-GObject", GLib.LogLevelFlags.All, new GLib.LogFunc (GLib.Log.PrintTraceLogFunction)); + } + } +} |