gstreamer/gstreamer-sharp/DynamicSignal.cs

152 lines
5.6 KiB
C#
Raw Normal View History

//
// DynamicSignal.cs: C# bindings to g_dynamic_signal to provide
// dynamic runtime signal binding for GObject
//
// Authors:
// Aaron Bockover (abockover@novell.com)
//
// (C) 2006 Novell, Inc.
//
using System;
using System.Runtime.InteropServices;
namespace GLib
{
public delegate void DynamicSignalHandler(object o, DynamicSignalArgs args);
public class DynamicSignalArgs : EventArgs
{
private GLib.Object sender;
private object [] args;
internal DynamicSignalArgs(GLib.Object sender, object [] args)
{
this.sender = sender;
this.args = args;
}
public object this[int index] {
get { return Args[index]; }
}
public GLib.Object Sender {
get { return sender; }
}
public object [] Args {
get { return args; }
}
}
public static class DynamicSignal
{
private delegate void DynamicSignalNativeHandler(IntPtr objectPtr, uint argc,
IntPtr argsPtr, IntPtr userdata);
private static DynamicSignalNativeHandler dynamic_signal_handler =
new DynamicSignalNativeHandler(OnDynamicSignalRaised);
private static readonly int gvalue_struct_size = Marshal.SizeOf(typeof(GLib.Value));
public static void Connect(GLib.Object o, string name, DynamicSignalHandler handler)
{
Connect(o, name, false, handler);
}
public static void Connect(GLib.Object o, string name, bool after,
DynamicSignalHandler handler)
{
IntPtr entry_ptr = FindRegisteredEntry(o, name);
if(entry_ptr == IntPtr.Zero) {
g_dynamic_signal_connect(o.Handle, name, dynamic_signal_handler,
after, (IntPtr)GCHandle.Alloc(handler));
return;
}
Delegate registered_handler = GetEntryHandler(entry_ptr);
if(registered_handler != null) {
Delegate new_handler = Delegate.Combine(registered_handler, handler);
if(new_handler != registered_handler) {
g_dynamic_signal_update_entry_userdata(entry_ptr,
(IntPtr)GCHandle.Alloc(new_handler));
}
}
}
public static void Disconnect(GLib.Object o, string name, DynamicSignalHandler handler)
{
IntPtr entry_ptr = FindRegisteredEntry(o, name);
if(entry_ptr == IntPtr.Zero) {
return;
}
Delegate registered_handler = GetEntryHandler(entry_ptr);
Delegate new_handler = Delegate.Remove(registered_handler, handler);
if(new_handler == null || handler == null) {
g_dynamic_signal_disconnect(o.Handle, name);
return;
} else if(new_handler != null && registered_handler != new_handler) {
g_dynamic_signal_update_entry_userdata(entry_ptr,
(IntPtr)GCHandle.Alloc(new_handler));
}
}
private static IntPtr FindRegisteredEntry(GLib.Object o, string name)
{
return g_dynamic_signal_find_registration(o.Handle, name);
}
private static DynamicSignalHandler GetEntryHandler(IntPtr entryPtr)
{
IntPtr handler_ptr = Marshal.ReadIntPtr(entryPtr, Marshal.SizeOf(typeof(IntPtr)));
return (DynamicSignalHandler)((GCHandle)handler_ptr).Target;
}
private static void OnDynamicSignalRaised(IntPtr objectPtr, uint argc,
IntPtr argsPtr, IntPtr userdata)
{
GLib.Object gobject = GLib.Object.GetObject(objectPtr, false);
object [] args = new object[argc];
for(int i = 0; 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));
Type type = GType.LookupType(g_value_type(struct_ptr));
if(type.IsSubclassOf(typeof(GLib.Opaque))) {
args[i] = GLib.Opaque.GetOpaque(g_value_peek_pointer(struct_ptr), type, true);
} else {
args[i] = argument.Val;
}
}
DynamicSignalHandler handler = (DynamicSignalHandler)((GCHandle)userdata).Target;
if(handler != null) {
handler(gobject, new DynamicSignalArgs(gobject, args));
}
}
[DllImport("gstreamersharpglue-0.10")]
private static extern uint g_dynamic_signal_connect(IntPtr o, string name,
DynamicSignalNativeHandler callback, bool swapped, IntPtr userdata);
[DllImport("gstreamersharpglue-0.10")]
private static extern void g_dynamic_signal_disconnect(IntPtr o, string name);
[DllImport("gstreamersharpglue-0.10")]
private static extern IntPtr g_dynamic_signal_find_registration(IntPtr o, string name);
[DllImport("gstreamersharpglue-0.10")]
private static extern void g_dynamic_signal_update_entry_userdata(IntPtr entry, IntPtr userdata);
[DllImport("gstreamersharpglue-0.10")]
private static extern IntPtr g_value_type(IntPtr value);
[DllImport("libgobject-2.0-0.dll")]
private static extern IntPtr g_value_peek_pointer(IntPtr value);
}
}