#include #include "pyobjc-api.h" #import static const void* mod_retain(const void* info) { PyGILState_STATE state = PyGILState_Ensure(); Py_INCREF((PyObject*)info); PyGILState_Release(state); return info; } static void mod_release(const void* info) { PyGILState_STATE state = PyGILState_Ensure(); Py_DECREF((PyObject*)info); PyGILState_Release(state); } static CFRunLoopTimerContext mod_CFRunLoopTimerContext = { 0, NULL, mod_retain, mod_release, NULL }; static void mod_CFRunLoopTimerCallBack( CFRunLoopTimerRef f, void* _info) { PyObject* info = (PyObject*)_info; PyGILState_STATE state = PyGILState_Ensure(); PyObject* py_f = PyObjC_ObjCToPython(@encode(CFRunLoopTimerRef), &f); PyObject* result = PyObject_CallFunction( PyTuple_GET_ITEM(info, 0), "NO", py_f, PyTuple_GET_ITEM(info, 1)); if (result == NULL) { PyObjCErr_ToObjCWithGILState(&state); } Py_DECREF(result); PyGILState_Release(state); } static PyObject* mod_CFRunLoopTimerCreate( PyObject* self __attribute__((__unused__)), PyObject* args) { PyObject* py_allocator; PyObject* py_fireDate; PyObject* py_interval; PyObject* py_flags; PyObject* py_order; PyObject* callout; PyObject* info; CFAllocatorRef allocator; CFAbsoluteTime fireDate; CFTimeInterval interval; CFOptionFlags flags; CFIndex order; if (!PyArg_ParseTuple(args, "OOOOOOO", &py_allocator, &py_fireDate, &py_interval, &py_flags, &py_order, &callout, &info)) { return NULL; } if (PyObjC_PythonToObjC(@encode(CFAllocatorRef), py_allocator, &allocator) < 0) { return NULL; } if (PyObjC_PythonToObjC(@encode(CFAbsoluteTime), py_fireDate, &fireDate) < 0) { return NULL; } if (PyObjC_PythonToObjC(@encode(CFTimeInterval), py_interval, &interval) < 0) { return NULL; } if (PyObjC_PythonToObjC(@encode(CFOptionFlags), py_flags, &flags) < 0) { return NULL; } if (PyObjC_PythonToObjC(@encode(CFIndex), py_order, &order) < 0) { return NULL; } CFRunLoopTimerContext context = mod_CFRunLoopTimerContext; context.info = Py_BuildValue("OO", callout, info); if (context.info == NULL) { return NULL; } CFRunLoopTimerRef rv = NULL; PyObjC_DURING rv = CFRunLoopTimerCreate( allocator, fireDate, interval, flags, order, mod_CFRunLoopTimerCallBack, &context); PyObjC_HANDLER rv = NULL; PyObjCErr_FromObjC(localException); PyObjC_ENDHANDLER Py_DECREF((PyObject*)context.info); if (PyErr_Occurred()) { return NULL; } PyObject* result = PyObjC_ObjCToPython(@encode(CFRunLoopTimerRef), &rv); if (rv != NULL) { CFRelease(rv); } return result; } static PyObject* mod_CFRunLoopTimerGetContext( PyObject* self __attribute__((__unused__)), PyObject* args) { PyObject* py_f; PyObject* py_context = NULL; CFRunLoopTimerRef f; CFRunLoopTimerContext context; if (!PyArg_ParseTuple(args, "O|O", &py_f, &py_context)) { return NULL; } if (py_context != NULL && py_context != Py_None) { PyErr_SetString(PyExc_ValueError, "invalid context"); return NULL; } if (PyObjC_PythonToObjC(@encode(CFRunLoopTimerRef), py_f, &f) < 0) { return NULL; } context.version = 0; PyObjC_DURING CFRunLoopTimerGetContext(f, &context); PyObjC_HANDLER PyObjCErr_FromObjC(localException); PyObjC_ENDHANDLER if (PyErr_Occurred()) { return NULL; } if (context.version != 0) { PyErr_SetString(PyExc_ValueError, "retrieved context is not valid"); return NULL; } if (context.retain != mod_retain) { PyErr_SetString(PyExc_ValueError, "retrieved context is not supported"); return NULL; } if (context.info == NULL) { Py_INCREF(PyObjC_NULL); return PyObjC_NULL; } Py_INCREF(PyTuple_GET_ITEM((PyObject*)context.info, 1)); return PyTuple_GET_ITEM((PyObject*)context.info, 1); } static PyMethodDef mod_methods[] = { { "CFRunLoopTimerCreate", (PyCFunction)mod_CFRunLoopTimerCreate, METH_VARARGS, NULL }, { "CFRunLoopTimerGetContext", (PyCFunction)mod_CFRunLoopTimerGetContext, METH_VARARGS, NULL }, { 0, 0, 0, 0 } /* sentinel */ }; void init_CFRunLoopTimer(void); void init_CFRunLoopTimer(void) { PyObject* m = Py_InitModule4("_CFRunLoopTimer", mod_methods, "", NULL, PYTHON_API_VERSION); PyObjC_ImportAPI(m); }