forked from pythonnet/pythonnet
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEventHandlerCollection.cs
More file actions
124 lines (107 loc) · 3.69 KB
/
EventHandlerCollection.cs
File metadata and controls
124 lines (107 loc) · 3.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using System.Security.Permissions;
namespace Python.Runtime;
[Serializable]
internal class EventHandlerCollection: Dictionary<object, List<Handler>>
{
readonly EventInfo info;
public EventHandlerCollection(EventInfo @event)
{
info = @event;
}
/// <summary>
/// Register a new Python object event handler with the event.
/// </summary>
internal bool AddEventHandler(BorrowedReference target, PyObject handler)
{
object? obj = null;
if (target != null)
{
var co = (CLRObject)ManagedType.GetManagedObject(target)!;
obj = co.inst;
}
// Create a true delegate instance of the appropriate type to
// wrap the Python handler. Note that wrapper delegate creation
// always succeeds, though calling the wrapper may fail.
Type type = info.EventHandlerType;
Delegate d = PythonEngine.DelegateManager.GetDelegate(type, handler);
// Now register the handler in a mapping from instance to pairs
// of (handler hash, delegate) so we can lookup to remove later.
object key = obj ?? info.ReflectedType;
if (!TryGetValue(key, out var list))
{
list = new List<Handler>();
this[key] = list;
}
list.Add(new Handler(Runtime.PyObject_Hash(handler), d));
// Note that AddEventHandler helper only works for public events,
// so we have to get the underlying add method explicitly.
object[] args = { d };
MethodInfo mi = info.GetAddMethod(true);
mi.Invoke(obj, BindingFlags.Default, null, args, null);
return true;
}
/// <summary>
/// Remove the given Python object event handler.
/// </summary>
internal bool RemoveEventHandler(BorrowedReference target, BorrowedReference handler)
{
object? obj = null;
if (target != null)
{
var co = (CLRObject)ManagedType.GetManagedObject(target)!;
obj = co.inst;
}
nint hash = Runtime.PyObject_Hash(handler);
if (hash == -1 && Exceptions.ErrorOccurred())
{
return false;
}
object key = obj ?? info.ReflectedType;
if (!TryGetValue(key, out var list))
{
Exceptions.SetError(Exceptions.ValueError, "unknown event handler");
return false;
}
object?[] args = { null };
MethodInfo mi = info.GetRemoveMethod(true);
for (var i = 0; i < list.Count; i++)
{
var item = (Handler)list[i];
if (item.hash != hash)
{
continue;
}
args[0] = item.del;
try
{
mi.Invoke(obj, BindingFlags.Default, null, args, null);
}
catch
{
continue;
}
list.RemoveAt(i);
return true;
}
Exceptions.SetError(Exceptions.ValueError, "unknown event handler");
return false;
}
#region Serializable
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
protected EventHandlerCollection(SerializationInfo info, StreamingContext context)
: base(info, context)
{
this.info = (EventInfo)info.GetValue("event", typeof(EventInfo));
}
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("event", this.info);
}
#endregion
}