1/*
2 * Several methods of NSBezierPath cannot be handled automaticly because the
3 * size of a C-style array depends on the value of another argument.
4 */
5#include <Python.h>
6#include "pyobjc-api.h"
7
8#import <AppKit/AppKit.h>
9
10static PyObject*
11call_NSBezierPath_elementAtIndex_associatedPoints_(
12	PyObject* method,
13	PyObject* self, PyObject* arguments)
14{
15	PyObject* result;
16	PyObject* v;
17	struct objc_super super;
18	int    idx;
19	int    pointCount;
20	NSPoint points[3];
21	NSBezierPathElement res;
22
23	if  (!PyArg_ParseTuple(arguments, "i", &idx)) {
24		return NULL;
25	}
26
27	PyObjC_DURING
28		if (PyObjCIMP_Check(method)) {
29			res = ((NSBezierPathElement(*)(id,SEL,int,NSPoint*))
30			   PyObjCIMP_GetIMP(method))(
31			   	PyObjCObject_GetObject(self),
32				PyObjCIMP_GetSelector(method),
33				idx,
34				points
35			   );
36		} else {
37			PyObjC_InitSuper(&super,
38				PyObjCSelector_GetClass(method),
39				PyObjCObject_GetObject(self));
40
41
42			res = (NSBezierPathElement)objc_msgSendSuper(&super,
43				PyObjCSelector_GetSelector(method),
44				idx,
45				points);
46		}
47	PyObjC_HANDLER
48		PyObjCErr_FromObjC(localException);
49	PyObjC_ENDHANDLER
50
51	if (PyErr_Occurred()) {
52		return NULL;
53	}
54
55	switch (res) {
56	case NSMoveToBezierPathElement: pointCount = 1; break;
57	case NSLineToBezierPathElement: pointCount = 1; break;
58	case NSCurveToBezierPathElement: pointCount = 3; break;
59	case NSClosePathBezierPathElement: pointCount = 0; break;
60	default:
61		PyErr_SetString(PyExc_ValueError,
62			"ObjC returned illegal value");
63		return NULL;
64	}
65
66	result = PyTuple_New(2);
67	if (result == NULL) return NULL;
68
69	v = PyObjC_ObjCToPython(@encode(NSBezierPathElement), &res);
70	if (v == NULL) {
71		Py_DECREF(result);
72		return NULL;
73	}
74
75	PyTuple_SET_ITEM(result, 0, v);
76
77	v = PyObjC_CArrayToPython(@encode(NSPoint), points, pointCount);
78	if (v == NULL) {
79		Py_DECREF(result);
80		return NULL;
81	}
82	PyTuple_SET_ITEM(result, 1, v);
83
84	return result;
85}
86
87static PyObject*
88call_NSBezierPath_setAssociatedPoints_atIndex_(
89	PyObject* method,
90	PyObject* self, PyObject* arguments)
91{
92	PyObject* result;
93	struct objc_super super;
94	int    idx;
95	NSPoint points[3];
96	PyObject* pointList;
97	PyObject* seq;
98	int i, len;
99
100	if  (!PyArg_ParseTuple(arguments, "Oi", &pointList, &idx)) {
101		return NULL;
102	}
103
104	memset(points, 0, sizeof(points));
105
106	seq = PySequence_Fast(pointList, "points is not a sequence");
107	if (seq == NULL) {
108		return NULL;
109	}
110
111	len = PySequence_Fast_GET_SIZE(seq);
112	if (len > 3) {
113		Py_DECREF(seq);
114		PyErr_SetString(PyExc_ValueError, "Need at most 3 elements");
115		return NULL;
116	}
117
118	for (i = 0; i < len; i++) {
119		int err = PyObjC_PythonToObjC(@encode(NSPoint),
120			PySequence_Fast_GET_ITEM(seq, i), points + i);
121		if (err == -1) {
122			return NULL;
123		}
124	}
125
126	PyObjC_DURING
127		if (PyObjCIMP_Check(method)) {
128			((void(*)(id,SEL,NSPoint*,int))
129			   PyObjCIMP_GetIMP(method))(
130			   	PyObjCObject_GetObject(self),
131				PyObjCIMP_GetSelector(method),
132				points,
133				idx);
134		} else {
135			PyObjC_InitSuper(&super,
136				PyObjCSelector_GetClass(method),
137				PyObjCObject_GetObject(self));
138
139
140			(void)objc_msgSendSuper(&super,
141				PyObjCSelector_GetSelector(method),
142				points,
143				idx);
144		}
145	PyObjC_HANDLER
146		PyObjCErr_FromObjC(localException);
147		result = NULL;
148	PyObjC_ENDHANDLER
149
150	if (PyErr_Occurred()) return NULL;
151
152	result = Py_None;
153	Py_INCREF(result);
154
155	return result;
156}
157
158static void
159imp_NSBezierPath_elementAtIndex_associatedPoints_(
160	void* cif __attribute__((__unused__)),
161	void* resp,
162	void** args,
163	void* callable)
164{
165	id self = *(id*)args[0];
166	//SEL _meth = *(SEL*)args[1];
167	int idx = *(int*)args[2];
168	NSPoint* points = *(NSPoint**)args[3];
169
170	PyObject* result;
171	PyObject* seq = NULL;
172	PyObject* arglist = NULL;
173	PyObject* v;
174	int err;
175	int pointCount;
176	int i;
177	PyObject* pyself = NULL;
178	int cookie = 0;
179
180	PyGILState_STATE state = PyGILState_Ensure();
181
182	arglist = PyTuple_New(2);
183	if (arglist == NULL) goto error;
184
185	pyself = PyObjCObject_NewTransient(self, &cookie);
186	if (pyself == NULL) goto error;
187	PyTuple_SetItem(arglist, 0, pyself);
188	Py_INCREF(pyself);
189
190	v = PyInt_FromLong(idx);
191	if (v == NULL) goto error;
192	PyTuple_SET_ITEM(arglist, 1, v);
193
194	result = PyObject_Call((PyObject*)callable, arglist, NULL);
195	Py_DECREF(arglist); arglist = NULL;
196	PyObjCObject_ReleaseTransient(pyself, cookie); pyself = NULL;
197	if (result == NULL) goto error;
198
199	seq = PySequence_Fast(result, "should return tuple of lenght 2");
200	Py_DECREF(result);
201	if (seq == NULL) goto error;
202
203	if (PySequence_Fast_GET_SIZE(seq) != 2) {
204		PyErr_SetString(PyExc_ValueError,
205			"should return tuple of lenght 2");
206		goto error;
207	}
208
209	v = PySequence_Fast_GET_ITEM(seq, 0);
210
211	err = PyObjC_PythonToObjC(@encode(NSBezierPathElement), v, resp);
212	if (err == -1) goto error;
213
214	v = PySequence_Fast(PySequence_Fast_GET_ITEM(seq, 1),
215		"result[1] should be a sequence");
216	if (v == NULL) goto error;
217
218	switch (*(NSBezierPathElement*)resp) {
219	case NSMoveToBezierPathElement: pointCount = 1; break;
220	case NSLineToBezierPathElement: pointCount = 1; break;
221	case NSCurveToBezierPathElement: pointCount = 3; break;
222	case NSClosePathBezierPathElement: pointCount = 0; break;
223	default:
224		PyErr_SetString(PyExc_ValueError,
225			"Return[0] should be NS{*}PathElement");
226		Py_DECREF(v);
227		goto error;
228	}
229
230	if (PySequence_Fast_GET_SIZE(v) != pointCount) {
231		PyErr_SetString(PyExc_ValueError,
232			"wrong number of points");
233		Py_DECREF(v);
234		goto error;
235	}
236
237	for (i = 0; i < pointCount; i++) {
238		err = PyObjC_PythonToObjC(@encode(NSPoint),
239			PySequence_Fast_GET_ITEM(v, i),
240			points + i);
241		if (err == -1) {
242			Py_DECREF(v);
243			goto error;
244		}
245	}
246
247	Py_DECREF(v);
248	Py_DECREF(seq);
249	PyGILState_Release(state);
250	return;
251
252error:
253	*(NSBezierPathElement*)resp = 0;
254	Py_XDECREF(arglist);
255	if (pyself) {
256		PyObjCObject_ReleaseTransient(pyself, cookie);
257	}
258	Py_XDECREF(seq);
259	PyObjCErr_ToObjCWithGILState(&state);
260}
261
262
263static PyMethodDef mod_methods[] = {
264	{ 0, 0, 0, 0 } /* sentinel */
265};
266
267void init_nsbezierpath(void);
268void init_nsbezierpath(void)
269{
270	PyObject* m = Py_InitModule4("_nsbezierpath", mod_methods, "", NULL,
271			PYTHON_API_VERSION);
272
273	PyObjC_ImportAPI(m);
274
275	Class cls = objc_lookUpClass("NSBezierPath");
276	if (!cls) return;
277
278	if (PyObjC_RegisterMethodMapping(cls,
279		@selector(elementAtIndex:associatedPoints:),
280		call_NSBezierPath_elementAtIndex_associatedPoints_,
281		imp_NSBezierPath_elementAtIndex_associatedPoints_) < 0 ) {
282
283		return;
284	}
285
286	if (PyObjC_RegisterMethodMapping(cls,
287		@selector(setAssociatedPoints:atIndex:),
288		call_NSBezierPath_setAssociatedPoints_atIndex_,
289		PyObjCUnsupportedMethod_IMP) < 0 ) {
290
291		return;
292	}
293
294	return;
295}
296