1 // GLib.Type.cs - GLib GType class implementation 2 // 3 // Author: Mike Kestner <mkestner@speakeasy.net> 4 // 5 // Copyright (c) 2003 Mike Kestner 6 // Copyright (c) 2003 Novell, Inc. 7 // 8 // This program is free software; you can redistribute it and/or 9 // modify it under the terms of version 2 of the Lesser GNU General 10 // Public License as published by the Free Software Foundation. 11 // 12 // This program is distributed in the hope that it will be useful, 13 // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 // Lesser General Public License for more details. 16 // 17 // You should have received a copy of the GNU Lesser General Public 18 // License along with this program; if not, write to the 19 // Free Software Foundation, Inc., 59 Temple Place - Suite 330, 20 // Boston, MA 02111-1307, USA. 21 22 23 namespace GLib { 24 25 using System; 26 using System.Collections; 27 using System.Collections.Generic; 28 using System.IO; 29 using System.Reflection; 30 using System.Runtime.InteropServices; 31 32 [StructLayout(LayoutKind.Sequential)] 33 public struct GType : IEquatable<GType> { 34 35 IntPtr val; 36 GTypeGLib.GType37 public GType (IntPtr val) 38 { 39 this.val = val; 40 } 41 FromNameGLib.GType42 public static GType FromName (string native_name) 43 { 44 return new GType (g_type_from_name (native_name)); 45 } 46 47 public static readonly GType Invalid = new GType ((IntPtr) TypeFundamentals.TypeInvalid); 48 public static readonly GType None = new GType ((IntPtr) TypeFundamentals.TypeNone); 49 public static readonly GType Interface = new GType ((IntPtr) TypeFundamentals.TypeInterface); 50 public static readonly GType Char = new GType ((IntPtr) TypeFundamentals.TypeChar); 51 public static readonly GType UChar = new GType ((IntPtr) TypeFundamentals.TypeUChar); 52 public static readonly GType Boolean = new GType ((IntPtr) TypeFundamentals.TypeBoolean); 53 public static readonly GType Int = new GType ((IntPtr) TypeFundamentals.TypeInt); 54 public static readonly GType UInt = new GType ((IntPtr) TypeFundamentals.TypeUInt); 55 public static readonly GType Long = new GType ((IntPtr) TypeFundamentals.TypeLong); 56 public static readonly GType ULong = new GType ((IntPtr) TypeFundamentals.TypeULong); 57 public static readonly GType Int64 = new GType ((IntPtr) TypeFundamentals.TypeInt64); 58 public static readonly GType UInt64 = new GType ((IntPtr) TypeFundamentals.TypeUInt64); 59 public static readonly GType Enum = new GType ((IntPtr) TypeFundamentals.TypeEnum); 60 public static readonly GType Flags = new GType ((IntPtr) TypeFundamentals.TypeFlags); 61 public static readonly GType Float = new GType ((IntPtr) TypeFundamentals.TypeFloat); 62 public static readonly GType Double = new GType ((IntPtr) TypeFundamentals.TypeDouble); 63 public static readonly GType String = new GType ((IntPtr) TypeFundamentals.TypeString); 64 public static readonly GType Pointer = new GType ((IntPtr) TypeFundamentals.TypePointer); 65 public static readonly GType Boxed = new GType ((IntPtr) TypeFundamentals.TypeBoxed); 66 public static readonly GType Param = new GType ((IntPtr) TypeFundamentals.TypeParam); 67 public static readonly GType Object = new GType ((IntPtr) TypeFundamentals.TypeObject); 68 69 static Dictionary<IntPtr, Type> types = new Dictionary<IntPtr, Type> (IntPtrEqualityComparer.Instance); 70 static Dictionary<Type, GType> gtypes = new Dictionary<Type, GType> (); 71 RegisterGLib.GType72 public static void Register (GType native_type, System.Type type) 73 { 74 if (native_type != GType.Pointer && native_type != GType.Boxed && native_type != ManagedValue.GType) 75 types[native_type.Val] = type; 76 if (type != null) 77 gtypes[type] = native_type; 78 } 79 80 [DllImport("libgobject-2.0-0.dll", CallingConvention=CallingConvention.Cdecl)] g_type_initGLib.GType81 static extern void g_type_init (); 82 GTypeGLib.GType83 static GType () 84 { 85 if (!GLib.Thread.Supported) 86 GLib.Thread.Init (); 87 88 g_type_init (); 89 90 Register (GType.Char, typeof (sbyte)); 91 Register (GType.UChar, typeof (byte)); 92 Register (GType.Boolean, typeof (bool)); 93 Register (GType.Int, typeof (int)); 94 Register (GType.UInt, typeof (uint)); 95 Register (GType.Int64, typeof (long)); 96 Register (GType.UInt64, typeof (ulong)); 97 Register (GType.Float, typeof (float)); 98 Register (GType.Double, typeof (double)); 99 Register (GType.String, typeof (string)); 100 Register (GType.Pointer, typeof (IntPtr)); 101 Register (GType.Object, typeof (GLib.Object)); 102 103 // One-way mapping 104 gtypes[typeof (char)] = GType.UInt; 105 } 106 operator GTypeGLib.GType107 public static explicit operator GType (System.Type type) 108 { 109 GType gtype; 110 111 if (gtypes.TryGetValue (type, out gtype)) 112 return gtype; 113 114 if (type.IsSubclassOf (typeof (GLib.Object))) { 115 gtype = GLib.Object.LookupGType (type); 116 Register (gtype, type); 117 return gtype; 118 } 119 120 if (type.IsEnum) { 121 GTypeTypeAttribute geattr; 122 GTypeAttribute gattr; 123 if ((geattr = (GTypeTypeAttribute)Attribute.GetCustomAttribute (type, typeof (GTypeTypeAttribute), false)) != null) { 124 gtype = geattr.Type; 125 } else if ((gattr = (GTypeAttribute)Attribute.GetCustomAttribute (type, typeof (GTypeAttribute), false)) != null) { 126 // This should never happen for generated code, keep it in place for other users of the API. 127 var pi = gattr.WrapperType.GetProperty ("GType", BindingFlags.Public | BindingFlags.Static); 128 gtype = (GType)pi.GetValue (null, null); 129 } else 130 gtype = ManagedValue.GType; 131 } else { 132 GTypeTypeAttribute geattr; 133 PropertyInfo pi; 134 if ((geattr = (GTypeTypeAttribute)Attribute.GetCustomAttribute (type, typeof (GTypeTypeAttribute), false)) != null) { 135 gtype = geattr.Type; 136 } else if ((pi = type.GetProperty ("GType", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy)) != null) { 137 gtype = (GType)pi.GetValue (null, null); 138 } else if (type.IsSubclassOf (typeof (GLib.Opaque))) 139 gtype = GType.Pointer; 140 else 141 gtype = ManagedValue.GType; 142 } 143 144 145 Register (gtype, type); 146 return gtype; 147 } 148 GetQualifiedNameGLib.GType149 static string GetQualifiedName (string cname) 150 { 151 for (int i = 1; i < cname.Length; i++) { 152 if (System.Char.IsUpper (cname[i])) { 153 if (i == 1 && cname [0] == 'G') 154 return "GLib." + cname.Substring (1); 155 else 156 return cname.Substring (0, i) + "." + cname.Substring (i); 157 } 158 } 159 160 throw new ArgumentException ("cname is not in NamespaceType format. GType.Register should be called directly for " + cname); 161 } 162 operator TypeGLib.GType163 public static explicit operator Type (GType gtype) 164 { 165 return LookupType (gtype.Val); 166 } 167 InitGLib.GType168 public static void Init () 169 { 170 // cctor already calls g_type_init. 171 } 172 LookupTypeGLib.GType173 public static Type LookupType (IntPtr typeid) 174 { 175 Type result; 176 if (types.TryGetValue (typeid, out result)) 177 return result; 178 179 string native_name = Marshaller.Utf8PtrToString (g_type_name (typeid)); 180 string type_name = GetQualifiedName (native_name); 181 Assembly[] assemblies = (Assembly[]) AppDomain.CurrentDomain.GetAssemblies ().Clone (); 182 foreach (Assembly asm in assemblies) { 183 result = asm.GetType (type_name); 184 if (result != null) 185 break; 186 } 187 188 if (result == null) { 189 // Because of lazy loading of references, it's possible the type's assembly 190 // needs to be loaded. We will look for it by name in the references of 191 // the currently loaded assemblies. Hopefully a recursive traversal is 192 // not needed. We avoid one for now because of problems experienced 193 // in a patch from bug #400595, and a desire to keep memory usage low 194 // by avoiding a complete loading of all dependent assemblies. 195 string ns = type_name.Substring (0, type_name.LastIndexOf ('.')); 196 string asm_name = ns.ToLower ().Replace ('.', '-') + "-sharp"; 197 foreach (Assembly asm in assemblies) { 198 foreach (AssemblyName ref_name in asm.GetReferencedAssemblies ()) { 199 if (ref_name.Name != asm_name) 200 continue; 201 try { 202 string asm_dir = Path.GetDirectoryName (asm.Location); 203 Assembly ref_asm; 204 if (File.Exists (Path.Combine (asm_dir, ref_name.Name + ".dll"))) 205 ref_asm = Assembly.LoadFrom (Path.Combine (asm_dir, ref_name.Name + ".dll")); 206 else 207 ref_asm = Assembly.Load (ref_name); 208 result = ref_asm.GetType (type_name); 209 if (result != null) 210 break; 211 } catch (Exception) { 212 /* Failure to load a referenced assembly is not an error */ 213 } 214 } 215 if (result != null) 216 break; 217 } 218 } 219 220 Register (new GType (typeid), result); 221 return result; 222 } 223 224 public IntPtr Val { 225 get { 226 return val; 227 } 228 } 229 EqualsGLib.GType230 public override bool Equals (object o) 231 { 232 if (!(o is GType)) 233 return false; 234 235 return ((GType) o) == this; 236 } 237 EqualsGLib.GType238 public bool Equals (GType other) 239 { 240 return this == other; 241 } 242 operator ==GLib.GType243 public static bool operator == (GType a, GType b) 244 { 245 return a.Val == b.Val; 246 } 247 operator !=GLib.GType248 public static bool operator != (GType a, GType b) 249 { 250 return a.Val != b.Val; 251 } 252 GetHashCodeGLib.GType253 public override int GetHashCode () 254 { 255 return val.GetHashCode (); 256 } 257 258 [DllImport("libgobject-2.0-0.dll", CallingConvention=CallingConvention.Cdecl)] g_type_nameGLib.GType259 static extern IntPtr g_type_name (IntPtr raw); 260 261 [DllImport("libgobject-2.0-0.dll", CallingConvention=CallingConvention.Cdecl)] g_type_from_nameGLib.GType262 static extern IntPtr g_type_from_name (string name); 263 ToStringGLib.GType264 public override string ToString () 265 { 266 return Marshaller.Utf8PtrToString (g_type_name (val)); 267 } 268 } 269 } 270