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())); } }
// Wraps a pointer to a GObject with a native wrapper type // NOTE: generic type T is the type we want to cast as, NOT the // actual type of the object. public static T WrapPointerAs <T>(IntPtr ptr, bool owned) where T : GLib.Object, new() { // Sanity Check if (ptr == IntPtr.Zero) { return(null); } // 1. Check if we already have a wrapper for this instance // We should always have an existing wrapper for subclasses // because the object must never outlive the wrapper. // // NOTE: If we for some reason need to create wrappers for user-defined // types in the future, it may be worth adding a GObjectArgs type to pass // to constructors to inhibit construction. GLib.Object wrapper; if (wrappers.TryGetValue(ptr, out wrapper)) { if (owned && !wrapper.isOwned) { wrapper.Take(); } // Ensure it is possible to return the wrapper // as the requested type. bool isEqual = wrapper.GetType() == typeof(T); bool isSubclass = wrapper.GetType().IsSubclassOf(typeof(T)); if (!(isEqual || isSubclass)) { throw new InvalidCastException($"Cannot get pointer as {typeof(T).FullName}"); } return((T)wrapper); } // 2. No wrapper exists for this pointer. We assume that the pointer cannot be a // user created managed subclass (this will always match the lifetime of the native // object), so we initialise a new wrapper with the type of the pointer. GTypeInstance obj = (GTypeInstance)Marshal.PtrToStructure(ptr, typeof(GTypeInstance)); GTypeClass klass = (GTypeClass)Marshal.PtrToStructure(obj.g_class, typeof(GTypeClass)); System.Type realType = (Type) new GLib.GType(klass.gtype); // We cannot wrap a subclass // The subclass wrapper must always outlive the GObject and we // enforce this with ToggleRefs // TODO: Use ToggleRefs if (IsManaged(typeof(T))) { throw new Exception("We cannot wrap a managed subclass. Something has gone very wrong"); } // 3. Create the wrapper type. The wrapper uses lazy initialisation to allow us to // alternatively initialise it as a wrapper, so we call InitWrapper before Handle // can be used. T ret = (T)Activator.CreateInstance(realType, null); ret.InitWrapper(ptr, owned); return(ret); }