public static GType RegisterStatic(string typeName, FlagsValue[] values) { GType.AssertGTypeName(typeName); var typeName_ = GMarshal.StringToUtf8Ptr(typeName); var values_ = GMarshal.CArrayToPtr <FlagsValue> (values, nullTerminated: true); var ret = g_flags_register_static(typeName_, values_); // values are never freed for the liftime of the program return(ret); }
/// <summary> /// ClassInit callback for managed classes. /// </summary> /// <param name="classPtr">Pointer to <see cref="Struct"/>.</param> /// <param name="userDataPtr">Pointer to user data from <see cref="TypeInfo"/>.</param> /// <remarks> /// This takes care of overriding the methods to make the managed type /// interop with the GObject type system. /// </remarks> static void UnmanagedInitManagedClass(IntPtr classPtr, IntPtr userDataPtr) { try { // Can't use type.GetGType () here since the type registration has // not finished. So, we get the GType this way instead. var gtype = Marshal.PtrToStructure <GType> (classPtr); var type = (Type)GCHandle.FromIntPtr(userDataPtr).Target; // override property native accessors Marshal.WriteIntPtr(classPtr, (int)setPropertyOffset, setPropertyPtr); Marshal.WriteIntPtr(classPtr, (int)getPropertyOffset, getPropertyPtr); Marshal.WriteIntPtr(classPtr, (int)notifyOffset, notifyPtr); // Install Properties uint propId = 1; // propId 0 is used internally, so we start with 1 foreach (var propInfo in type.GetProperties()) { if (propInfo.DeclaringType != type) { // only register properties declared in this type or in interfaces continue; } var name = propInfo.TryGetGPropertyName(); if (name == null) { // this property is not to be registered with the GObject type system continue; } // TODO: localize strings for nick and blurb var nick = propInfo.GetCustomAttribute <DisplayNameAttribute> (true) ?.DisplayName ?? name; var blurb = propInfo.GetCustomAttribute <DescriptionAttribute> (true) ?.Description ?? nick; var defaultValue = propInfo.GetCustomAttribute <DefaultValueAttribute> (true) ?.Value; // setup the flags var flags = default(ParamFlags); if (propInfo.CanRead) { flags |= ParamFlags.Readable; } if (propInfo.CanWrite) { flags |= ParamFlags.Writable; } // Construct properties don't work with managed types because they // require setting the property before the class has been instantiated. // So, we don't ever set ParamFlags.Construct or ParamFlags.ConstructOnly flags |= ParamFlags.StaticName; flags |= ParamFlags.StaticNick; flags |= ParamFlags.StaticBlurb; // Always explicit notify. Setting properties from managed code // must manually call notify, so if a property was set via // unmanaged code, it would result in double notification if // ExplicitNotify was not set. flags |= ParamFlags.ExplicitNotify; if (propInfo.GetCustomAttribute <ObsoleteAttribute> (true) != null) { flags |= ParamFlags.Deprecated; } // create the pspec instance based on type ParamSpec pspec; // TODO: Need to create special boxed type for non-GType objects var propertyGType = (GType)propInfo.PropertyType; var fundamentalGType = propertyGType.Fundamental; if (fundamentalGType == GType.Boolean) { pspec = new ParamSpecBoolean(name, nick, blurb, (bool)(defaultValue ?? default(bool)), flags); } else if (fundamentalGType == GType.Boxed) { pspec = new ParamSpecBoxed(name, nick, blurb, propertyGType, flags); } else if (fundamentalGType == GType.Char) { pspec = new ParamSpecChar(name, nick, blurb, sbyte.MinValue, sbyte.MaxValue, (sbyte)(defaultValue ?? default(sbyte)), flags); } else if (fundamentalGType == GType.UChar) { pspec = new ParamSpecUChar(name, nick, blurb, byte.MinValue, byte.MaxValue, (byte)(defaultValue ?? default(byte)), flags); } else if (fundamentalGType == GType.Double) { pspec = new ParamSpecDouble(name, nick, blurb, double.MinValue, double.MaxValue, (double)(defaultValue ?? default(double)), flags); } else if (fundamentalGType == GType.Float) { pspec = new ParamSpecFloat(name, nick, blurb, float.MinValue, float.MaxValue, (float)(defaultValue ?? default(float)), flags); } else if (fundamentalGType == GType.Enum) { pspec = new ParamSpecEnum(name, nick, blurb, propertyGType, (System.Enum)defaultValue, flags); } else if (fundamentalGType == GType.Flags) { pspec = new ParamSpecFlags(name, nick, blurb, propertyGType, (System.Enum)defaultValue, flags); } else if (fundamentalGType == GType.Int) { pspec = new ParamSpecInt(name, nick, blurb, int.MinValue, int.MaxValue, (int)(defaultValue ?? default(int)), flags); } else if (fundamentalGType == GType.UInt) { pspec = new ParamSpecUInt(name, nick, blurb, uint.MinValue, uint.MaxValue, (uint)(defaultValue ?? default(uint)), flags); } else if (fundamentalGType == GType.Int64) { pspec = new ParamSpecInt64(name, nick, blurb, long.MinValue, long.MaxValue, (long)(defaultValue ?? default(long)), flags); } else if (fundamentalGType == GType.UInt64) { pspec = new ParamSpecUInt64(name, nick, blurb, ulong.MinValue, ulong.MaxValue, (ulong)(defaultValue ?? default(ulong)), flags); } else if (fundamentalGType == GType.Long) { pspec = new ParamSpecLong(name, nick, blurb, nlong.MinValue, nlong.MaxValue, (nlong)(defaultValue ?? default(nlong)), flags); } else if (fundamentalGType == GType.ULong) { pspec = new ParamSpecULong(name, nick, blurb, nulong.MinValue, nulong.MaxValue, (nulong)(defaultValue ?? default(nulong)), flags); } else if (fundamentalGType == GType.Object) { pspec = new ParamSpecObject(name, nick, blurb, propertyGType, flags); } // TODO: do we need this one? // else if (fundamentalGType == GType.Param) { // pspec = new ParamSpecParam (name, nick, blurb, ?, flags); // } else if (fundamentalGType == GType.Pointer) { pspec = new ParamSpecPointer(name, nick, blurb, flags); } else if (fundamentalGType == GType.String) { pspec = new ParamSpecString(name, nick, blurb, (string)defaultValue, flags); } else if (fundamentalGType == GType.Type) { pspec = new ParamSpecGType(name, nick, blurb, propertyGType, flags); } else if (fundamentalGType == GType.Variant) { // TODO: need to pass variant type using attribute? // for now, always using any type var variantType = VariantType.Any; pspec = new ParamSpecVariant(name, nick, blurb, variantType, defaultValue == null ? null : (Variant)defaultValue, flags); } else { // TODO: Need more specific exception throw new Exception("unhandled GType"); } var methodInfo = propInfo.GetAccessors().First(); if (methodInfo.GetBaseDefinition() != methodInfo || propInfo.TryGetMatchingInterfacePropertyInfo() != null) { // if this type did not declare the property, the we know // we are overriding a property from a base class or interface var namePtr = GMarshal.StringToUtf8Ptr(name); g_object_class_override_property(classPtr, propId, namePtr); GMarshal.Free(namePtr); } else { g_object_class_install_property(classPtr, propId, pspec.Handle); GC.KeepAlive(pspec); } propId++; } foreach (var eventInfo in type.GetEvents()) { if (eventInfo.DeclaringType != type) { // only register events declared in this type continue; } var signalAttr = eventInfo.GetCustomAttribute <GSignalAttribute>(true); if (signalAttr == null) { // events without SignalAttribute are not installed continue; } // figure out the name var name = signalAttr.Name ?? eventInfo.Name; Signal.ValidateName(name); // figure out the flags var flags = default(SignalFlags); switch (signalAttr.When) { case EmissionStage.First: flags |= SignalFlags.RunFirst; break; case EmissionStage.Last: default: flags |= SignalFlags.RunLast; break; case EmissionStage.Cleanup: flags |= SignalFlags.RunCleanup; break; } if (signalAttr.NoRecurse) { flags |= SignalFlags.NoRecurse; } if (signalAttr.Detailed) { flags |= SignalFlags.Detailed; } if (signalAttr.Action) { flags |= SignalFlags.Action; } if (signalAttr.NoHooks) { flags |= SignalFlags.NoHooks; } if (eventInfo.GetCustomAttribute <ObsoleteAttribute> (true) != null) { flags |= SignalFlags.Deprecated; } // figure out the parameter types var methodInfo = eventInfo.EventHandlerType.GetMethod("Invoke"); var returnGType = methodInfo.ReturnType.GetGType(); var parameters = methodInfo.GetParameters(); var parameterGTypes = new GType[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { parameterGTypes[i] = parameters[i].ParameterType.GetGType(); } // create a closure that will be called when the signal is emitted var fieldInfo = type.GetField(eventInfo.Name, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); var closure = new Closure((p) => { var eventDelegate = (MulticastDelegate)fieldInfo.GetValue(p[0]); return(eventDelegate?.DynamicInvoke(p.Skip(1).ToArray())); }); // register the signal var namePtr = GMarshal.StringToUtf8Ptr(name); var parameterGTypesPtr = GMarshal.CArrayToPtr <GType> (parameterGTypes, false); Signal.g_signal_newv(namePtr, gtype, flags, closure.Handle, null, IntPtr.Zero, null, returnGType, (uint)parameterGTypes.Length, parameterGTypesPtr); } } catch (Exception ex) { ex.LogUnhandledException(); } }
/// <summary> /// This function is meant to be called from the complete_type_info() /// function of a #GTypePlugin implementation, see the example for /// g_enum_complete_type_info() above. /// </summary> /// <param name="gFlagsType"> /// the type identifier of the type being completed /// </param> /// <param name="info"> /// the #GTypeInfo struct to be filled in /// </param> /// <param name="constValues"> /// An array of #GFlagsValue structs for the possible /// enumeration values. /// </param> public static void CompleteTypeInfo(GType gFlagsType, out TypeInfo info, FlagsValue[] constValues) { var constValues_ = GMarshal.CArrayToPtr <FlagsValue> (constValues, nullTerminated: true); g_flags_complete_type_info(gFlagsType, out info, constValues_); }
/// <summary> /// This function is meant to be called from the `complete_type_info` /// function of a #GTypePlugin implementation, as in the following /// example: /// </summary> /// <remarks> /// |[<!-- language="C" --> /// static void /// my_enum_complete_type_info (GTypePlugin *plugin, /// GType g_type, /// GTypeInfo *info, /// GTypeValueTable *value_table) /// { /// static const GEnumValue values[] = { /// { MY_ENUM_FOO, "MY_ENUM_FOO", "foo" }, /// { MY_ENUM_BAR, "MY_ENUM_BAR", "bar" }, /// { 0, NULL, NULL } /// }; /// /// g_enum_complete_type_info (type, info, values); /// } /// ]| /// </remarks> /// <param name="gEnumType"> /// the type identifier of the type being completed /// </param> /// <param name="info"> /// the #GTypeInfo struct to be filled in /// </param> /// <param name="constValues"> /// An array of #GEnumValue structs for the possible /// enumeration values. The array is terminated by a struct with all /// members being 0. /// </param> static void CompleteTypeInfo(GType gEnumType, out TypeInfo info, EnumValue[] constValues) { var constValues_ = GMarshal.CArrayToPtr <EnumValue> (constValues, nullTerminated: true); g_enum_complete_type_info(gEnumType, out info, constValues_); }