// MiniObject.cs - GstMiniObject class wrapper implementation // // Authors: Mike Kestner // Sebastian Dröge // // Copyright (c) 2001-2003 Mike Kestner // Copyright (c) 2004-2005 Novell, Inc. // Copyright (c) 2009 Sebastian Dröge . // // 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. // Based on Object.cs from Gtk# 2.8.3 // TODO: For managed types, install finalizer in ThresholdType // and only destroy the managed instance if the native instance // gets finalized => move managed instance to managed_tb_destroyed // and unref, if finalizer is called remove it completely. // For non-managed types handle as is. namespace Gst { using System; using System.Collections; using System.ComponentModel; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using GLib; public class MiniObject : IWrapper, IDisposable { [StructLayout (LayoutKind.Sequential) ] struct GTypeClass { public IntPtr gtype; } [StructLayout (LayoutKind.Sequential) ] struct GstMiniObjectClass { GTypeClass parent; IntPtr copy; IntPtr finalize; IntPtr reserved; } [StructLayout (LayoutKind.Sequential) ] struct GTypeInstance { public IntPtr g_class; } [StructLayout (LayoutKind.Sequential) ] struct GstMiniObject { GTypeInstance parent; public int refcount; public Gst.MiniObjectFlags flags; IntPtr reserved; } IntPtr handle; bool disposed = false; static Hashtable Objects = new Hashtable(); ~MiniObject () { Dispose (); } [DllImport ("gstreamer-0.10.dll") ] static extern void gst_mini_object_unref (IntPtr raw); public virtual void Dispose () { if (disposed) return; disposed = true; lock (typeof (MiniObject)) { if (handle != IntPtr.Zero) { Objects.Remove (handle); try { gst_mini_object_unref (handle); } catch (Exception e) { Console.WriteLine ("Exception while disposing a " + this + " in Gtk#"); throw e; } handle = IntPtr.Zero; } } GC.SuppressFinalize (this); } [DllImport ("gstreamer-0.10.dll") ] static extern IntPtr gst_mini_object_ref (IntPtr raw); public static MiniObject GetObject (IntPtr o, bool owned_ref) { if (o == IntPtr.Zero) return null; MiniObject obj = null; lock (typeof (MiniObject)) { WeakReference weak_ref = Objects[o] as WeakReference; if (weak_ref != null && weak_ref.IsAlive) obj = weak_ref.Target as MiniObject; if (obj == null) obj = Objects[o] as MiniObject; } if (obj != null && obj.handle == o) { if (owned_ref) gst_mini_object_unref (obj.handle); obj.disposed = false; return obj; } obj = CreateObject (o); if (obj == null) return null; if (!owned_ref) gst_mini_object_ref (obj.Handle); Objects [o] = new WeakReference (obj); return obj; } static BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance; private static MiniObject CreateObject (IntPtr raw) { if (raw == IntPtr.Zero) return null; Type type = GetTypeOrParent (raw); if (type == null) return null; MiniObject obj; try { obj = Activator.CreateInstance (type, flags, null, new object[] {raw}, null) as Gst.MiniObject; } catch (MissingMethodException) { throw new GLib.MissingIntPtrCtorException ("Gst.MiniObject subclass " + type + " must provide a protected or public IntPtr ctor to support wrapping of native object handles."); } return obj; } [DllImport ("gstreamersharpglue-0.10.dll") ] static extern IntPtr gstsharp_g_type_from_instance (IntPtr inst); static Type GetTypeOrParent (IntPtr obj) { IntPtr typeid = gstsharp_g_type_from_instance (obj); if (typeid == GType.Invalid.Val) return null; Type result = GType.LookupType (typeid); while (result == null) { typeid = g_type_parent (typeid); if (typeid == IntPtr.Zero) return null; result = GType.LookupType (typeid); } return result; } [DllImport ("libgobject-2.0-0.dll") ] static extern IntPtr g_type_parent (IntPtr typ); public static MiniObject 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); 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); } } static Hashtable class_structs; static GstMiniObjectClass GetClassStruct (GLib.GType gtype, bool use_cache) { if (class_structs == null) class_structs = new Hashtable (); if (use_cache && class_structs.Contains (gtype)) return (GstMiniObjectClass) class_structs [gtype]; else { IntPtr class_ptr = gtype.ClassPtr; GstMiniObjectClass class_struct = (GstMiniObjectClass) Marshal.PtrToStructure (class_ptr, typeof (GstMiniObjectClass)); if (use_cache) class_structs.Add (gtype, class_struct); return class_struct; } } static void OverrideClassStruct (GLib.GType gtype, GstMiniObjectClass class_struct) { IntPtr class_ptr = gtype.ClassPtr; Marshal.StructureToPtr (class_struct, class_ptr, false); } static int type_uid; static string BuildEscapedName (System.Type t) { string qn = t.FullName; // Just a random guess StringBuilder sb = new StringBuilder (20 + qn.Length); sb.Append ("__gtksharp_"); sb.Append (type_uid++); sb.Append ("_"); foreach (char c in qn) { if ( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) sb.Append (c); else if (c == '.') sb.Append ('_'); else if ( (uint) c <= byte.MaxValue) { sb.Append ('+'); sb.Append ( ( (byte) c).ToString ("x2")); } else { sb.Append ('-'); sb.Append ( ( (uint) c).ToString ("x4")); } } return sb.ToString (); } [StructLayout (LayoutKind.Sequential) ] struct GTypeInfo { public ushort class_size; IntPtr base_init; IntPtr base_finalize; IntPtr class_init; IntPtr class_finalize; IntPtr class_data; public ushort instance_size; ushort n_preallocs; IntPtr instance_init; IntPtr value_table; } [StructLayout (LayoutKind.Sequential) ] struct GTypeQuery { public IntPtr type; public IntPtr type_name; public uint class_size; public uint instance_size; } [DllImport ("libgobject-2.0-0.dll") ] static extern void g_type_query (IntPtr type, out GTypeQuery query); [DllImport ("libgobject-2.0-0.dll") ] static extern IntPtr g_type_register_static (IntPtr parent, IntPtr name, ref GTypeInfo info, int flags); private static GType RegisterGType (System.Type t) { GType parent_gtype = LookupGType (t.BaseType); string name = BuildEscapedName (t); IntPtr native_name = GLib.Marshaller.StringToPtrGStrdup (name); GTypeQuery query; g_type_query (parent_gtype.Val, out query); GTypeInfo info = new GTypeInfo (); info.class_size = (ushort) query.class_size; info.instance_size = (ushort) query.instance_size; GType gtype = new GType (g_type_register_static (parent_gtype.Val, native_name, ref info, 0)); GLib.Marshaller.Free (native_name); GLib.GType.Register (gtype, t); ConnectDefaultHandlers (gtype, t); InvokeClassInitializers (gtype, t); return gtype; } [DllImport ("glibsharpglue-2") ] static extern IntPtr gtksharp_register_type (IntPtr name, IntPtr parent_type); 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) { GType gtype = (GType) t; if (gtype.ToString () != "GtkSharpValue") return gtype; return RegisterGType (t); } protected MiniObject (IntPtr raw) { Raw = raw; } protected MiniObject () { CreateNativeObject (); } [DllImport ("gstreamer-0.10.dll") ] static extern IntPtr gst_mini_object_new (IntPtr gtype); protected virtual void CreateNativeObject () { Raw = gst_mini_object_new (LookupGType ().Val); Objects [handle] = this; } protected virtual IntPtr Raw { get { return handle; } set { if (handle != IntPtr.Zero) Objects.Remove (handle); handle = value; if (value == IntPtr.Zero) return; Objects [value] = new WeakReference (this); } } [DllImport ("gstreamer-0.10.dll") ] static extern IntPtr gst_mini_object_get_type(); public static GLib.GType GType { get { IntPtr raw_ret = gst_mini_object_get_type(); GLib.GType ret = new GLib.GType (raw_ret); return ret; } } protected string TypeName { get { return NativeType.ToString(); } } internal GLib.GType NativeType { get { return LookupGType (); } } public IntPtr Handle { get { return handle; } } public IntPtr OwnedHandle { get { return gst_mini_object_ref (handle); } } public override int GetHashCode () { return Handle.GetHashCode (); } Hashtable data; 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 bool g_type_check_instance_is_a (IntPtr obj, IntPtr gtype); internal static bool IsMiniObject (IntPtr obj) { return g_type_check_instance_is_a (obj, MiniObject.GType.Val); } internal int Refcount { get { GstMiniObject inst_struct = (GstMiniObject) Marshal.PtrToStructure (Handle, typeof (GstMiniObject)); return inst_struct.refcount; } } public Gst.MiniObjectFlags Flags { get { GstMiniObject inst_struct = (GstMiniObject) Marshal.PtrToStructure (Handle, typeof (GstMiniObject)); return inst_struct.flags; } set { GstMiniObject inst_struct = (GstMiniObject) Marshal.PtrToStructure (Handle, typeof (GstMiniObject)); inst_struct.flags = value; } } [DllImport ("gstreamer-0.10.dll") ] static extern bool gst_mini_object_is_writable (IntPtr raw); public bool IsWritable { get { bool raw_ret = gst_mini_object_is_writable (Handle); bool ret = raw_ret; return ret; } } [DllImport ("gstreamer-0.10.dll") ] private static extern IntPtr gst_value_dup_mini_object (ref GLib.Value v); public MiniObject (GLib.Value val) : base () { Raw = gst_value_dup_mini_object (ref val); } [DllImport ("gstreamer-0.10.dll") ] private static extern void gst_value_set_mini_object (ref GLib.Value v, IntPtr o); public static explicit operator GLib.Value (MiniObject o) { GLib.Value val = new GLib.Value (o.LookupGType ()); gst_value_set_mini_object (ref val, o.Handle); return val; } public void SetGValue (ref GLib.Value val) { gst_value_set_mini_object (ref val, Handle); } /* FIXME: This is not optimal */ public void MakeWritable() { if (IsWritable) return; IntPtr old = Handle; IntPtr copy = gst_mini_object_copy (Handle); Raw = copy; gst_mini_object_unref (old); } [DllImport ("gstreamer-0.10.dll") ] static extern IntPtr gst_mini_object_copy (IntPtr raw); public Gst.MiniObject Copy() { IntPtr raw_ret = gst_mini_object_copy (Handle); return GetObject (raw_ret, true); } } }