Panda3D
 All Classes Functions Variables Enumerations
pythonCallbackObject.cxx
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
 All Classes Functions Variables Enumerations