DynamicSignal: Reformat to match conventions

This commit is contained in:
Stephan Sundermann 2014-11-25 11:13:44 +01:00
parent 5b386f21fb
commit db3ffc2a70

View file

@ -29,401 +29,429 @@ using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Collections; using System.Collections;
namespace Gst { namespace Gst
{
delegate void GClosureMarshal (IntPtr closure, ref GLib.Value retval, uint argc, IntPtr argsPtr, delegate void GClosureMarshal (IntPtr closure, ref GLib.Value retval, uint argc, IntPtr argsPtr,
IntPtr invocation_hint, IntPtr data); IntPtr invocation_hint, IntPtr data);
public delegate void SignalHandler (object o, SignalArgs args); public delegate void SignalHandler (object o, SignalArgs args);
public static class DynamicSignal { public static class DynamicSignal
{
private static readonly int gvalue_struct_size = Marshal.SizeOf (typeof (GLib.Value));
private static readonly int gvalue_struct_size = Marshal.SizeOf (typeof(GLib.Value));
class ObjectSignalKey {
object o; class ObjectSignalKey
string signal_name; {
object o;
public ObjectSignalKey (object o, string name) { string signal_name;
this.o = o;
signal_name = name; public ObjectSignalKey (object o, string name)
} {
this.o = o;
public override bool Equals (object o) { signal_name = name;
if (o is ObjectSignalKey) { }
ObjectSignalKey k = (ObjectSignalKey) o;
return k.o.Equals (this.o) && signal_name.Equals (k.signal_name); public override bool Equals (object o)
} {
return base.Equals (o); if (o is ObjectSignalKey) {
} ObjectSignalKey k = (ObjectSignalKey)o;
return k.o.Equals (this.o) && signal_name.Equals (k.signal_name);
public override int GetHashCode() { }
return o.GetHashCode() ^ signal_name.GetHashCode(); return base.Equals (o);
} }
}
public override int GetHashCode ()
class SignalInfo { {
uint handlerId; return o.GetHashCode () ^ signal_name.GetHashCode ();
IntPtr closure; }
Delegate registeredHandler; }
Type argsType;
class SignalInfo
public IntPtr Closure { {
get { uint handlerId;
return closure; IntPtr closure;
} set { Delegate registeredHandler;
closure = value; Type argsType;
}
} public IntPtr Closure {
get {
public uint HandlerId { return closure;
get { }
return handlerId; set {
} set { closure = value;
handlerId = value; }
} }
}
public uint HandlerId {
public Delegate RegisteredHandler { get {
get { return handlerId;
return registeredHandler; }
} set { set {
registeredHandler = value; handlerId = value;
} }
} }
public Type ArgsType { public Delegate RegisteredHandler {
get { get {
return argsType; return registeredHandler;
} set { }
argsType = value; set {
} registeredHandler = value;
} }
}
public SignalInfo (uint handlerId, IntPtr closure, Delegate registeredHandler) {
this.handlerId = handlerId; public Type ArgsType {
this.closure = closure; get {
this.registeredHandler = registeredHandler; return argsType;
}
if (!IsValidDelegate (registeredHandler)) set {
throw new Exception ("Invalid delegate"); argsType = value;
}
MethodInfo mi = registeredHandler.Method; }
ParameterInfo[] parms = mi.GetParameters ();
this.argsType = parms[1].ParameterType; public SignalInfo (uint handlerId, IntPtr closure, Delegate registeredHandler)
} {
this.handlerId = handlerId;
public void UpdateArgsType (Delegate d) { this.closure = closure;
if (!IsCompatibleDelegate (d)) this.registeredHandler = registeredHandler;
throw new Exception ("Incompatible delegate");
if (!IsValidDelegate (registeredHandler))
MethodInfo mi = d.Method; throw new Exception ("Invalid delegate");
ParameterInfo[] parms = mi.GetParameters ();
MethodInfo mi = registeredHandler.Method;
Type t1 = parms[1].ParameterType; ParameterInfo[] parms = mi.GetParameters ();
Type t2 = argsType; this.argsType = parms [1].ParameterType;
}
if (t1 == t2)
return; public void UpdateArgsType (Delegate d)
{
if (t1.IsSubclassOf (t2)) if (!IsCompatibleDelegate (d))
argsType = t1; throw new Exception ("Incompatible delegate");
else if (t2.IsSubclassOf (t1))
argsType = t2; MethodInfo mi = d.Method;
else ParameterInfo[] parms = mi.GetParameters ();
throw new Exception ("Incompatible delegate");
} Type t1 = parms [1].ParameterType;
Type t2 = argsType;
public bool IsCompatibleDelegate (Delegate d) {
if (!IsValidDelegate (d)) if (t1 == t2)
return false; return;
MethodInfo mi = d.Method; if (t1.IsSubclassOf (t2))
ParameterInfo[] parms = mi.GetParameters (); argsType = t1;
else if (t2.IsSubclassOf (t1))
if (parms[1].ParameterType != this.argsType && argsType = t2;
!parms[1].ParameterType.IsSubclassOf (this.argsType) && else
!this.argsType.IsSubclassOf (parms[1].ParameterType)) throw new Exception ("Incompatible delegate");
return false; }
return true; public bool IsCompatibleDelegate (Delegate d)
} {
if (!IsValidDelegate (d))
public static bool IsValidDelegate (Delegate d) { return false;
MethodInfo mi = d.Method;
MethodInfo mi = d.Method;
if (mi.ReturnType != typeof (void)) ParameterInfo[] parms = mi.GetParameters ();
return false;
if (parms [1].ParameterType != this.argsType &&
ParameterInfo[] parms = mi.GetParameters (); !parms [1].ParameterType.IsSubclassOf (this.argsType) &&
if (parms.Length != 2) !this.argsType.IsSubclassOf (parms [1].ParameterType))
return false; return false;
if (parms[1].ParameterType != typeof (GLib.SignalArgs) && return true;
!parms[1].ParameterType.IsSubclassOf (typeof (GLib.SignalArgs))) }
return false;
public static bool IsValidDelegate (Delegate d)
return true; {
} MethodInfo mi = d.Method;
}
if (mi.ReturnType != typeof(void))
static Hashtable SignalHandlers = new Hashtable(); return false;
static GClosureMarshal marshalHandler = new GClosureMarshal (OnMarshal); ParameterInfo[] parms = mi.GetParameters ();
if (parms.Length != 2)
public static void Connect (GLib.Object o, string name, SignalHandler handler) { return false;
Connect (o, name, false, (Delegate) handler);
} if (parms [1].ParameterType != typeof(GLib.SignalArgs) &&
!parms [1].ParameterType.IsSubclassOf (typeof(GLib.SignalArgs)))
public static void Connect (GLib.Object o, string name, return false;
bool after, SignalHandler handler) {
Connect (o, name, after, (Delegate) handler); return true;
} }
}
public static void Connect (GLib.Object o, string name, Delegate handler) {
Connect (o, name, false, handler); static Hashtable SignalHandlers = new Hashtable ();
}
static GClosureMarshal marshalHandler = new GClosureMarshal (OnMarshal);
static int g_closure_sizeof = gstsharp_g_closure_sizeof ();
public static void Connect (GLib.Object o, string name, SignalHandler handler)
public static void Connect (GLib.Object o, string name, {
bool after, Delegate handler) { Connect (o, name, false, (Delegate)handler);
Delegate newHandler; }
ObjectSignalKey k = new ObjectSignalKey (o, name); public static void Connect (GLib.Object o, string name,
bool after, SignalHandler handler)
if (!SignalInfo.IsValidDelegate (handler)) {
throw new Exception ("Invalid delegate"); Connect (o, name, after, (Delegate)handler);
}
if (SignalHandlers[k] != null) {
SignalInfo si = (SignalInfo) SignalHandlers[k]; public static void Connect (GLib.Object o, string name, Delegate handler)
if (!si.IsCompatibleDelegate (handler)) {
throw new Exception ("Incompatible delegate"); Connect (o, name, false, handler);
}
newHandler = Delegate.Combine (si.RegisteredHandler, handler);
si.UpdateArgsType (handler); static int g_closure_sizeof = gstsharp_g_closure_sizeof ();
si.RegisteredHandler = newHandler;
} else { public static void Connect (GLib.Object o, string name,
if (!SignalInfo.IsValidDelegate (handler)) bool after, Delegate handler)
throw new Exception ("Invalid delegate"); {
Delegate newHandler;
IntPtr closure = g_closure_new_simple (g_closure_sizeof, IntPtr.Zero);
g_closure_set_meta_marshal (closure, (IntPtr) GCHandle.Alloc (k), marshalHandler); ObjectSignalKey k = new ObjectSignalKey (o, name);
uint signalId = g_signal_connect_closure (o.Handle, name, closure, after);
SignalHandlers.Add (k, new SignalInfo (signalId, closure, handler)); if (!SignalInfo.IsValidDelegate (handler))
} throw new Exception ("Invalid delegate");
}
if (SignalHandlers [k] != null) {
[DllImport ("libgstreamersharpglue-1.0.0.dll") ] SignalInfo si = (SignalInfo)SignalHandlers [k];
static extern int gstsharp_g_closure_sizeof (); if (!si.IsCompatibleDelegate (handler))
throw new Exception ("Incompatible delegate");
public static void Disconnect (GLib.Object o, string name, Delegate handler) {
ObjectSignalKey k = new ObjectSignalKey (o, name); newHandler = Delegate.Combine (si.RegisteredHandler, handler);
if (SignalHandlers[k] != null) { si.UpdateArgsType (handler);
SignalInfo si = (SignalInfo) SignalHandlers[k]; si.RegisteredHandler = newHandler;
Delegate newHandler = Delegate.Remove (si.RegisteredHandler, handler); } else {
if (newHandler == null || handler == null) { if (!SignalInfo.IsValidDelegate (handler))
g_signal_handler_disconnect (o.Handle, si.HandlerId); throw new Exception ("Invalid delegate");
SignalHandlers.Remove (k);
} else { IntPtr closure = g_closure_new_simple (g_closure_sizeof, IntPtr.Zero);
si.RegisteredHandler = newHandler; g_closure_set_meta_marshal (closure, (IntPtr)GCHandle.Alloc (k), marshalHandler);
} uint signalId = g_signal_connect_closure (o.Handle, name, closure, after);
} SignalHandlers.Add (k, new SignalInfo (signalId, closure, handler));
} }
}
static void OnMarshal (IntPtr closure, ref GLib.Value retval, uint argc, IntPtr argsPtr,
IntPtr ihint, IntPtr data) { [DllImport ("libgstreamersharpglue-1.0.0.dll")]
object [] args = new object[argc - 1]; static extern int gstsharp_g_closure_sizeof ();
object o = ( (GLib.Value) Marshal.PtrToStructure (argsPtr, typeof (GLib.Value))).Val;
public static void Disconnect (GLib.Object o, string name, Delegate handler)
for (int i = 1; i < argc; i++) { {
IntPtr struct_ptr = (IntPtr) ( (long) argsPtr + (i * gvalue_struct_size)); ObjectSignalKey k = new ObjectSignalKey (o, name);
GLib.Value argument = (GLib.Value) Marshal.PtrToStructure (struct_ptr, typeof (GLib.Value)); if (SignalHandlers [k] != null) {
args[i - 1] = argument.Val; SignalInfo si = (SignalInfo)SignalHandlers [k];
} Delegate newHandler = Delegate.Remove (si.RegisteredHandler, handler);
if (newHandler == null || handler == null) {
if (data == IntPtr.Zero) { g_signal_handler_disconnect (o.Handle, si.HandlerId);
Console.Error.WriteLine ("No available data"); SignalHandlers.Remove (k);
return; } else {
} si.RegisteredHandler = newHandler;
}
ObjectSignalKey k = (ObjectSignalKey) ( (GCHandle) data).Target; }
if (k != null) { }
SignalInfo si = (SignalInfo) SignalHandlers[k];
GLib.SignalArgs arg = (GLib.SignalArgs) Activator.CreateInstance (si.ArgsType); static void OnMarshal (IntPtr closure, ref GLib.Value retval, uint argc, IntPtr argsPtr,
arg.Args = args; IntPtr ihint, IntPtr data)
si.RegisteredHandler.DynamicInvoke (new object[] {o, arg}); {
if (arg.RetVal != null) { object[] args = new object[argc - 1];
retval.Val = arg.RetVal; object o = ((GLib.Value)Marshal.PtrToStructure (argsPtr, typeof(GLib.Value))).Val;
}
} for (int i = 1; i < argc; i++) {
} IntPtr struct_ptr = (IntPtr)((long)argsPtr + (i * gvalue_struct_size));
GLib.Value argument = (GLib.Value)Marshal.PtrToStructure (struct_ptr, typeof(GLib.Value));
args [i - 1] = argument.Val;
[DllImport ("libgobject-2.0-0.dll") ] }
static extern IntPtr g_closure_new_simple (int size, IntPtr data);
if (data == IntPtr.Zero) {
[DllImport ("libgobject-2.0-0.dll") ] Console.Error.WriteLine ("No available data");
static extern uint g_signal_connect_closure (IntPtr instance, return;
string name, IntPtr closure, bool after); }
[DllImport ("libgobject-2.0-0.dll") ] ObjectSignalKey k = (ObjectSignalKey)((GCHandle)data).Target;
static extern void g_closure_set_meta_marshal (IntPtr closure, IntPtr data, GClosureMarshal marshal); if (k != null) {
SignalInfo si = (SignalInfo)SignalHandlers [k];
class GTypeSignalKey { GLib.SignalArgs arg = (GLib.SignalArgs)Activator.CreateInstance (si.ArgsType);
GType type; arg.Args = args;
string signal_name; si.RegisteredHandler.DynamicInvoke (new object[] { o, arg });
if (arg.RetVal != null) {
public GTypeSignalKey (GType type, string name) { retval.Val = arg.RetVal;
this.type = type; }
signal_name = name; }
} }
public override bool Equals (object o) {
if (o is GTypeSignalKey) { [DllImport ("libgobject-2.0-0.dll")]
GTypeSignalKey k = (GTypeSignalKey) o; static extern IntPtr g_closure_new_simple (int size, IntPtr data);
return k.type.Equals (this.type) && signal_name.Equals (k.signal_name);
} [DllImport ("libgobject-2.0-0.dll")]
return base.Equals (o); static extern uint g_signal_connect_closure (IntPtr instance,
} string name, IntPtr closure, bool after);
public override int GetHashCode() { [DllImport ("libgobject-2.0-0.dll")]
return type.GetHashCode() ^ signal_name.GetHashCode(); static extern void g_closure_set_meta_marshal (IntPtr closure, IntPtr data, GClosureMarshal marshal);
}
} class GTypeSignalKey
{
struct SignalQuery { GType type;
public uint signal_id; string signal_name;
public string signal_name;
public GType itype; public GTypeSignalKey (GType type, string name)
public uint signal_flags; {
public GType return_type; this.type = type;
public uint n_params; signal_name = name;
public Type[] param_types; }
}
public override bool Equals (object o)
static Hashtable SignalEmitInfo = new Hashtable (); {
if (o is GTypeSignalKey) {
public static object Emit (GLib.Object o, string name, params object[] parameters) { GTypeSignalKey k = (GTypeSignalKey)o;
SignalQuery query; return k.type.Equals (this.type) && signal_name.Equals (k.signal_name);
IntPtr type = gstsharp_g_type_from_instance (o.Handle); }
GType gtype = new GType (type); return base.Equals (o);
string signal_name, signal_detail; }
uint signal_detail_quark = 0;
int colon; public override int GetHashCode ()
{
colon = name.LastIndexOf ("::"); return type.GetHashCode () ^ signal_name.GetHashCode ();
}
if (colon == -1) { }
signal_name = name;
signal_detail = String.Empty; struct SignalQuery
} else { {
signal_name = name.Substring (0, colon); public uint signal_id;
signal_detail = name.Substring (colon + 2); public string signal_name;
} public GType itype;
public uint signal_flags;
GTypeSignalKey key = new GTypeSignalKey (gtype, signal_name); public GType return_type;
public uint n_params;
if (SignalEmitInfo[key] == null) { public Type[] param_types;
IntPtr native_string = GLib.Marshaller.StringToPtrGStrdup (signal_name); }
uint signal_id = g_signal_lookup (native_string, type);
GLib.Marshaller.Free (native_string); static Hashtable SignalEmitInfo = new Hashtable ();
if (signal_id == 0) public static object Emit (GLib.Object o, string name, params object[] parameters)
throw new NotSupportedException (String.Format ("{0} has no signal of name {1}", o, name)); {
GSignalQuery q = new GSignalQuery (); SignalQuery query;
g_signal_query (signal_id, ref q); IntPtr type = gstsharp_g_type_from_instance (o.Handle);
GType gtype = new GType (type);
if (q.signal_id == 0) string signal_name, signal_detail;
throw new NotSupportedException (String.Format ("{0} couldn't be queried for signal with name {1}", o, name)); uint signal_detail_quark = 0;
int colon;
query = new SignalQuery ();
colon = name.LastIndexOf ("::");
query.signal_id = signal_id;
query.signal_name = GLib.Marshaller.Utf8PtrToString (q.signal_name); if (colon == -1) {
query.itype = new GType (q.itype); signal_name = name;
query.signal_flags = q.signal_flags; signal_detail = String.Empty;
query.return_type = new GType (q.return_type); } else {
query.n_params = q.n_params; signal_name = name.Substring (0, colon);
query.param_types = new Type[q.n_params]; signal_detail = name.Substring (colon + 2);
}
for (int i = 0; i < query.n_params; i++) {
IntPtr t = Marshal.ReadIntPtr (q.param_types, i); GTypeSignalKey key = new GTypeSignalKey (gtype, signal_name);
GType g = new GType (t);
if (SignalEmitInfo [key] == null) {
query.param_types[i] = (Type) g; IntPtr native_string = GLib.Marshaller.StringToPtrGStrdup (signal_name);
} uint signal_id = g_signal_lookup (native_string, type);
GLib.Marshaller.Free (native_string);
SignalEmitInfo.Add (key, query);
} if (signal_id == 0)
throw new NotSupportedException (String.Format ("{0} has no signal of name {1}", o, name));
query = (SignalQuery) SignalEmitInfo[key]; GSignalQuery q = new GSignalQuery ();
GLib.Value[] signal_parameters = new GLib.Value[query.n_params + 1]; g_signal_query (signal_id, ref q);
signal_parameters[0] = new GLib.Value (o);
if (q.signal_id == 0)
if (parameters.Length != query.n_params) throw new NotSupportedException (String.Format ("{0} couldn't be queried for signal with name {1}", o, name));
throw new ApplicationException (String.Format ("Invalid number of parameters: expected {0}, got {1}", query.n_params, parameters.Length));
query = new SignalQuery ();
for (int i = 0; i < query.n_params; i++) {
Type expected_type = (Type) query.param_types[i]; query.signal_id = signal_id;
Type given_type = parameters[i].GetType (); query.signal_name = GLib.Marshaller.Utf8PtrToString (q.signal_name);
query.itype = new GType (q.itype);
if (expected_type != given_type && ! given_type.IsSubclassOf (given_type)) query.signal_flags = q.signal_flags;
throw new ApplicationException (String.Format ("Invalid parameter type: expected {0}, got {1}", expected_type, given_type)); query.return_type = new GType (q.return_type);
query.n_params = q.n_params;
signal_parameters[i + 1] = new GLib.Value (parameters[i]); query.param_types = new Type[q.n_params];
}
for (int i = 0; i < query.n_params; i++) {
GLib.Value return_value = new GLib.Value (); IntPtr t = Marshal.ReadIntPtr (q.param_types, i);
if (query.return_type != GType.Invalid && query.return_type != GType.None) GType g = new GType (t);
return_value.Init (query.return_type);
query.param_types [i] = (Type)g;
if (signal_detail != String.Empty) { }
IntPtr native_string = GLib.Marshaller.StringToPtrGStrdup (signal_detail);
signal_detail_quark = g_quark_from_string (native_string); SignalEmitInfo.Add (key, query);
GLib.Marshaller.Free (native_string); }
}
query = (SignalQuery)SignalEmitInfo [key];
g_signal_emitv (signal_parameters, query.signal_id, signal_detail_quark, ref return_value); GLib.Value[] signal_parameters = new GLib.Value[query.n_params + 1];
signal_parameters [0] = new GLib.Value (o);
foreach (GLib.Value v in signal_parameters)
v.Dispose (); if (parameters.Length != query.n_params)
throw new ApplicationException (String.Format ("Invalid number of parameters: expected {0}, got {1}", query.n_params, parameters.Length));
object ret = (query.return_type != GType.Invalid && query.return_type != GType.None) ? return_value.Val : null;
for (int i = 0; i < query.n_params; i++) {
if (ret != null) Type expected_type = (Type)query.param_types [i];
return_value.Dispose (); Type given_type = parameters [i].GetType ();
return ret; if (expected_type != given_type && !given_type.IsSubclassOf (given_type))
} throw new ApplicationException (String.Format ("Invalid parameter type: expected {0}, got {1}", expected_type, given_type));
signal_parameters [i + 1] = new GLib.Value (parameters [i]);
}
GLib.Value return_value = new GLib.Value ();
if (query.return_type != GType.Invalid && query.return_type != GType.None)
return_value.Init (query.return_type);
if (signal_detail != String.Empty) {
IntPtr native_string = GLib.Marshaller.StringToPtrGStrdup (signal_detail);
signal_detail_quark = g_quark_from_string (native_string);
GLib.Marshaller.Free (native_string);
}
g_signal_emitv (signal_parameters, query.signal_id, signal_detail_quark, ref return_value);
foreach (GLib.Value v in signal_parameters)
v.Dispose ();
object ret = (query.return_type != GType.Invalid && query.return_type != GType.None) ? return_value.Val : null;
if (ret != null)
return_value.Dispose ();
return ret;
}
[DllImport ("libgstreamersharpglue-1.0.0.dll") ] [DllImport ("libgstreamersharpglue-1.0.0.dll")]
static extern IntPtr gstsharp_g_type_from_instance (IntPtr o); static extern IntPtr gstsharp_g_type_from_instance (IntPtr o);
[DllImport ("libgobject-2.0-0.dll") ] [DllImport ("libgobject-2.0-0.dll")]
static extern int g_signal_handler_disconnect (IntPtr o, uint handler_id); static extern int g_signal_handler_disconnect (IntPtr o, uint handler_id);
[DllImport ("libgobject-2.0-0.dll") ] [DllImport ("libgobject-2.0-0.dll")]
static extern uint g_signal_lookup (IntPtr name, IntPtr itype); static extern uint g_signal_lookup (IntPtr name, IntPtr itype);
[DllImport ("libglib-2.0-0.dll") ] [DllImport ("libglib-2.0-0.dll")]
static extern uint g_quark_from_string (IntPtr str); static extern uint g_quark_from_string (IntPtr str);
[DllImport ("libgobject-2.0-0.dll") ] [DllImport ("libgobject-2.0-0.dll")]
static extern void g_signal_emitv (GLib.Value[] parameters, uint signal_id, uint detail, ref GLib.Value return_value); static extern void g_signal_emitv (GLib.Value[] parameters, uint signal_id, uint detail, ref GLib.Value return_value);
[StructLayout (LayoutKind.Sequential) ] [StructLayout (LayoutKind.Sequential)]
struct GSignalQuery { struct GSignalQuery
public uint signal_id; {
public IntPtr signal_name; public uint signal_id;
public IntPtr itype; public IntPtr signal_name;
public uint signal_flags; public IntPtr itype;
public IntPtr return_type; public uint signal_flags;
public uint n_params; public IntPtr return_type;
public IntPtr param_types; public uint n_params;
} public IntPtr param_types;
}
[DllImport ("libgobject-2.0-0.dll") ] [DllImport ("libgobject-2.0-0.dll")]
static extern void g_signal_query (uint signal_id, ref GSignalQuery query); static extern void g_signal_query (uint signal_id, ref GSignalQuery query);
} }
} }