1 /*
2 * Copyright (c) 2009 Mat Sutcliffe (oktal@gmx.co.uk)
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23 * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "EXTERN.h"
27 #include "perl.h"
28 #include "XSUB.h"
29
30 #include <agar/core.h>
31 #include <agar/gui.h>
32 #include "perl_agar.h"
33
34 /* How many event args belong to perl? */
35 static const int apNumOurArgs = 1;
36
37 /* Store a coderef with an event handler and increment its reference count. */
AP_StoreEventPV(AG_Event * event,SV * pv)38 void AP_StoreEventPV(AG_Event *event, SV *pv)
39 {
40 if (event != NULL) {
41 AG_EventPushPointer(event, "perl.pv", pv);
42 SvREFCNT_inc(pv);
43 }
44 }
45
46 /* An event handler routine that calls the coderef stored in its argv[1]. */
AP_EventHandler(AG_Event * event)47 void AP_EventHandler(AG_Event *event)
48 {
49 dSP;
50 SV *pv = AP_RetrieveEventPV(event);
51 if (pv == NULL) { return; }
52
53 ENTER;
54 SAVETMPS;
55
56 PUSHMARK(SP);
57 XPUSHs(sv_setref_iv(sv_newmortal(), "Agar::Event", PTR2IV(event)));
58 PUTBACK;
59
60 call_sv(pv, G_VOID);
61
62 FREETMPS;
63 LEAVE;
64 }
65
66 /* A variant of the above that decrements the reference count of the coderef. */
AP_EventHandlerDecRef(AG_Event * event)67 void AP_EventHandlerDecRef(AG_Event *event)
68 {
69 AP_EventHandler(event);
70 AP_DecRefEventPV(event);
71 }
72
73 /* Safely retrieves a coderef stored in an event handler. */
AP_RetrieveEventPV(AG_Event * event)74 SV * AP_RetrieveEventPV(AG_Event *event)
75 {
76 if (event == NULL) { return NULL; }
77 if (event->handler == AP_EventHandler ||
78 event->handler == AP_EventHandlerDecRef) {
79 return AG_PTR(1);
80 }
81 return NULL;
82 }
83
84 /* Safely decrements the reference count of an event handler coderef. */
AP_DecRefEventPV(AG_Event * event)85 void AP_DecRefEventPV(AG_Event *event)
86 {
87 SV *pv = AP_RetrieveEventPV(event);
88 if (pv != NULL) {
89 SvREFCNT_dec(pv);
90 }
91 }
92
93 MODULE = Agar::Event PACKAGE = Agar::Event PREFIX = AG_
94 PROTOTYPES: ENABLE
95 VERSIONCHECK: DISABLE
96
97 const char *
98 name(event)
99 Agar::Event event
100 CODE:
101 RETVAL = event->name;
102 OUTPUT:
103 RETVAL
104
105 Agar::Object
106 receiver(event)
107 Agar::Event event
108 CODE:
109 RETVAL = AG_SELF();
110 OUTPUT:
111 RETVAL
112
113 Agar::Object
114 sender(event)
115 Agar::Event event
116 CODE:
117 if ((RETVAL = AG_SENDER()) == NULL) {
118 XSRETURN_UNDEF;
119 }
120 OUTPUT:
121 RETVAL
122
123 IV
124 ptr(event, index)
125 Agar::Event event
126 int index
127 PREINIT:
128 static const enum ag_variable_type argtype = AG_VARIABLE_POINTER;
129 CODE:
130 index += apNumOurArgs;
131 if (index <= apNumOurArgs || index >= event->argc ||
132 event->argv[index].type != argtype) {
133 XSRETURN_UNDEF;
134 }
135 RETVAL = PTR2IV(AG_PTR(index));
136 OUTPUT:
137 RETVAL
138
139 IV
140 ptrNamed(event, name)
141 Agar::Event event
142 const char *name
143 PREINIT:
144 static const enum ag_variable_type argtype = AG_VARIABLE_POINTER;
145 CODE:
146 RETVAL = PTR2IV(AG_PTR_NAMED(name));
147 OUTPUT:
148 RETVAL
149
150 Agar::Object
151 object(event, index, classSpec)
152 Agar::Event event
153 int index
154 const char * classSpec
155 PREINIT:
156 static const enum ag_variable_type argtype = AG_VARIABLE_POINTER;
157 CODE:
158 index += apNumOurArgs;
159 if (index <= apNumOurArgs || index >= event->argc ||
160 event->argv[index].type != argtype) {
161 XSRETURN_UNDEF;
162 }
163 RETVAL = AG_OBJECT(index, classSpec);
164 OUTPUT:
165 RETVAL
166
167 SV *
168 string(event, index)
169 Agar::Event event
170 int index
171 PREINIT:
172 static const enum ag_variable_type argtype = AG_VARIABLE_STRING;
173 CODE:
174 index += apNumOurArgs;
175 if (index <= apNumOurArgs || index >= event->argc ||
176 event->argv[index].type != argtype) {
177 XSRETURN_UNDEF;
178 }
179 RETVAL = newSVpv(AG_STRING(index), 0);
180 OUTPUT:
181 RETVAL
182
183 int
184 int(event, index)
185 Agar::Event event
186 int index
187 PREINIT:
188 static const enum ag_variable_type argtype = AG_VARIABLE_INT;
189 CODE:
190 index += apNumOurArgs;
191 if (index <= apNumOurArgs || index >= event->argc ||
192 event->argv[index].type != argtype) {
193 XSRETURN_UNDEF;
194 }
195 RETVAL = AG_INT(index);
196 OUTPUT:
197 RETVAL
198
199 Uint
200 Uint(event, index)
201 Agar::Event event
202 int index
203 PREINIT:
204 static const enum ag_variable_type argtype = AG_VARIABLE_UINT;
205 CODE:
206 index += apNumOurArgs;
207 if (index <= apNumOurArgs || index >= event->argc ||
208 event->argv[index].type != argtype) {
209 XSRETURN_UNDEF;
210 }
211 RETVAL = AG_UINT(index);
212 OUTPUT:
213 RETVAL
214
215 long
216 long(event, index)
217 Agar::Event event
218 int index
219 PREINIT:
220 static const enum ag_variable_type argtype = AG_VARIABLE_SINT32;
221 CODE:
222 index += apNumOurArgs;
223 if (index <= apNumOurArgs || index >= event->argc ||
224 event->argv[index].type != argtype) {
225 XSRETURN_UNDEF;
226 }
227 RETVAL = AG_LONG(index);
228 OUTPUT:
229 RETVAL
230
231 Ulong
232 Ulong(event, index)
233 Agar::Event event
234 int index
235 PREINIT:
236 static const enum ag_variable_type argtype = AG_VARIABLE_UINT32;
237 CODE:
238 index += apNumOurArgs;
239 if (index <= apNumOurArgs || index >= event->argc ||
240 event->argv[index].type != argtype) {
241 XSRETURN_UNDEF;
242 }
243 RETVAL = AG_ULONG(index);
244 OUTPUT:
245 RETVAL
246
247 float
248 float(event, index)
249 Agar::Event event
250 int index
251 PREINIT:
252 static const enum ag_variable_type argtype = AG_VARIABLE_FLOAT;
253 CODE:
254 index += apNumOurArgs;
255 if (index <= apNumOurArgs || index >= event->argc ||
256 event->argv[index].type != argtype) {
257 XSRETURN_UNDEF;
258 }
259 RETVAL = AG_FLOAT(index);
260 OUTPUT:
261 RETVAL
262
263 double
264 double(event, index)
265 Agar::Event event
266 int index
267 PREINIT:
268 static const enum ag_variable_type argtype = AG_VARIABLE_DOUBLE;
269 CODE:
270 index += apNumOurArgs;
271 if (index <= apNumOurArgs || index >= event->argc ||
272 event->argv[index].type != argtype) {
273 XSRETURN_UNDEF;
274 }
275 RETVAL = AG_DOUBLE(index);
276 OUTPUT:
277 RETVAL
278
279