1/*
2 * Manual wrappers for CoreGraphics
3 */
4#include <Python.h>
5#include "pyobjc-api.h"
6
7#import <ApplicationServices/ApplicationServices.h>
8
9#ifndef OS_TIGER
10static PyObject*
11m_CGFontCopyTableTags(PyObject* self __attribute__((__unused__)),
12		PyObject* args)
13{
14	PyObject* py_font;
15	CGFontRef font;
16	CFArrayRef tags;
17
18	if (!PyArg_ParseTuple(args, "O", &py_font)) {
19		return NULL;
20	}
21
22	if (PyObjC_PythonToObjC(@encode(CGFontRef), py_font, &font) == -1) {
23		return NULL;
24	}
25
26	tags = NULL;
27	PyObjC_DURING
28		tags = CGFontCopyTableTags(font);
29
30	PyObjC_HANDLER
31		tags = NULL;
32		PyObjCErr_FromObjC(localException);
33	PyObjC_ENDHANDLER
34
35	if (tags == NULL && PyErr_Occurred()) {
36		return NULL;
37	}
38
39	if (tags == NULL)  {
40		Py_INCREF(Py_None);
41		return Py_None;
42	}
43
44	Py_ssize_t len = CFArrayGetCount(tags);
45	Py_ssize_t i;
46	PyObject* result = PyTuple_New(len);
47	if (result == NULL) {
48		CFRelease(tags);
49		return NULL;
50	}
51
52	for (i = 0; i < len; i++) {
53		uint32_t cur = (uint32_t)(uintptr_t)CFArrayGetValueAtIndex(tags, i);
54		PyObject* v = PyObjC_ObjCToPython(@encode(uint32_t), &cur);
55		if (v == NULL) {
56			CFRelease(tags);
57			return NULL;
58		}
59		PyTuple_SET_ITEM(result, i, v);
60	}
61	CFRelease(tags);
62	return result;
63}
64
65static PyObject*
66m_CGWindowListCreate(PyObject* self __attribute__((__unused__)),
67		PyObject* args)
68{
69	PyObject* py_option;
70	PyObject* py_relativeToWindow;
71	CGWindowListOption option;
72	CGWindowID relativeToWindow;
73	CFArrayRef windowList;
74
75	if (!PyArg_ParseTuple(args, "OO", &py_option, &py_relativeToWindow)) {
76		return NULL;
77	}
78
79	if (PyObjC_PythonToObjC(@encode(CGWindowListOption), py_option, &option) == -1) {
80		return NULL;
81	}
82
83	if (PyObjC_PythonToObjC(@encode(CGWindowID), py_relativeToWindow, &relativeToWindow) == -1) {
84		return NULL;
85	}
86
87	windowList = NULL;
88	PyObjC_DURING
89		windowList = CGWindowListCreate(option, relativeToWindow);
90
91	PyObjC_HANDLER
92		windowList = NULL;
93		PyObjCErr_FromObjC(localException);
94	PyObjC_ENDHANDLER
95
96	if (windowList == NULL && PyErr_Occurred()) {
97		return NULL;
98	}
99
100	if (windowList == NULL)  {
101		Py_INCREF(Py_None);
102		return Py_None;
103	}
104
105	Py_ssize_t len = CFArrayGetCount(windowList);
106	Py_ssize_t i;
107	PyObject* result = PyTuple_New(len);
108	if (result == NULL) {
109		CFRelease(windowList);
110		return NULL;
111	}
112
113	for (i = 0; i < len; i++) {
114		CGWindowID cur = (CGWindowID)CFArrayGetValueAtIndex(windowList, i);
115		PyObject* v = PyObjC_ObjCToPython(@encode(CGWindowID), &cur);
116		if (v == NULL) {
117			CFRelease(windowList);
118			return NULL;
119		}
120		PyTuple_SET_ITEM(result, i, v);
121	}
122	CFRelease(windowList);
123	return result;
124}
125
126
127
128static CFArrayRef
129createWindowList(PyObject* items)
130{
131	PyObject* seq = PySequence_Fast(items, "list of windowIDs");
132	if (seq == NULL) {
133		return NULL;
134	}
135
136	CFMutableArrayRef array = CFArrayCreateMutable(NULL, PySequence_Fast_GET_SIZE(seq), NULL);
137	if (array == NULL) {
138		Py_DECREF(seq);
139		PyErr_SetString(PyExc_ValueError, "Cannot create CFArray");
140		return NULL;
141	}
142
143	Py_ssize_t len = PySequence_Fast_GET_SIZE(seq);
144	Py_ssize_t i;
145	for (i = 0; i < len; i++) {
146		CGWindowID windowID;
147
148		if (PyObjC_PythonToObjC(@encode(CGWindowID), PySequence_Fast_GET_ITEM(seq, i), &windowID) == -1) {
149			Py_DECREF(seq);
150			CFRelease(array);
151			return NULL;
152		}
153		CFArrayAppendValue(array, (const void*)windowID);
154	}
155	Py_DECREF(seq);
156	return (CFArrayRef)array;
157}
158
159static PyObject*
160m_CGWindowListCreateDescriptionFromArray(PyObject* self __attribute__((__unused__)),
161		PyObject* args)
162{
163	PyObject* py_windowArray;
164	CFArrayRef windowArray;
165
166	if (!PyArg_ParseTuple(args, "O", &py_windowArray)) {
167		return NULL;
168	}
169
170	windowArray = createWindowList(py_windowArray);
171	if (windowArray == NULL) {
172		return NULL;
173	}
174
175	CFArrayRef descriptions = NULL;
176	PyObjC_DURING
177		descriptions = CGWindowListCreateDescriptionFromArray(windowArray);
178
179	PyObjC_HANDLER
180		descriptions = NULL;
181		PyObjCErr_FromObjC(localException);
182	PyObjC_ENDHANDLER
183
184	CFRelease(windowArray);
185
186	if (descriptions == NULL && PyErr_Occurred()) {
187		return NULL;
188	}
189
190	if (descriptions == NULL)  {
191		Py_INCREF(Py_None);
192		return Py_None;
193	}
194
195	PyObject* rv = PyObjC_ObjCToPython(@encode(CFArrayRef), &descriptions);
196	CFRelease(descriptions);
197	return rv;
198}
199
200static PyObject*
201m_CGWindowListCreateImageFromArray(PyObject* self __attribute__((__unused__)),
202		PyObject* args)
203{
204	PyObject* py_screenBounds;
205	PyObject* py_windowArray;
206	PyObject* py_imageOption;
207	CGRect screenBounds;
208	CFArrayRef windowArray;
209	CGWindowImageOption imageOption;
210
211	if (!PyArg_ParseTuple(args, "OOO", &py_screenBounds, &py_windowArray, &py_imageOption)) {
212		return NULL;
213	}
214
215	if (PyObjC_PythonToObjC(@encode(CGRect), py_screenBounds, &screenBounds) == -1) {
216		return NULL;
217	}
218
219	if (PyObjC_PythonToObjC(@encode(CGWindowImageOption), py_imageOption, &imageOption) == -1) {
220		return NULL;
221	}
222
223
224	windowArray = createWindowList(py_windowArray);
225	if (windowArray == NULL) {
226		return NULL;
227	}
228
229	CGImageRef image = NULL;
230	PyObjC_DURING
231		image = CGWindowListCreateImageFromArray(screenBounds, windowArray, imageOption);
232
233	PyObjC_HANDLER
234		image = NULL;
235		PyObjCErr_FromObjC(localException);
236	PyObjC_ENDHANDLER
237
238	CFRelease(windowArray);
239
240	if (image == NULL && PyErr_Occurred()) {
241		return NULL;
242	}
243
244	if (image == NULL)  {
245		Py_INCREF(Py_None);
246		return Py_None;
247	}
248
249	PyObject* rv = PyObjC_ObjCToPython(@encode(CGImageRef), &image);
250	CFRelease(image);
251	return rv;
252}
253#endif /* !OS_TIGER */
254
255static PyObject*
256m_CGBitmapContextCreate(PyObject* self __attribute__((__unused__)),
257		PyObject* args)
258{
259	PyObject* py_data;
260	PyObject* py_width;
261	PyObject* py_height;
262	PyObject* py_bitsPerComponent;
263	PyObject* py_bytesPerRow;
264	PyObject* py_colorSpace;
265	PyObject* py_bitmapInfo;
266
267	void*	data;
268	size_t  width;
269	size_t  height;
270	size_t  bitsPerComponent;
271	size_t  bytesPerRow;
272	CGColorSpaceRef colorSpace;
273	CGBitmapInfo bitmapInfo;
274
275	if (!PyArg_ParseTuple(args, "OOOOOOO", &py_data, &py_width, &py_height, &py_bitsPerComponent, &py_bytesPerRow, &py_colorSpace, &py_bitmapInfo)) {
276		return NULL;
277	}
278
279	if (PyObjC_PythonToObjC(@encode(size_t), py_width, &width) == -1) {
280		return NULL;
281	}
282	if (PyObjC_PythonToObjC(@encode(size_t), py_height, &height) == -1) {
283		return NULL;
284	}
285	if (PyObjC_PythonToObjC(@encode(size_t), py_bitsPerComponent, &bitsPerComponent) == -1) {
286		return NULL;
287	}
288	if (PyObjC_PythonToObjC(@encode(size_t), py_bytesPerRow, &bytesPerRow) == -1) {
289		return NULL;
290	}
291	if (PyObjC_PythonToObjC(@encode(CGColorSpaceRef), py_colorSpace, &colorSpace) == -1) {
292		return NULL;
293	}
294	if (PyObjC_PythonToObjC(@encode(CGBitmapInfo), py_bitmapInfo, &bitmapInfo) == -1) {
295		return NULL;
296	}
297
298	if (py_data == Py_None) {
299		data = NULL;
300
301	} else if (PyUnicode_Check(py_data)) {
302		PyErr_SetString(PyExc_TypeError, "Cannot use Unicode as backing store");
303		return NULL;
304
305	} else {
306		Py_ssize_t size;
307
308		if (PyObject_AsWriteBuffer(py_data, &data, &size) == -1) {
309			return NULL;
310		}
311	}
312
313
314	CGContextRef ctx = NULL;
315	PyObjC_DURING
316		ctx = CGBitmapContextCreate(data, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo);
317
318	PyObjC_HANDLER
319		ctx = NULL;
320		PyObjCErr_FromObjC(localException);
321	PyObjC_ENDHANDLER
322
323	if (ctx == NULL && PyErr_Occurred()) {
324		return NULL;
325	}
326
327	if (ctx == NULL)  {
328		Py_INCREF(Py_None);
329		return Py_None;
330	}
331
332	PyObject* rv = PyObjC_ObjCToPython(@encode(CGContextRef), &ctx);
333	CFRelease(ctx);
334	return rv;
335}
336
337
338static PyMethodDef m_methods[] = {
339#ifndef OS_TIGER
340	{
341		"CGFontCopyTableTags",
342		(PyCFunction)m_CGFontCopyTableTags,
343		METH_VARARGS,
344		NULL
345	},
346	{
347		"CGWindowListCreate",
348		(PyCFunction)m_CGWindowListCreate,
349		METH_VARARGS,
350		NULL
351	},
352	{
353		"CGWindowListCreateDescriptionFromArray",
354		(PyCFunction)m_CGWindowListCreateDescriptionFromArray,
355		METH_VARARGS,
356		NULL
357	},
358	{
359		"CGWindowListCreateImageFromArray",
360		(PyCFunction)m_CGWindowListCreateImageFromArray,
361		METH_VARARGS,
362		NULL
363	},
364#endif /* !OS_TIGER */
365	{
366		"CGBitmapContextCreate",
367		(PyCFunction)m_CGBitmapContextCreate,
368		METH_VARARGS,
369		NULL
370	},
371
372
373	{ 0, 0, 0, }
374};
375
376void init_coregraphics(void);
377void init_coregraphics(void)
378{
379	PyObject* m = Py_InitModule4("_coregraphics", m_methods,
380		NULL, NULL, PYTHON_API_VERSION);
381
382        if (PyObjC_ImportAPI(m) < 0) { return; }
383}
384