// GLib.Signals.Simple.cs - GLib Simple Signal implementation // // Authors: Bob Smith // Mike Kestner // // (c) 2001 Bob Smith & Mike Kestner namespace GLib { using System; using System.Collections; using System.Runtime.InteropServices; using GLib; /// /// SimpleDelegate Delegate /// /// /// /// Used to connect to simple signals which contain no signal- /// specific data. /// public delegate void SimpleDelegate (IntPtr obj, int key); /// /// SimpleSignal Class /// /// /// /// Wraps a simple signal which contains no single-specific data. /// public class SimpleSignal { // A counter used to produce unique keys for instances. private static int _NextKey = 0; // Hashtable containing refs to all current instances. private static Hashtable _Instances = new Hashtable (); // locals to create and pin the shared delegate. private static SimpleDelegate _Delegate; private static GCHandle _GCHandle; // Shared delegate that relays events to registered handlers. private static void SimpleCallback(IntPtr obj, int inst_key) { if (!_Instances.Contains (inst_key)) throw new Exception ("Unexpected signal key"); SimpleSignal ss = (SimpleSignal) _Instances [inst_key]; EventArgs args = new EventArgs (); ss._handler (ss._obj, args); } // private instance members private GLib.Object _obj; private EventHandler _handler; private int _key; /// /// SimpleSignal Constructor /// /// /// /// Registers a new event handler for a specified signal. /// A connection to the raw object signal is made which /// causes any events which occur to be relayed to the /// event handler. /// [DllImport ("gobject-1.3.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] static extern void g_signal_connect_data ( IntPtr obj, IntPtr name, SimpleDelegate cb, int key, IntPtr p, int flags); public SimpleSignal (GLib.Object obj, IntPtr raw, String name, EventHandler eh) { if (_Delegate == null) { _Delegate = new SimpleDelegate(SimpleCallback); /* FIXME: need layout attribute for * SimpleCallback to avoid an exception. * _GCHandle = GCHandle.Alloc ( * _Delegate, GCHandleType.Pinned); */ } _key = _NextKey++; _obj = obj; _handler = eh; _Instances [_key] = this; g_signal_connect_data ( raw, Marshal.StringToHGlobalAnsi (name), _Delegate, _key, new IntPtr (0), 0); } // Destructor needed to release references from the instance // table and unpin the delegate if no refs remain. ~SimpleSignal () { _Instances.Remove (_key); if (_Instances.Count == 0) { // FIXME: when pin works _GCHandle.Free(); _Delegate = null; } } } }