Don't allow subclassing of element bindings

...and clean up/simplify the DynamicSignal stuff.
This commit is contained in:
Sebastian Dröge 2009-06-05 20:59:24 +02:00
parent 0196d9b622
commit 8ece992223
9 changed files with 126 additions and 98 deletions

View file

@ -255,7 +255,7 @@ public class ElementGen {
string class_name = (ei.class_name != null) ? ei.class_name : ei.gtype_name.StartsWith ("Gst") ? ei.gtype_name.Substring (3) : ei.gtype_name;
writer.Write ("\tpublic class " + class_name + " : ");
writer.Write ("\tpublic sealed class " + class_name + " : ");
for (int i = 1; i < ei.hierarchy.Count; i++) {
string parent_type = (string) ei.hierarchy[i];
string parent_managed_type = CTypeToManagedType (parent_type, api_doc);
@ -349,19 +349,13 @@ public class ElementGen {
}
writer.WriteLine ("\t\t}\n");
writer.WriteLine ("\t\tprivate Delegate " + managed_name + "_delegate;\n");
writer.WriteLine ("\t\tprotected virtual void On" + managed_name + " (object o, GLib.SignalArgs args) {");
writer.WriteLine ("\t\t\tBindingHelper.InvokeProxySignalDelegate (" + managed_name + "_delegate, typeof (" + managed_name + "Args), o, args);");
writer.WriteLine ("\t\t}\n");
writer.WriteLine ("\t\tpublic event " + managed_name + "Handler " + managed_name + " {");
writer.WriteLine ("\t\t\tadd {");
writer.WriteLine ("\t\t\t\t" + managed_name + "_delegate = BindingHelper.AddProxySignalDelegate (this, \"" + si.name + "\", On" + managed_name + ", " + managed_name + "_delegate, value);");
writer.WriteLine ("\t\t\t\tDynamicSignal.Connect (this, \"" + si.name + "\", value);");
writer.WriteLine ("\t\t\t}\n");
writer.WriteLine ("\t\t\tremove {");
writer.WriteLine ("\t\t\t\t" + managed_name + "_delegate = BindingHelper.RemoveProxySignalDelegate (this, \"" + si.name + "\", On" + managed_name + ", " + managed_name + "_delegate, value);");
writer.WriteLine ("\t\t\t\tDynamicSignal.Disconnect (this, \"" + si.name + "\", value);");
writer.WriteLine ("\t\t\t}");
writer.WriteLine ("\t\t}");
}

View file

@ -1,50 +0,0 @@
//
// BindingHelper.cs: Utility methods to make creating
// element bindings by hand an easier task
//
// Authors:
// Aaron Bockover (abockover@novell.com)
//
// Copyright (C) 2006 Novell, Inc.
//
using System;
using GLib;
namespace Gst {
public static class BindingHelper {
public static Delegate AddProxySignalDelegate (GLib.Object o, string signal,
DynamicSignalHandler baseHandler, Delegate existingHandler, Delegate addHandler) {
if (existingHandler == null) {
DynamicSignal.Connect (o, signal, baseHandler);
}
return Delegate.Combine (existingHandler, addHandler);
}
public static Delegate RemoveProxySignalDelegate (GLib.Object o, string signal,
DynamicSignalHandler baseHandler, Delegate existingHandler, Delegate removeHandler) {
Delegate temp_delegate = Delegate.Remove (existingHandler, removeHandler);
if (temp_delegate == null) {
DynamicSignal.Disconnect (o, signal, baseHandler);
}
return temp_delegate;
}
public static void InvokeProxySignalDelegate (Delegate raiseDelegate, Type type,
object o, GLib.SignalArgs args) {
if (!type.IsSubclassOf (typeof (GLib.SignalArgs))) {
throw new ArgumentException ("Args type must derive SignalArgs");
}
if (raiseDelegate != null) {
GLib.SignalArgs new_args = (GLib.SignalArgs) Activator.CreateInstance (type);
new_args.RetVal = args.RetVal;
new_args.Args = args.Args;
raiseDelegate.DynamicInvoke (new object [] { o, new_args });
}
}
}
}

View file

@ -10,16 +10,17 @@
using GLib;
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Collections;
namespace Gst {
public delegate void DynamicSignalHandler (object o, SignalArgs args);
delegate void GClosureMarshal (IntPtr closure, ref GLib.Value retval, uint argc, IntPtr argsPtr,
IntPtr invocation_hint, IntPtr data);
public delegate void SignalHandler (object o, SignalArgs args);
public static class DynamicSignal {
private static readonly int gvalue_struct_size = Marshal.SizeOf (typeof (GLib.Value));
@ -50,6 +51,7 @@ namespace Gst {
uint handlerId;
IntPtr closure;
Delegate registeredHandler;
Type argsType;
public IntPtr Closure {
get {
@ -78,10 +80,79 @@ namespace Gst {
}
}
public Type ArgsType {
get {
return argsType;
}
set {
argsType = value;
}
}
public SignalInfo (uint handlerId, IntPtr closure, Delegate registeredHandler) {
this.handlerId = handlerId;
this.closure = closure;
this.registeredHandler = registeredHandler;
if (!IsValidDelegate (registeredHandler))
throw new Exception ("Invalid delegate");
MethodInfo mi = registeredHandler.Method;
ParameterInfo[] parms = mi.GetParameters ();
this.argsType = parms[1].ParameterType;
}
public void UpdateArgsType (Delegate d) {
if (!IsCompatibleDelegate (d))
throw new Exception ("Incompatible delegate");
MethodInfo mi = d.Method;
ParameterInfo[] parms = mi.GetParameters ();
Type t1 = parms[1].ParameterType;
Type t2 = argsType;
if (t1 == t2)
return;
if (t1.IsSubclassOf (t2))
argsType = t1;
else if (t2.IsSubclassOf (t1))
argsType = t2;
else
throw new Exception ("Incompatible delegate");
}
public bool IsCompatibleDelegate (Delegate d) {
if (!IsValidDelegate (d))
return false;
MethodInfo mi = d.Method;
ParameterInfo[] parms = mi.GetParameters ();
if (parms[1].ParameterType != this.argsType &&
!parms[1].ParameterType.IsSubclassOf (this.argsType) &&
!this.argsType.IsSubclassOf (parms[1].ParameterType))
return false;
return true;
}
public static bool IsValidDelegate (Delegate d) {
MethodInfo mi = d.Method;
if (mi.ReturnType != typeof (void))
return false;
ParameterInfo[] parms = mi.GetParameters ();
if (parms.Length != 2)
return false;
if (parms[1].ParameterType != typeof (GLib.SignalArgs) &&
!parms[1].ParameterType.IsSubclassOf (typeof (GLib.SignalArgs)))
return false;
return true;
}
}
@ -89,23 +160,42 @@ namespace Gst {
static GClosureMarshal marshalHandler = new GClosureMarshal (OnMarshal);
public static void Connect (GLib.Object o, string name, DynamicSignalHandler handler) {
public static void Connect (GLib.Object o, string name, SignalHandler handler) {
Connect (o, name, false, (Delegate) handler);
}
public static void Connect (GLib.Object o, string name,
bool after, SignalHandler handler) {
Connect (o, name, after, (Delegate) handler);
}
public static void Connect (GLib.Object o, string name, Delegate handler) {
Connect (o, name, false, handler);
}
static int g_closure_sizeof = gstsharp_g_closure_sizeof ();
public static void Connect (GLib.Object o, string name,
bool after, DynamicSignalHandler handler) {
bool after, Delegate handler) {
Delegate newHandler;
ObjectSignalKey k = new ObjectSignalKey (o, name);
if (!SignalInfo.IsValidDelegate (handler))
throw new Exception ("Invalid delegate");
if (SignalHandlers[k] != null) {
SignalInfo si = (SignalInfo) SignalHandlers[k];
if (!si.IsCompatibleDelegate (handler))
throw new Exception ("Incompatible delegate");
newHandler = Delegate.Combine (si.RegisteredHandler, handler);
si.UpdateArgsType (handler);
si.RegisteredHandler = newHandler;
} else {
if (!SignalInfo.IsValidDelegate (handler))
throw new Exception ("Invalid delegate");
IntPtr closure = g_closure_new_simple (g_closure_sizeof, IntPtr.Zero);
g_closure_set_meta_marshal (closure, (IntPtr) GCHandle.Alloc (k), marshalHandler);
uint signalId = g_signal_connect_closure (o.Handle, name, closure, after);
@ -116,7 +206,7 @@ namespace Gst {
[DllImport ("gstreamersharpglue-0.10.dll") ]
static extern int gstsharp_g_closure_sizeof ();
public static void Disconnect (GLib.Object o, string name, DynamicSignalHandler handler) {
public static void Disconnect (GLib.Object o, string name, Delegate handler) {
ObjectSignalKey k = new ObjectSignalKey (o, name);
if (SignalHandlers[k] != null) {
SignalInfo si = (SignalInfo) SignalHandlers[k];
@ -143,15 +233,15 @@ namespace Gst {
if (data == IntPtr.Zero) {
Console.Error.WriteLine ("No available data");
return;
}
ObjectSignalKey k = (ObjectSignalKey) ( (GCHandle) data).Target;
if (k != null) {
SignalArgs arg = new SignalArgs();
arg.Args = args;
SignalInfo si = (SignalInfo) SignalHandlers[k];
DynamicSignalHandler handler = (DynamicSignalHandler) si.RegisteredHandler;
handler (o, arg);
GLib.SignalArgs arg = (GLib.SignalArgs) Activator.CreateInstance (si.ArgsType);
arg.Args = args;
si.RegisteredHandler.DynamicInvoke (new object[] {o, arg});
if (arg.RetVal != null) {
retval.Val = arg.RetVal;
}

View file

@ -38,7 +38,6 @@ clean-local:
sources = \
DynamicSignal.cs \
BindingHelper.cs \
Application.cs \
Version.cs \
AssemblyInfo.cs \

View file

@ -49,11 +49,19 @@ public PropertyInfo[] Properties {
}
}
public void Connect (string signal, DynamicSignalHandler handler) {
public void Connect (string signal, SignalHandler handler) {
DynamicSignal.Connect (this, signal, handler);
}
public void Disconnect (string signal, DynamicSignalHandler handler) {
public void Disconnect (string signal, SignalHandler handler) {
DynamicSignal.Disconnect (this, signal, handler);
}
public void Connect (string signal, Delegate handler) {
DynamicSignal.Connect (this, signal, handler);
}
public void Disconnect (string signal, Delegate handler) {
DynamicSignal.Disconnect (this, signal, handler);
}

View file

@ -103,19 +103,13 @@ public class StreamInfo : GLib.Object {
}
private Delegate Muted_delegate;
protected virtual void OnMuted (object o, GLib.SignalArgs args) {
BindingHelper.InvokeProxySignalDelegate (Muted_delegate, typeof (MutedArgs), o, args);
}
public event MutedHandler Muted {
add {
Muted_delegate = BindingHelper.AddProxySignalDelegate (this, "muted", OnMuted, Muted_delegate, value);
DynamicSignal.Connect (this, "muted", value);
}
remove {
Muted_delegate = BindingHelper.RemoveProxySignalDelegate (this, "muted", OnMuted, Muted_delegate, value);
DynamicSignal.Disconnect (this, "muted", value);
}
}

View file

@ -9,6 +9,7 @@
using System;
using Gst;
using Gst.CorePlugins;
using Gst.BasePlugins;
public delegate void ErrorHandler(object o, ErrorArgs args);
@ -28,8 +29,8 @@ public class ProgressArgs : EventArgs
public class DecodeBinTranscoder : IDisposable
{
private Pipeline pipeline;
private Element filesrc;
private Element filesink;
private FileSrc filesrc;
private FileSink filesink;
private Element audioconvert;
private Element encoder;
private DecodeBin decodebin;
@ -47,8 +48,8 @@ public class DecodeBinTranscoder : IDisposable
public void Transcode(string inputFile, string outputFile)
{
filesrc["location"] = inputFile;
filesink["location"] = outputFile;
filesrc.Location = inputFile;
filesink.Location = outputFile;
pipeline.SetState(State.Playing);
progress_timeout = GLib.Timeout.Add(250, OnProgressTimeout);
@ -92,8 +93,8 @@ public class DecodeBinTranscoder : IDisposable
{
pipeline = new Pipeline("pipeline");
filesrc = ElementFactory.Make("filesrc", "filesrc");
filesink = ElementFactory.Make("filesink", "filesink");
filesrc = ElementFactory.Make("filesrc", "filesrc") as FileSrc;
filesink = ElementFactory.Make("filesink", "filesink") as FileSink;
audioconvert = ElementFactory.Make("audioconvert", "audioconvert");
encoder = ElementFactory.Make("wavenc", "wavenc");
decodebin = ElementFactory.Make("decodebin", "decodebin") as DecodeBin;

View file

@ -1,12 +1,8 @@
using System;
using GLib;
using Gst;
using Gst.BasePlugins;
public class PlayBinPlayer
{
private static MainLoop loop;

View file

@ -11,11 +11,11 @@ public static class GstTypefindTest
Application.Init();
Pipeline pipeline = new Pipeline("pipeline");
Element source = ElementFactory.Make("filesrc", "source");
FileSrc source = FileSrc.Make("source");
typefind = TypeFindElement.Make("typefind");
Element sink = ElementFactory.Make("fakesink", "sink");
FakeSink sink = FakeSink.Make("sink");
source["location"] = args[0];
source.Location = args[0];
typefind.HaveType += OnHaveType;
@ -26,16 +26,12 @@ public static class GstTypefindTest
pipeline.SetState(State.Paused);
pipeline.SetState(State.Null);
source.Dispose();
typefind.Dispose();
sink.Dispose();
pipeline.Dispose();
}
private static void OnHaveType(object o, GLib.SignalArgs args)
private static void OnHaveType(object o, TypeFindElement.HaveTypeArgs args)
{
Caps caps = args.Args[1] as Caps;
Console.WriteLine("MimeType: {0}", caps);
Console.WriteLine("MimeType: {0}", args.Caps);
}
}