1 // SignalClosure.cs - signal marshaling class 2 // 3 // Authors: Mike Kestner <mkestner@novell.com> 4 // 5 // Copyright (c) 2008 Novell, Inc. 6 // 7 // This program is free software; you can redistribute it and/or 8 // modify it under the terms of version 2 of the Lesser GNU General 9 // Public License as published by the Free Software Foundation. 10 // 11 // This program is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 // Lesser General Public License for more details. 15 // 16 // You should have received a copy of the GNU Lesser General Public 17 // License along with this program; if not, write to the 18 // Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 // Boston, MA 02111-1307, USA. 20 21 22 namespace GLib { 23 24 using System; 25 using System.Collections; 26 using System.Collections.Generic; 27 using System.Runtime.InteropServices; 28 29 internal class ClosureInvokedArgs : EventArgs { 30 31 EventArgs args; 32 GLib.Object obj; 33 object result; 34 ClosureInvokedArgs(GLib.Object obj, EventArgs args)35 public ClosureInvokedArgs (GLib.Object obj, EventArgs args) 36 { 37 this.obj = obj; 38 this.args = args; 39 } 40 41 public EventArgs Args { 42 get { 43 return args; 44 } 45 } 46 47 public GLib.Object Target { 48 get { 49 return obj; 50 } 51 } 52 } 53 ClosureInvokedHandler(object o, ClosureInvokedArgs args)54 internal delegate void ClosureInvokedHandler (object o, ClosureInvokedArgs args); 55 56 public partial class Signal 57 { 58 class SignalClosure : IDisposable 59 { 60 internal Signal signal; 61 IntPtr raw_closure; 62 uint id = UInt32.MaxValue; 63 GCHandle? gch; 64 65 static Dictionary<IntPtr, SignalClosure> closures = new Dictionary<IntPtr, SignalClosure> (IntPtrEqualityComparer.Instance); 66 SignalClosure(Signal sig, System.Type args_type)67 public SignalClosure (Signal sig, System.Type args_type) 68 { 69 raw_closure = glibsharp_closure_new (Marshaler, Notify, IntPtr.Zero); 70 closures [raw_closure] = this; 71 signal = sig; 72 } 73 SignalClosure(Signal sig, Delegate custom_marshaler)74 public SignalClosure (Signal sig, Delegate custom_marshaler) 75 { 76 gch = GCHandle.Alloc (sig); 77 raw_closure = g_cclosure_new (custom_marshaler, (IntPtr)gch, Notify); 78 closures [raw_closure] = this; 79 signal = sig; 80 } 81 82 public event EventHandler Disposed; 83 public event ClosureInvokedHandler Invoked; 84 Connect(bool is_after)85 public void Connect (bool is_after) 86 { 87 IntPtr native_name = GLib.Marshaller.StringToPtrGStrdup (signal.name); 88 id = g_signal_connect_closure (signal.tref.Handle, native_name, raw_closure, is_after); 89 GLib.Marshaller.Free (native_name); 90 } 91 Disconnect()92 public void Disconnect () 93 { 94 if (id != UInt32.MaxValue && g_signal_handler_is_connected (signal.tref.Handle, id)) 95 g_signal_handler_disconnect (signal.tref.Handle, id); 96 } 97 Dispose()98 public void Dispose () 99 { 100 Disconnect (); 101 closures.Remove (raw_closure); 102 if (gch != null) { 103 gch.Value.Free (); 104 gch = null; 105 } 106 if (Disposed != null) 107 Disposed (this, EventArgs.Empty); 108 GC.SuppressFinalize (this); 109 } 110 Invoke(ClosureInvokedArgs args)111 public void Invoke (ClosureInvokedArgs args) 112 { 113 if (Invoked == null) 114 return; 115 Invoked (this, args); 116 } 117 118 static ClosureMarshal marshaler; 119 static ClosureMarshal Marshaler { 120 get { 121 if (marshaler == null) { 122 unsafe 123 { 124 marshaler = new ClosureMarshal (MarshalCallback); 125 } 126 } 127 return marshaler; 128 } 129 } 130 131 [UnmanagedFunctionPointer (CallingConvention.Cdecl)] ClosureMarshal(IntPtr closure, Value* return_val, uint n_param_vals, Value* param_values, IntPtr invocation_hint, IntPtr marshal_data)132 unsafe delegate void ClosureMarshal (IntPtr closure, Value* return_val, uint n_param_vals, Value* param_values, IntPtr invocation_hint, IntPtr marshal_data); 133 MarshalCallback(IntPtr raw_closure, Value* return_val, uint n_param_vals, Value* param_values, IntPtr invocation_hint, IntPtr marshal_data)134 unsafe static void MarshalCallback (IntPtr raw_closure, Value* return_val, uint n_param_vals, Value* param_values, IntPtr invocation_hint, IntPtr marshal_data) 135 { 136 SignalClosure closure = null; 137 try { 138 closure = closures [raw_closure] as SignalClosure; 139 GLib.Object __obj = param_values [0].Val as GLib.Object; 140 if (__obj == null) 141 return; 142 143 if (closure.signal.args_type == typeof (EventArgs)) { 144 closure.Invoke (new ClosureInvokedArgs (__obj, EventArgs.Empty)); 145 return; 146 } 147 148 SignalArgs args = FastActivator.CreateSignalArgs (closure.signal.args_type); 149 args.Args = new object [n_param_vals - 1]; 150 for (int i = 1; i < n_param_vals; i++) { 151 args.Args [i - 1] = param_values [i].Val; 152 } 153 ClosureInvokedArgs ci_args = new ClosureInvokedArgs (__obj, args); 154 closure.Invoke (ci_args); 155 for (int i = 1; i < n_param_vals; i++) { 156 param_values [i].Update (args.Args [i - 1]); 157 } 158 if (return_val == null || args.RetVal == null) 159 return; 160 161 return_val->Val = args.RetVal; 162 } catch (Exception e) { 163 if (closure != null) 164 Console.WriteLine ("Marshaling {0} signal", closure.signal.name); 165 ExceptionManager.RaiseUnhandledException (e, false); 166 } 167 } 168 169 [UnmanagedFunctionPointer (CallingConvention.Cdecl)] ClosureNotify(IntPtr data, IntPtr closure)170 delegate void ClosureNotify (IntPtr data, IntPtr closure); 171 NotifyCallback(IntPtr data, IntPtr raw_closure)172 static void NotifyCallback (IntPtr data, IntPtr raw_closure) 173 { 174 SignalClosure closure; 175 if (closures.TryGetValue (raw_closure, out closure)) 176 closure.Dispose (); 177 } 178 179 static ClosureNotify notify_handler; 180 static ClosureNotify Notify { 181 get { 182 if (notify_handler == null) 183 notify_handler = new ClosureNotify (NotifyCallback); 184 return notify_handler; 185 } 186 } 187 188 [DllImport ("glibsharpglue-2", CallingConvention = CallingConvention.Cdecl)] glibsharp_closure_new(ClosureMarshal marshaler, ClosureNotify notify, IntPtr gch)189 static extern IntPtr glibsharp_closure_new (ClosureMarshal marshaler, ClosureNotify notify, IntPtr gch); 190 191 [DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)] g_cclosure_new(Delegate cb, IntPtr user_data, ClosureNotify notify)192 static extern IntPtr g_cclosure_new (Delegate cb, IntPtr user_data, ClosureNotify notify); 193 194 [DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)] g_signal_connect_closure(IntPtr obj, IntPtr name, IntPtr closure, bool is_after)195 static extern uint g_signal_connect_closure (IntPtr obj, IntPtr name, IntPtr closure, bool is_after); 196 197 [DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)] g_signal_handler_disconnect(IntPtr instance, uint handler)198 static extern void g_signal_handler_disconnect (IntPtr instance, uint handler); 199 200 [DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)] g_signal_handler_is_connected(IntPtr instance, uint handler)201 static extern bool g_signal_handler_is_connected (IntPtr instance, uint handler); 202 } 203 } 204 } 205