Panda3D
 All Classes Functions Variables Enumerations
pythonCallbackObject.cxx
1 // Filename: pythonCallbackObject.cxx
2 // Created by: drose (13Mar09)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "pythonCallbackObject.h"
16 
17 #ifdef HAVE_PYTHON
18 
19 #include "py_panda.h"
20 #include "thread.h"
21 #include "callbackData.h"
22 #include "config_util.h"
23 
24 TypeHandle PythonCallbackObject::_type_handle;
25 
26 Configure(config_pythonCallbackObject);
27 ConfigureFn(config_pythonCallbackObject) {
28  PythonCallbackObject::init_type();
29 }
30 
31 #ifndef CPPPARSER
32 extern struct Dtool_PyTypedObject Dtool_TypedObject;
33 #endif
34 
35 ////////////////////////////////////////////////////////////////////
36 // Function: PythonCallbackObject::Constructor
37 // Access: Published
38 // Description:
39 ////////////////////////////////////////////////////////////////////
40 PythonCallbackObject::
41 PythonCallbackObject(PyObject *function) {
42  _function = Py_None;
43  Py_INCREF(_function);
44 
45  set_function(function);
46 
47 #ifndef SIMPLE_THREADS
48  // Ensure that the Python threading system is initialized and ready
49  // to go.
50 #ifdef WITH_THREAD // This symbol defined within Python.h
51 
52 #if PY_VERSION_HEX >= 0x03020000
53  Py_Initialize();
54 #endif
55 
56  PyEval_InitThreads();
57 #endif
58 #endif
59 }
60 
61 ////////////////////////////////////////////////////////////////////
62 // Function: PythonCallbackObject::Destructor
63 // Access: Published, Virtual
64 // Description:
65 ////////////////////////////////////////////////////////////////////
66 PythonCallbackObject::
67 ~PythonCallbackObject() {
68  Py_DECREF(_function);
69 }
70 
71 ////////////////////////////////////////////////////////////////////
72 // Function: PythonCallbackObject::set_function
73 // Access: Published
74 // Description: Replaces the function that is called for the callback.
75 // runs. The parameter should be a Python callable
76 // object.
77 ////////////////////////////////////////////////////////////////////
78 void PythonCallbackObject::
79 set_function(PyObject *function) {
80  Py_DECREF(_function);
81  _function = function;
82  Py_INCREF(_function);
83  if (_function != Py_None && !PyCallable_Check(_function)) {
84  nassert_raise("Invalid function passed to PythonCallbackObject");
85  }
86 }
87 
88 ////////////////////////////////////////////////////////////////////
89 // Function: PythonCallbackObject::get_function
90 // Access: Published
91 // Description: Returns the function that is called for the callback.
92 ////////////////////////////////////////////////////////////////////
93 PyObject *PythonCallbackObject::
94 get_function() {
95  Py_INCREF(_function);
96  return _function;
97 }
98 
99 ////////////////////////////////////////////////////////////////////
100 // Function: PythonCallbackObject::do_callback
101 // Access: Public, Virtual
102 // Description: This method called when the callback is triggered; it
103 // *replaces* the original function. To continue
104 // performing the original function, you must call
105 // cbdata->upcall() during the callback.
106 ////////////////////////////////////////////////////////////////////
107 void PythonCallbackObject::
108 do_callback(CallbackData *cbdata) {
109 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
110  // Use PyGILState to protect this asynchronous call.
111  PyGILState_STATE gstate;
112  gstate = PyGILState_Ensure();
113 #endif
114 
115  do_python_callback(cbdata);
116 
117 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
118  PyGILState_Release(gstate);
119 #endif
120 }
121 
122 ////////////////////////////////////////////////////////////////////
123 // Function: PythonCallbackObject::do_python_callback
124 // Access: Private
125 // Description: The Python calls that implement do_callback(). This
126 // function is separate so we can acquire the Python
127 // interpretor lock while it runs.
128 ////////////////////////////////////////////////////////////////////
129 void PythonCallbackObject::
130 do_python_callback(CallbackData *cbdata) {
131  nassertv(cbdata != NULL);
132 
133  // Wrap the cbdata up in a Python object, then put it in a tuple,
134  // for the argument list.
135  PyObject *pycbdata =
136  DTool_CreatePyInstanceTyped(cbdata, Dtool_TypedObject,
137  false, false, cbdata->get_type_index());
138  PyObject *args = Py_BuildValue("(O)", pycbdata);
139  Py_DECREF(pycbdata);
140 
141  PyObject *result =
142  Thread::get_current_thread()->call_python_func(_function, args);
143  Py_DECREF(args);
144 
145  if (result == (PyObject *)NULL) {
146  util_cat.error()
147  << "Exception occurred in " << *this << "\n";
148  } else {
149  Py_DECREF(result);
150  }
151 }
152 
153 #endif // HAVE_PYTHON
This is a generic data block that is passed along to a CallbackObject when a callback is made...
Definition: callbackData.h:32
int get_type_index() const
Returns the internal index number associated with this object&#39;s TypeHandle, a unique number for each ...
Definition: typedObject.I:52
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
Definition: thread.I:145
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85