// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 // $Id: Python.cpp 59 2008-05-15 20:55:31Z cubicool $ // Python.h needs to be included before anything else. #ifdef OSGWIDGET_USEPYTHON #include #endif #include #include #include #include namespace osgWidget { // Our Python library. namespace py { #ifdef OSGWIDGET_USEPYTHON // TODO: Until I can find a way to move data around inside of the context, this will // have to do. I don't really like it, but I've got no choice. static PyObject* G_ERR = 0; PyObject* newWindow(PyObject* self, PyObject* args) { PyObject* buffer = 0; const char* name = 0; int width = 0; int height = 0; /* if(PyArg_ParseTuple(args, "sO!ii", &name, &PyBuffer_Type, &buffer, &width, &height)) { const void* buf = 0; int len = 0; if(!PyObject_AsReadBuffer(buffer, &buf, &len)) { // if(Database::instance().add(name, buf, width, height)) return Py_BuildValue("i", len); // else PyErr_SetString(G_ERR, "Couldn't add image to database."); } else PyErr_SetString(G_ERR, "Couldn't read buffer data."); return 0; } */ PyErr_SetString(G_ERR, "still testing..."); return 0; } static PyMethodDef methods[] = { { "newWindow", newWindow, METH_VARARGS, "docstring" }, { 0, 0, 0, 0 } }; #endif } // A helper function for all those cases where we need to inform the user that there isn't // a LUA engine available. bool noPythonFail(const std::string& err) { warn() << err << "; Python not compiled in library." << std::endl; return false; } // Our "private", internal data. struct PythonEngineData { #ifdef OSGWIDGET_USEPYTHON PythonEngineData(): mod (0), err (0), main (0) { } bool valid() const { return mod && err && main; } PyObject* mod; PyObject* err; PyObject* main; #endif }; PythonEngine::PythonEngine(WindowManager* wm): _wm(wm) { #ifdef OSGWIDGET_USEPYTHON _data = new PythonEngineData(); #else _data = 0; #endif } bool PythonEngine::initialize() { #ifdef OSGWIDGET_USEPYTHON Py_InitializeEx(0); if(!_data->valid()) { _data->mod = Py_InitModule3("osgwidget", py::methods, "main docstring"); _data->err = PyErr_NewException((char*)("osgwidget.error"), 0, 0); _data->main = PyModule_GetDict(PyImport_AddModule("__main__")); Py_INCREF(_data->err); // TODO: ...sigh... py::G_ERR = _data->err; PyModule_AddObject(_data->mod, "error", _data->err); } return true; #else return noPythonFail("Can't initialize the PythonEngine"); #endif } bool PythonEngine::close() { #ifdef OSGWIDGET_USEPYTHON if(_data->valid()) { Py_DECREF(_data->err); Py_Finalize(); } delete _data; return true; #else return noPythonFail("Can't close the PythonEngine"); #endif } bool PythonEngine::eval(const std::string& code) { #ifdef OSGWIDGET_USEPYTHON PyObject* r = PyRun_String(code.c_str(), Py_file_input, _data->main, _data->main); if(!r) { r = PyErr_Occurred(); if(r) { PyErr_Print(); PyErr_Clear(); } return false; } return true; #else return noPythonFail("Can't evaluate code in PythonEngine"); #endif } bool PythonEngine::runFile(const std::string& filePath) { #ifdef OSGWIDGET_USEPYTHON if(!osgDB::fileExists(filePath)) { warn() << "Couldn't find file \"" << filePath << "\" for PythonEngine." << std::endl ; return false; } FILE* f = fopen(filePath.c_str(), "r"); PyObject* r = PyRun_File(f, filePath.c_str(), Py_file_input, _data->main, _data->main); fclose(f); if(!r) { r = PyErr_Occurred(); if(r) { // The following snippet lets us get the return code. That is: if the // script is stopped with sys.exit() or similar. We could use this // return code to do something sensible... later. if(PyErr_ExceptionMatches(PyExc_SystemExit)) { PyObject* ty = 0; PyObject* er = 0; PyObject* tr = 0; PyErr_Fetch(&ty, &er, &tr); Py_DECREF(ty); Py_DECREF(er); Py_DECREF(er); } else { PyErr_Print(); PyErr_Clear(); } } return false; } return true; #else return noPythonFail("Can't evaluate code in PythonEngine"); #endif } }