1/*
2 * Functions that return arrays by indirection, something that cannot be
3 * described by the metadata.
4 */
5#include <Python.h>
6#include "pyobjc-api.h"
7
8#import <ApplicationServices/ApplicationServices.h>
9
10static PyObject*
11m_CGWaitForScreenRefreshRects(PyObject* self __attribute__((__unused__)),
12		PyObject* args)
13{
14	CGRect* rectArray = NULL;
15	CGRectCount count = 0;
16	CGError err;
17
18	if (PyTuple_GET_SIZE(args) == 2) {
19		if (PyTuple_GET_ITEM(args, 0) != Py_None) {
20			PyErr_SetString(PyExc_ValueError, "pRectArray");
21			return NULL;
22		}
23		if (PyTuple_GET_ITEM(args, 1) != Py_None) {
24			PyErr_SetString(PyExc_ValueError, "pCount");
25			return NULL;
26		}
27	}
28
29	PyObjC_DURING
30		err = CGWaitForScreenRefreshRects(&rectArray, &count);
31
32	PyObjC_HANDLER
33		PyObjCErr_FromObjC(localException);
34	PyObjC_ENDHANDLER
35
36	if (PyErr_Occurred()) {
37		return NULL;
38	}
39
40	if (err == kCGErrorSuccess) {
41		/* Build the array */
42		PyObject* arr = PyObjC_CArrayToPython(
43			@encode(CGRect), rectArray, count);
44		if (arr == NULL) {
45			return NULL;
46		}
47
48		/* Free the C-level array */
49		CGReleaseScreenRefreshRects(rectArray);
50
51		return Py_BuildValue("lNl", err, arr, count);
52	}
53
54	return Py_BuildValue("lOO", err, Py_None, Py_None);
55}
56
57static PyObject*
58m_CGWaitForScreenUpdateRects(PyObject* self __attribute__((__unused__)),
59		PyObject* args)
60{
61	CGRect* rectArray = NULL;
62	size_t count = 0;
63	CGScreenUpdateOperation requestedOperations;
64	CGScreenUpdateOperation currentOperation;
65	CGScreenUpdateMoveDelta delta;
66	CGError err;
67	PyObject* py_ops;
68
69	if (!PyArg_ParseTuple(args, "O", &py_ops)) {
70		PyObject* py_curop;
71		PyObject* py_rectarr;
72		PyObject* py_count;
73		PyObject* py_delta;
74
75		if (!PyArg_ParseTuple(args, "OOOOO", &py_ops, &py_curop, &py_rectarr, &py_count, &py_delta)) {
76			return NULL;
77		}
78
79		if (py_curop != Py_None) {
80			PyErr_SetString(PyExc_ValueError, "currentOperation != None");
81			return NULL;
82		}
83		if (py_rectarr != Py_None) {
84			PyErr_SetString(PyExc_ValueError, "pRectArray != None");
85			return NULL;
86		}
87		if (py_count != Py_None) {
88			PyErr_SetString(PyExc_ValueError, "pCount != None");
89			return NULL;
90		}
91		if (py_delta != Py_None) {
92			PyErr_SetString(PyExc_ValueError, "pDelta != None");
93			return NULL;
94		}
95	}
96
97	if (PyObjC_PythonToObjC(@encode(CGScreenUpdateOperation), py_ops, &requestedOperations) < 0) {
98		return NULL;
99	}
100
101	PyObjC_DURING
102		err = CGWaitForScreenUpdateRects(
103				requestedOperations,
104				&currentOperation,
105				&rectArray, &count,
106				&delta);
107
108	PyObjC_HANDLER
109		err = -1; /* Avoid compiler warning */
110		PyObjCErr_FromObjC(localException);
111	PyObjC_ENDHANDLER
112
113	if (PyErr_Occurred()) {
114		return NULL;
115	}
116
117	if (err == kCGErrorSuccess) {
118		/* Build the array */
119		PyObject* arr = PyObjC_CArrayToPython(
120			@encode(CGRect), rectArray, count);
121		if (arr == NULL) {
122			return NULL;
123		}
124		PyObject* dlt = PyObjC_ObjCToPython(
125				@encode(CGScreenUpdateMoveDelta), &delta);
126		if (dlt == NULL) {
127			return NULL;
128		}
129
130		/* Free the C-level array */
131		CGReleaseScreenRefreshRects(rectArray);
132
133		return Py_BuildValue("llNl", err, currentOperation, arr, count, dlt);
134	}
135
136	return Py_BuildValue("lOOOO", err, Py_None, Py_None, Py_None, Py_None);
137}
138
139static PyObject*
140m_CGReleaseScreenRefreshRects(
141	PyObject* self __attribute__((__unused__)),
142	PyObject* args)
143{
144	PyObject* array;
145
146	if (!PyArg_Parse(args, "O", &array)) {
147		return NULL;
148	}
149
150	/* Do nothing, our wrappers for CGWaitForScreenRefreshRects and
151	 * CGWaitForScreenUpdateRects have already released the real array.
152	 */
153
154	Py_INCREF(Py_None);
155	return Py_None;
156}
157
158
159static PyMethodDef mod_methods[] = {
160	{
161		"CGWaitForScreenRefreshRects",
162		(PyCFunction)m_CGWaitForScreenRefreshRects,
163		METH_VARARGS,
164		NULL
165	},
166	{
167		"CGWaitForScreenUpdateRects",
168		(PyCFunction)m_CGWaitForScreenUpdateRects,
169		METH_VARARGS,
170		NULL
171	},
172	{
173		"CGReleaseScreenRefreshRects",
174		(PyCFunction)m_CGReleaseScreenRefreshRects,
175		METH_VARARGS,
176		NULL
177	},
178
179
180	{ 0, 0, 0, 0 }
181};
182
183PyObjC_MODULE_INIT(_doubleindirect)
184{
185	PyObject* m = PyObjC_MODULE_CREATE(_doubleindirect);
186
187	if (PyObjC_ImportAPI(m) < 0) PyObjC_INITERROR();
188
189	PyObjC_INITDONE();
190}
191