Panda3D
|
00001 // Filename: pythonCallbackObject.cxx 00002 // Created by: drose (13Mar09) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "pythonCallbackObject.h" 00016 00017 #ifdef HAVE_PYTHON 00018 #include "py_panda.h" 00019 #include "thread.h" 00020 #include "callbackData.h" 00021 00022 TypeHandle PythonCallbackObject::_type_handle; 00023 00024 #ifndef CPPPARSER 00025 IMPORT_THIS struct Dtool_PyTypedObject Dtool_TypedObject; 00026 #endif 00027 00028 //////////////////////////////////////////////////////////////////// 00029 // Function: PythonCallbackObject::Constructor 00030 // Access: Published 00031 // Description: 00032 //////////////////////////////////////////////////////////////////// 00033 PythonCallbackObject:: 00034 PythonCallbackObject(PyObject *function) { 00035 _function = Py_None; 00036 Py_INCREF(_function); 00037 00038 set_function(function); 00039 00040 #ifndef SIMPLE_THREADS 00041 // Ensure that the Python threading system is initialized and ready 00042 // to go. 00043 #ifdef WITH_THREAD // This symbol defined within Python.h 00044 PyEval_InitThreads(); 00045 #endif 00046 #endif 00047 } 00048 00049 //////////////////////////////////////////////////////////////////// 00050 // Function: PythonCallbackObject::Destructor 00051 // Access: Published, Virtual 00052 // Description: 00053 //////////////////////////////////////////////////////////////////// 00054 PythonCallbackObject:: 00055 ~PythonCallbackObject() { 00056 Py_DECREF(_function); 00057 } 00058 00059 //////////////////////////////////////////////////////////////////// 00060 // Function: PythonCallbackObject::set_function 00061 // Access: Published 00062 // Description: Replaces the function that is called for the callback. 00063 // runs. The parameter should be a Python callable 00064 // object. 00065 //////////////////////////////////////////////////////////////////// 00066 void PythonCallbackObject:: 00067 set_function(PyObject *function) { 00068 Py_DECREF(_function); 00069 _function = function; 00070 Py_INCREF(_function); 00071 if (_function != Py_None && !PyCallable_Check(_function)) { 00072 nassert_raise("Invalid function passed to PythonCallbackObject"); 00073 } 00074 } 00075 00076 //////////////////////////////////////////////////////////////////// 00077 // Function: PythonCallbackObject::get_function 00078 // Access: Published 00079 // Description: Returns the function that is called for the callback. 00080 //////////////////////////////////////////////////////////////////// 00081 PyObject *PythonCallbackObject:: 00082 get_function() { 00083 Py_INCREF(_function); 00084 return _function; 00085 } 00086 00087 //////////////////////////////////////////////////////////////////// 00088 // Function: PythonCallbackObject::do_callback 00089 // Access: Public, Virtual 00090 // Description: This method called when the callback is triggered; it 00091 // *replaces* the original function. To continue 00092 // performing the original function, you must call 00093 // cbdata->upcall() during the callback. 00094 //////////////////////////////////////////////////////////////////// 00095 void PythonCallbackObject:: 00096 do_callback(CallbackData *cbdata) { 00097 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 00098 // Use PyGILState to protect this asynchronous call. 00099 PyGILState_STATE gstate; 00100 gstate = PyGILState_Ensure(); 00101 #endif 00102 00103 do_python_callback(cbdata); 00104 00105 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) 00106 PyGILState_Release(gstate); 00107 #endif 00108 } 00109 00110 //////////////////////////////////////////////////////////////////// 00111 // Function: PythonCallbackObject::do_python_callback 00112 // Access: Private 00113 // Description: The Python calls that implement do_callback(). This 00114 // function is separate so we can acquire the Python 00115 // interpretor lock while it runs. 00116 //////////////////////////////////////////////////////////////////// 00117 void PythonCallbackObject:: 00118 do_python_callback(CallbackData *cbdata) { 00119 nassertv(cbdata != NULL); 00120 00121 // Wrap the cbdata up in a Python object, then put it in a tuple, 00122 // for the argument list. 00123 PyObject *pycbdata = 00124 DTool_CreatePyInstanceTyped(cbdata, Dtool_TypedObject, 00125 false, false, cbdata->get_type_index()); 00126 PyObject *args = Py_BuildValue("(O)", pycbdata); 00127 Py_DECREF(pycbdata); 00128 00129 PyObject *result = 00130 Thread::get_current_thread()->call_python_func(_function, args); 00131 Py_DECREF(args); 00132 00133 if (result == (PyObject *)NULL) { 00134 util_cat.error() 00135 << "Exception occurred in " << *this << "\n"; 00136 } else { 00137 Py_DECREF(result); 00138 } 00139 } 00140 00141 #endif // HAVE_PYTHON