open_toontown_panda3d/panda/src/putil/pythonCallbackObject.cxx

142 lines
4.5 KiB
C++

// Filename: pythonCallbackObject.cxx
// Created by: drose (13Mar09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "pythonCallbackObject.h"
#ifdef HAVE_PYTHON
#include "py_panda.h"
#include "thread.h"
#include "callbackData.h"
TypeHandle PythonCallbackObject::_type_handle;
#ifndef CPPPARSER
IMPORT_THIS struct Dtool_PyTypedObject Dtool_TypedObject;
#endif
////////////////////////////////////////////////////////////////////
// Function: PythonCallbackObject::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
PythonCallbackObject::
PythonCallbackObject(PyObject *function) {
_function = Py_None;
Py_INCREF(_function);
set_function(function);
#ifndef SIMPLE_THREADS
// Ensure that the Python threading system is initialized and ready
// to go.
#ifdef WITH_THREAD // This symbol defined within Python.h
PyEval_InitThreads();
#endif
#endif
}
////////////////////////////////////////////////////////////////////
// Function: PythonCallbackObject::Destructor
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
PythonCallbackObject::
~PythonCallbackObject() {
Py_DECREF(_function);
}
////////////////////////////////////////////////////////////////////
// Function: PythonCallbackObject::set_function
// Access: Published
// Description: Replaces the function that is called for the callback.
// runs. The parameter should be a Python callable
// object.
////////////////////////////////////////////////////////////////////
void PythonCallbackObject::
set_function(PyObject *function) {
Py_DECREF(_function);
_function = function;
Py_INCREF(_function);
if (_function != Py_None && !PyCallable_Check(_function)) {
nassert_raise("Invalid function passed to PythonCallbackObject");
}
}
////////////////////////////////////////////////////////////////////
// Function: PythonCallbackObject::get_function
// Access: Published
// Description: Returns the function that is called for the callback.
////////////////////////////////////////////////////////////////////
PyObject *PythonCallbackObject::
get_function() {
Py_INCREF(_function);
return _function;
}
////////////////////////////////////////////////////////////////////
// Function: PythonCallbackObject::do_callback
// Access: Public, Virtual
// Description: This method called when the callback is triggered; it
// *replaces* the original function. To continue
// performing the original function, you must call
// cbdata->upcall() during the callback.
////////////////////////////////////////////////////////////////////
void PythonCallbackObject::
do_callback(CallbackData *cbdata) {
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
// Use PyGILState to protect this asynchronous call.
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
#endif
do_python_callback(cbdata);
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
PyGILState_Release(gstate);
#endif
}
////////////////////////////////////////////////////////////////////
// Function: PythonCallbackObject::do_python_callback
// Access: Private
// Description: The Python calls that implement do_callback(). This
// function is separate so we can acquire the Python
// interpretor lock while it runs.
////////////////////////////////////////////////////////////////////
void PythonCallbackObject::
do_python_callback(CallbackData *cbdata) {
nassertv(cbdata != NULL);
// Wrap the cbdata up in a Python object, then put it in a tuple,
// for the argument list.
PyObject *pycbdata =
DTool_CreatePyInstanceTyped(cbdata, Dtool_TypedObject,
false, false, cbdata->get_type_index());
PyObject *args = Py_BuildValue("(O)", pycbdata);
Py_DECREF(pycbdata);
PyObject *result =
Thread::get_current_thread()->call_python_func(_function, args);
Py_DECREF(args);
if (result == (PyObject *)NULL) {
util_cat.error()
<< "Exception occurred in " << *this << "\n";
} else {
Py_DECREF(result);
}
}
#endif // HAVE_PYTHON