From: vsr Date: Tue, 15 May 2007 10:36:00 +0000 (+0000) Subject: Porting to Qt4 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=c1b9ddec41f91d604118ff33fdcc190c93f89499;p=modules%2Fgui.git Porting to Qt4 --- diff --git a/src/PyInterp/Makefile.am b/src/PyInterp/Makefile.am index 9a783f209..7a451b4ad 100755 --- a/src/PyInterp/Makefile.am +++ b/src/PyInterp/Makefile.am @@ -27,13 +27,13 @@ include $(top_srcdir)/adm_local/unix/make_common_starter.am lib_LTLIBRARIES = libPyInterp.la -salomeinclude_HEADERS= \ - PyInterp.h \ - PyInterp_base.h \ +salomeinclude_HEADERS= \ + PyInterp.h \ + PyInterp_Interp.h \ PyInterp_Dispatcher.h -dist_libPyInterp_la_SOURCES= \ - PyInterp_base.cxx \ +dist_libPyInterp_la_SOURCES= \ + PyInterp_Interp.cxx \ PyInterp_Dispatcher.cxx MOC_FILES= PyInterp_Watcher_moc.cxx diff --git a/src/PyInterp/PyInterp.h b/src/PyInterp/PyInterp.h index af9536fd8..4f2777d00 100755 --- a/src/PyInterp/PyInterp.h +++ b/src/PyInterp/PyInterp.h @@ -16,24 +16,24 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -#if !defined ( _PYINTERP_H ) -#define _PYINTERP_H +// File : PyInterp.h +// Author : Vadim SANDLER +// Module : SALOME + +#if !defined ( PYINTERP_H ) +#define PYINTERP_H // ======================================================== // set dllexport type for Win platform -#ifdef WNT - -#ifdef PYINTERP_EXPORTS -#define PYINTERP_EXPORT __declspec(dllexport) -#else -#define PYINTERP_EXPORT __declspec(dllimport) -#endif - -#else // WNT - -#define PYINTERP_EXPORT - -#endif // WNT +#ifdef WIN32 +# ifdef PYINTERP_EXPORTS +# define PYINTERP_EXPORT __declspec(dllexport) +# else +# define PYINTERP_EXPORT __declspec(dllimport) +# endif +#else // WIN32 +# define PYINTERP_EXPORT +#endif // WIN32 // ======================================================== // little trick - if we do not have debug python libraries @@ -53,9 +53,9 @@ // ======================================================== // avoid warning messages -#ifdef WNT +#ifdef WIN32 #pragma warning (disable : 4786) #pragma warning (disable : 4251) #endif -#endif // _PYINTERP_H +#endif // PYINTERP_H diff --git a/src/PyInterp/PyInterp.pro b/src/PyInterp/PyInterp.pro new file mode 100644 index 000000000..4c35c06ae --- /dev/null +++ b/src/PyInterp/PyInterp.pro @@ -0,0 +1,33 @@ +TEMPLATE = lib +TARGET = PyInterp +DESTDIR = ../../lib +MOC_DIR = ../../moc +OBJECTS_DIR = ../../obj/$$TARGET + +PYTHONVER=2.4 +PYTHONHOME=$$(PYTHONHOME) +PYTHONINC=$${PYTHONHOME}/include/python$${PYTHONVER} +PYTHONLIB=$${PYTHONHOME}/lib + +INCLUDEPATH += ../../include $${PYTHONINC} +unix:LIBS += -L$${PYTHONLIB} -lpython$${PYTHONVER} +win32:LIBS += /LIBPATH:$${PYTHONLIB} + +CONFIG -= debug release debug_and_release +CONFIG += qt thread debug dll shared + +win32:DEFINES += WIN32 +DEFINES += PYINTERP_EXPORTS + +HEADERS = PyInterp.h +HEADERS += PyInterp_Dispatcher.h +HEADERS += PyInterp_Watcher.h +HEADERS += PyInterp_Interp.h + +SOURCES = PyInterp_Dispatcher.cxx +SOURCES += PyInterp_Interp.cxx + +includes.files = $$HEADERS +includes.path = ../../include + +INSTALLS += includes diff --git a/src/PyInterp/PyInterp_Dispatcher.cxx b/src/PyInterp/PyInterp_Dispatcher.cxx index dd029a25b..e3adb001d 100755 --- a/src/PyInterp/PyInterp_Dispatcher.cxx +++ b/src/PyInterp/PyInterp_Dispatcher.cxx @@ -16,22 +16,17 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SALOME SALOMEGUI : implementation of desktop and GUI kernel -// // File : PyInterp_Dispatcher.cxx // Author : Sergey ANIKIN, OCC // Module : GUI -// $Header$ - -#include -#include -#include +#include "PyInterp_Dispatcher.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!! +#include "PyInterp_Interp.h" +#include "PyInterp_Watcher.h" -#include -#include +#include +#include -//#include using namespace std; PyInterp_Dispatcher* PyInterp_Dispatcher::myInstance = 0; @@ -40,11 +35,16 @@ void PyInterp_Request::process() { safeExecute(); - myMutex.lock(); - //if ( !IsSync() && getListener() && getEvent() ) - if ( getListener() && getEvent() ) - postEvent(); - myMutex.unlock(); + bool isSync = IsSync(); + + if ( !isSync ) + myMutex.lock(); + + if ( listener() ) + processEvent( listener() ); + + if ( !isSync ) + myMutex.unlock(); } void PyInterp_Request::safeExecute() @@ -65,23 +65,22 @@ QEvent* PyInterp_Request::createEvent() const return new PyInterp_Event( PyInterp_Event::NOTIFY, (PyInterp_Request*)this ); } -QEvent* PyInterp_Request::getEvent() +void PyInterp_Request::processEvent( QObject* o ) { - //if ( !myEvent && !IsSync() ) - if ( !myEvent ) - myEvent = createEvent(); - return myEvent; -} + if ( !o ) + return; -void PyInterp_Request::postEvent() -{ -#if QT_VERSION >= 0x030303 -// MESSAGE("*** PyInterp_Request::postEvent(): for Qt 3.3.3") - QApplication::postEvent( getListener(), getEvent() ); -#else -// MESSAGE("*** PyInterp_Request::postEvent(): for Qt 3.0.5") - QThread::postEvent( getListener(), getEvent() ); -#endif + QEvent* e = createEvent(); + if ( !e ) + return; + + if ( !IsSync() ) + QCoreApplication::postEvent( o, e ); + else + { + QCoreApplication::sendEvent( o, e ); + delete e; + } } void PyInterp_Request::setListener( QObject* o ) @@ -123,8 +122,9 @@ PyInterp_Dispatcher::~PyInterp_Dispatcher() // Clear the request queue myQueueMutex.lock(); - for ( std::list::iterator it = myQueue.begin(); it != myQueue.end(); ++it ) - PyInterp_Request::Destroy( *it ); + QListIterator it( myQueue ); + while ( it.hasNext() ) + PyInterp_Request::Destroy( it.next() ); myQueue.clear(); myQueueMutex.unlock(); @@ -138,7 +138,7 @@ PyInterp_Dispatcher::~PyInterp_Dispatcher() bool PyInterp_Dispatcher::IsBusy() const { - return running(); + return isRunning(); } void PyInterp_Dispatcher::Exec( PyInterp_Request* theRequest ) @@ -149,11 +149,12 @@ void PyInterp_Dispatcher::Exec( PyInterp_Request* theRequest ) //if ( theRequest->IsSync() && !IsBusy() ) // synchronous processing - nothing is done if dispatcher is busy! if ( theRequest->IsSync() ) // synchronous processing - nothing is done if dispatcher is busy! processRequest( theRequest ); - else { // asynchronous processing + else // asynchronous processing + { myQueueMutex.lock(); - myQueue.push_back( theRequest ); - if ( theRequest->getListener() ) - QObject::connect( theRequest->getListener(), SIGNAL( destroyed( QObject* ) ), myWatcher, SLOT( onDestroyed( QObject* ) ) ); + myQueue.enqueue( theRequest ); + if ( theRequest->listener() ) + QObject::connect( theRequest->listener(), SIGNAL( destroyed( QObject* ) ), myWatcher, SLOT( onDestroyed( QObject* ) ) ); myQueueMutex.unlock(); if ( !IsBusy() ) @@ -171,7 +172,7 @@ void PyInterp_Dispatcher::run() while( myQueue.size() ) { // MESSAGE("*** PyInterp_Dispatcher::run(): next request taken from the queue") - aRequest = myQueue.front(); + aRequest = myQueue.head(); // let other threads append their requests to the end of the queue myQueueMutex.unlock(); @@ -183,8 +184,8 @@ void PyInterp_Dispatcher::run() // prepare for removal of the first request in the queue myQueueMutex.lock(); // IMPORTANT: the first item could have been removed by objectDestroyed() --> we have to check it - if ( myQueue.front() == aRequest ) // It's still here --> remove it - myQueue.pop_front(); + if ( myQueue.head() == aRequest ) // It's still here --> remove it + myQueue.dequeue(); // MESSAGE("*** PyInterp_Dispatcher::run(): request processed") } @@ -203,13 +204,16 @@ void PyInterp_Dispatcher::objectDestroyed( const QObject* o ) // prepare for modification of the queue myQueueMutex.lock(); - for ( std::list::iterator it = myQueue.begin(); it != myQueue.end(); ++it ){ - if ( o == (*it)->getListener() ){ - (*it)->setListener( 0 ); // to prevent event posting - it = myQueue.erase( it ); + QMutableListIterator it( myQueue ); + while ( it.hasNext() ) + { + RequestPtr r = it.next(); + if ( o == r->listener() ) + { + r->setListener( 0 ); // to prevent event posting + it.remove(); } } myQueueMutex.unlock(); } - diff --git a/src/PyInterp/PyInterp_Dispatcher.h b/src/PyInterp/PyInterp_Dispatcher.h index 311c9e66f..511fbbdb4 100755 --- a/src/PyInterp/PyInterp_Dispatcher.h +++ b/src/PyInterp/PyInterp_Dispatcher.h @@ -16,25 +16,23 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -// SALOME SALOMEGUI : implementation of desktop and GUI kernel -// // File : PyInterp_Dispatcher.h // Author : Sergey Anikin, OCC // Module : SALOME -#ifndef _PYINTERP_DISPATCHER_H_ -#define _PYINTERP_DISPATCHER_H_ - -#include "PyInterp.h" +#ifndef PYINTERP_DISPATCHER_H +#define PYINTERP_DISPATCHER_H -#include -#include +#include "PyInterp.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!! -#include +#include +#include +#include +#include class QObject; -class PyInterp_base; +class PyInterp_Interp; class PyInterp_Watcher; class PyInterp_Dispatcher; @@ -46,12 +44,12 @@ class PYINTERP_EXPORT PyInterp_Request PyInterp_Request( const PyInterp_Request& ); protected: - virtual ~PyInterp_Request() {}; + virtual ~PyInterp_Request() {}; // protected destructor - to control deletion of requests public: PyInterp_Request( QObject* listener, bool sync = false ) - : myIsSync( sync ), myListener( listener ), myEvent( 0 ) {}; + : myIsSync( sync ), myListener( listener ) {}; static void Destroy( PyInterp_Request* ); // Deletes a request @@ -69,36 +67,35 @@ protected: virtual QEvent* createEvent() const; // This method can be overridden to customize notification event creation + virtual void processEvent( QObject* ); + private: void process(); - QObject* getListener() const { return myListener; } + QObject* listener() const { return myListener; } void setListener( QObject* ); - QEvent* getEvent(); - void postEvent(); private: + QMutex myMutex; bool myIsSync; QObject* myListener; - QEvent* myEvent; - QMutex myMutex; }; class PYINTERP_EXPORT PyInterp_LockRequest : public PyInterp_Request { public: - PyInterp_LockRequest( PyInterp_base* interp, QObject* listener = 0, bool sync = false ) + PyInterp_LockRequest( PyInterp_Interp* interp, QObject* listener = 0, bool sync = false ) : PyInterp_Request( listener, sync ), myInterp( interp ) {} protected: - PyInterp_base* getInterp() const { return myInterp; } + PyInterp_Interp* getInterp() const { return myInterp; } - virtual void safeExecute(); + virtual void safeExecute(); private: - PyInterp_base* myInterp; + PyInterp_Interp* myInterp; }; -class PYINTERP_EXPORT PyInterp_Event : public QCustomEvent +class PYINTERP_EXPORT PyInterp_Event : public QEvent { PyInterp_Event(); PyInterp_Event( const PyInterp_Event& ); @@ -107,7 +104,7 @@ public: enum { NOTIFY = QEvent::User + 5000, OK, ERROR, INCOMPLETE, LAST }; PyInterp_Event( int type, PyInterp_Request* request ) - : QCustomEvent( (QEvent::Type)type ), myRequest( request ) {} + : QEvent( (QEvent::Type)type ), myRequest( request ) {} virtual ~PyInterp_Event(); @@ -138,7 +135,7 @@ private: private: typedef PyInterp_Request* RequestPtr; - std::list myQueue; + QQueue myQueue; QMutex myQueueMutex; PyInterp_Watcher* myWatcher; @@ -147,4 +144,4 @@ private: friend class PyInterp_Watcher; }; -#endif +#endif // PYINTERP_DISPATCHER_H diff --git a/src/PyInterp/PyInterp_Interp.cxx b/src/PyInterp/PyInterp_Interp.cxx new file mode 100644 index 000000000..75503c3b3 --- /dev/null +++ b/src/PyInterp/PyInterp_Interp.cxx @@ -0,0 +1,330 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyInterp_Interp.cxx +// Author : Christian CAREMOLI, Paul RASCLE, EDF +// Module : SALOME + +#include "PyInterp_Interp.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!! + +#include + +#include +#include + +using namespace std; + +#define TOP_HISTORY_PY "--- top of history ---" +#define BEGIN_HISTORY_PY "--- begin of history ---" + +PyLockWrapper::PyLockWrapper(PyThreadState* theThreadState): + myThreadState(theThreadState), + mySaveThreadState(0) +{ + if (myThreadState->interp == PyInterp_Interp::_interp) + _savestate = PyGILState_Ensure(); + else + PyEval_AcquireThread(myThreadState); +} + +PyLockWrapper::~PyLockWrapper() +{ + if (myThreadState->interp == PyInterp_Interp::_interp) + PyGILState_Release(_savestate); + else + PyEval_ReleaseThread(myThreadState); +} + +PyLockWrapper PyInterp_Interp::GetLockWrapper() +{ + return _tstate; +} + +/*! + \class PyInterp_Interp + \brief Generic embedded Python interpreter. +*/ + +int PyInterp_Interp::_argc = 1; +char* PyInterp_Interp::_argv[] = {""}; +PyObject* PyInterp_Interp::builtinmodule = NULL; +PyThreadState* PyInterp_Interp::_gtstate = NULL; +PyInterpreterState* PyInterp_Interp::_interp = NULL; + +/*! + \brief Basic constructor. + + After construction the interpreter instance successor classes + must call virtual method initalize(). +*/ +PyInterp_Interp::PyInterp_Interp(): + _tstate(0), _vout(0), _verr(0), _g(0) +{ +} + +/*! + \brief Destructor. +*/ +PyInterp_Interp::~PyInterp_Interp() +{ +} + +/*! + \brief Initialize embedded interpreter. + + This method shoud be called after construction of the interpreter. + The method initialize() calls virtuals methods + - initPython() to initialize global Python interpreter + - initState() to initialize embedded interpreter state + - initContext() to initialize interpreter internal context + - initRun() to prepare interpreter for running commands + which should be implemented in the successor classes, according to the + embedded Python interpreter policy (mono or multi interpreter, etc). +*/ +void PyInterp_Interp::initialize() +{ + _history.clear(); // start a new list of user's commands + _ith = _history.begin(); + + initPython(); + // Here the global lock is released + + initState(); + + PyLockWrapper aLock = GetLockWrapper(); + + initContext(); + + // used to interpret & compile commands + PyObjWrapper m(PyImport_ImportModule("codeop")); + if(!m) { + PyErr_Print(); + return; + } + + // Create cStringIO to capture stdout and stderr + PycString_IMPORT; + if (PycStringIO) { // CTH11627 : additional check + _vout = PycStringIO->NewOutput(128); + _verr = PycStringIO->NewOutput(128); + } + + // All the initRun outputs are redirected to the standard output (console) + initRun(); +} + +/*! + \brief Initialize Python interpreter. + + Set program name, initialize interpreter, set program arguments, + initiaize threads. + */ +void PyInterp_Interp::initPython() +{ + if (Py_IsInitialized()) + return; + + // Python is not initialized + Py_SetProgramName(_argv[0]); + Py_Initialize(); // Initialize the interpreter + PySys_SetArgv(_argc, _argv); + PyEval_InitThreads(); // Create (and acquire) the interpreter lock + _interp = PyThreadState_Get()->interp; + _gtstate = PyEval_SaveThread(); // Release global thread state +} + +/*! + \brief Get embedded Python interpreter banner. + \return banner string + */ +string PyInterp_Interp::getbanner() +{ + // Should we take the lock ? + // PyEval_RestoreThread(_tstate); + string aBanner("Python "); + aBanner = aBanner + Py_GetVersion() + " on " + Py_GetPlatform() ; + aBanner = aBanner + "\ntype help to get general information on environment\n"; + //PyEval_SaveThread(); + return aBanner; +} + +/*! + \brief Initialize run command. + + This method is used to prepare interpreter for running + Python commands. + + \return \c true on success and \c false on error +*/ +bool PyInterp_Interp::initRun() +{ + PySys_SetObject("stderr",_verr); + PySys_SetObject("stdout",_vout); + + PyObjWrapper verr(PyObject_CallMethod(_verr,"reset","")); + PyObjWrapper vout(PyObject_CallMethod(_vout,"reset","")); + + //PyObject *m = PyImport_GetModuleDict(); + + PySys_SetObject("stdout",PySys_GetObject("__stdout__")); + PySys_SetObject("stderr",PySys_GetObject("__stderr__")); + + return true; +} + +/*! + \brief Compile Python command and evaluate it in the + python dictionary context if possible. + \internal + \param command Python command string + \param context Python context (dictionary) + \return -1 on fatal error, 1 if command is incomplete and 0 + if command is executed successfully + */ +static int compile_command(const char *command,PyObject *context) +{ + PyObject *m = PyImport_AddModule("codeop"); + if(!m) { // Fatal error. No way to go on. + PyErr_Print(); + return -1; + } + PyObjWrapper v(PyObject_CallMethod(m,"compile_command","s",command)); + if(!v) { + // Error encountered. It should be SyntaxError, + //so we don't write out traceback + PyObjWrapper exception, value, tb; + PyErr_Fetch(&exception, &value, &tb); + PyErr_NormalizeException(&exception, &value, &tb); + PyErr_Display(exception, value, NULL); + return -1; + } + else if (v == Py_None) { + // Incomplete text we return 1 : we need a complete text to execute + return 1; + } + else { + // Complete and correct text. We evaluate it. + //#if PY_VERSION_HEX < 0x02040000 // python version earlier than 2.4.0 + // PyObjWrapper r(PyEval_EvalCode(v,context,context)); + //#else + PyObjWrapper r(PyEval_EvalCode((PyCodeObject *)(void *)v,context,context)); + //#endif + if(!r) { + // Execution error. We return -1 + PyErr_Print(); + return -1; + } + // The command has been successfully executed. Return 0 + return 0; + } +} + +/*! + \brief Run Python command. + \param command Python command + \return command status +*/ +int PyInterp_Interp::run(const char *command) +{ + beforeRun(); + return simpleRun(command); +} + +/*! + \brief Run Python command (used internally). + \param command Python command + \param addToHistory if \c true (default), the command is added to the commands history + \return command status +*/ +int PyInterp_Interp::simpleRun(const char *command, const bool addToHistory) +{ + if( addToHistory && strcmp(command,"") != 0 ) { + _history.push_back(command); + _ith = _history.end(); + } + + // We come from C++ to enter Python world + // We need to acquire the Python global lock + //PyLockWrapper aLock(_tstate); // san - lock is centralized now + + // Reset redirected outputs before treatment + PySys_SetObject("stderr",_verr); + PySys_SetObject("stdout",_vout); + + PyObjWrapper verr(PyObject_CallMethod(_verr,"reset","")); + PyObjWrapper vout(PyObject_CallMethod(_vout,"reset","")); + + int ier = compile_command(command,_g); + + // Outputs are redirected on standards outputs (console) + PySys_SetObject("stdout",PySys_GetObject("__stdout__")); + PySys_SetObject("stderr",PySys_GetObject("__stderr__")); + + return ier; +} + +/*! + \brief Get previous command in the commands history. + \return previous command +*/ +const char * PyInterp_Interp::getPrevious() +{ + if(_ith != _history.begin()){ + _ith--; + return (*_ith).c_str(); + } + else + return BEGIN_HISTORY_PY; +} + +/*! + \brief Get next command in the commands history. + \return next command +*/ +const char * PyInterp_Interp::getNext() +{ + if(_ith != _history.end()){ + _ith++; + } + if (_ith == _history.end()) + return TOP_HISTORY_PY; + else + return (*_ith).c_str(); +} + +/*! + \brief Get standard error output. + \return standard error output +*/ +string PyInterp_Interp::getverr(){ + //PyLockWrapper aLock(_tstate); + PyObjWrapper v(PycStringIO->cgetvalue(_verr)); + string aRet(PyString_AsString(v)); + return aRet; +} + +/*! + \brief Get standard output. + \return standard output +*/ +string PyInterp_Interp::getvout(){ + //PyLockWrapper aLock(_tstate); + PyObjWrapper v(PycStringIO->cgetvalue(_vout)); + string aRet(PyString_AsString(v)); + return aRet; +} diff --git a/src/PyInterp/PyInterp_Interp.h b/src/PyInterp/PyInterp_Interp.h new file mode 100644 index 000000000..e68d0d909 --- /dev/null +++ b/src/PyInterp/PyInterp_Interp.h @@ -0,0 +1,106 @@ +// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// File : PyInterp_Interp.h +// Author : Christian CAREMOLI, Paul RASCLE, EDF +// Module : SALOME + +#ifndef PYINTERP_INTERP_H +#define PYINTERP_INTERP_H + +#include "PyInterp.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!! + +#include +#include + +class PYINTERP_EXPORT PyLockWrapper +{ + PyThreadState* myThreadState; + PyThreadState* mySaveThreadState; + PyGILState_STATE _savestate; +public: + PyLockWrapper(PyThreadState* theThreadState); + ~PyLockWrapper(); +}; + +class PYINTERP_EXPORT PyInterp_Interp +{ +public: + static int _argc; + static char* _argv[]; + static PyObject *builtinmodule; + static PyThreadState *_gtstate; + static PyInterpreterState *_interp; + + PyInterp_Interp(); + virtual ~PyInterp_Interp(); + + void initialize(); + + virtual int run(const char *command); + + PyLockWrapper GetLockWrapper(); + + std::string getbanner(); + std::string getverr(); + std::string getvout(); + + const char * getPrevious(); + const char * getNext(); + +protected: + PyThreadState * _tstate; + PyObject * _vout; + PyObject * _verr; + PyObject * _g; + PyObject * _codeop; + std::list _history; + std::list::iterator _ith; + + virtual int beforeRun() { return 0; } + int simpleRun(const char* command, const bool addToHistory = true); + + virtual bool initRun(); + virtual void initPython(); + virtual bool initState() = 0; + virtual bool initContext() = 0; +}; + +class PYINTERP_EXPORT PyObjWrapper +{ + PyObject* myObject; +public: + PyObjWrapper(PyObject* theObject) : myObject(theObject) {} + PyObjWrapper() : myObject(0) {} + virtual ~PyObjWrapper() { Py_XDECREF(myObject); } + + operator PyObject*() { return myObject; } + PyObject* operator->() { return myObject; } + PyObject* get() { return myObject; } + bool operator!() { return !myObject; } + bool operator==(PyObject* theObject) { return myObject == theObject; } + PyObject** operator&() { return &myObject; } + PyObjWrapper& operator=(PyObjWrapper* theObjWrapper) + { + Py_XDECREF(myObject); + myObject = theObjWrapper->myObject; + return *this; + } +}; + +#endif // PYINTERP_INTERP_H diff --git a/src/PyInterp/PyInterp_Watcher.h b/src/PyInterp/PyInterp_Watcher.h index 551eca7d0..1d50f5bf8 100755 --- a/src/PyInterp/PyInterp_Watcher.h +++ b/src/PyInterp/PyInterp_Watcher.h @@ -16,14 +16,18 @@ // // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -#ifndef _PYINTERP_WATCHER_H_ -#define _PYINTERP_WATCHER_H_ +// File : PyInterp_Watcher.h +// Author : Sergey Anikin, OCC +// Module : SALOME -#include +#ifndef PYINTERP_WATCHER_H +#define PYINTERP_WATCHER_H -#include +#include "PyInterp.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!! -#include +#include "PyInterp_Dispatcher.h" + +#include // Private class that keeps track of destructions of request listeners class PYINTERP_EXPORT PyInterp_Watcher : public QObject @@ -38,4 +42,4 @@ public slots: void onDestroyed( QObject* o ) { PyInterp_Dispatcher::Get()->objectDestroyed( o ); } }; -#endif // _PYINTERP_WATCHER_H_ +#endif // PYINTERP_WATCHER_H diff --git a/src/PyInterp/PyInterp_base.cxx b/src/PyInterp/PyInterp_base.cxx deleted file mode 100644 index 7225855fe..000000000 --- a/src/PyInterp/PyInterp_base.cxx +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License. -// -// This library is distributed in the hope that it will be useful -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// -// SALOME SALOMEGUI : implementation of desktop and GUI kernel -// -// File : PyInterp_base.cxx -// Author : Christian CAREMOLI, Paul RASCLE, EDF -// Module : SALOME -// $Header$ - - -#include -#include - -#include "PyInterp_base.h" // this include must be first (see PyInterp_base.h)! -#include - -using namespace std; - -PyLockWrapper::PyLockWrapper(PyThreadState* theThreadState): - myThreadState(theThreadState), - mySaveThreadState(0) -{ -#if defined(USE_GILSTATE) - if (myThreadState->interp == PyInterp_base::_interp) { - _savestate = PyGILState_Ensure(); - } else { - PyEval_AcquireThread(myThreadState); - } -#else - PyEval_AcquireThread(myThreadState); -#endif -} - -PyLockWrapper::~PyLockWrapper() -{ -#if defined(USE_GILSTATE) - if (myThreadState->interp == PyInterp_base::_interp) { - PyGILState_Release(_savestate); - } else { - PyEval_ReleaseThread(myThreadState); - } -#else - PyEval_ReleaseThread(myThreadState); -#endif -} - -class PyReleaseLock{ -public: - ~PyReleaseLock(){ - PyEval_ReleaseLock(); - } -}; - - -PyLockWrapper PyInterp_base::GetLockWrapper(){ - return _tstate; -} - - -// main python interpreter (static attributes) - -int PyInterp_base::_argc = 1; -char* PyInterp_base::_argv[] = {""}; - -PyObject *PyInterp_base::builtinmodule = NULL; - -PyThreadState *PyInterp_base::_gtstate = NULL; -PyInterpreterState *PyInterp_base::_interp = NULL; - - -/*! - * basic constructor here : herited classes constructors must call initalize() method - * defined here. - */ -PyInterp_base::PyInterp_base(): _tstate(0), _vout(0), _verr(0), _g(0), _atFirst(true) -{ -} - -PyInterp_base::~PyInterp_base() -{ -} - - -/*! - * Must be called by herited classes constructors. initialize() calls virtuals methods - * initstate & initcontext, not defined here in base class. initstate & initcontext methods - * must be implemented in herited classes, following the Python interpreter policy - * (mono or multi interpreter...). - */ -void PyInterp_base::initialize() -{ - _history.clear(); // start a new list of user's commands - _ith = _history.begin(); - - init_python(); - // Here the global lock is released - - initState(); - - PyLockWrapper aLock= GetLockWrapper(); - - initContext(); - - // used to interpret & compile commands - PyObjWrapper m(PyImport_ImportModule("codeop")); - if(!m){ - PyErr_Print(); - return; - } - - // Create cStringIO to capture stdout and stderr - PycString_IMPORT; - if (PycStringIO) { // CTH11627 : additional check - _vout = PycStringIO->NewOutput(128); - _verr = PycStringIO->NewOutput(128); - } - - // All the initRun outputs are redirected to the standard output (console) - initRun(); -} - -void PyInterp_base::init_python() -{ - _atFirst = false; - if (Py_IsInitialized()) - return; - - // Python is not initialized - Py_SetProgramName(_argv[0]); - Py_Initialize(); // Initialize the interpreter - PySys_SetArgv(_argc, _argv); - PyEval_InitThreads(); // Create (and acquire) the interpreter lock - _interp = PyThreadState_Get()->interp; - _gtstate = PyEval_SaveThread(); // Release global thread state -} - -string PyInterp_base::getbanner() -{ - // Should we take the lock ? - // PyEval_RestoreThread(_tstate); - string aBanner("Python "); - aBanner = aBanner + Py_GetVersion() + " on " + Py_GetPlatform() ; - aBanner = aBanner + "\ntype help to get general information on environment\n"; - //PyEval_SaveThread(); - return aBanner; -} - - -int PyInterp_base::initRun() -{ - PySys_SetObject("stderr",_verr); - PySys_SetObject("stdout",_vout); - - PyObjWrapper verr(PyObject_CallMethod(_verr,"reset","")); - PyObjWrapper vout(PyObject_CallMethod(_vout,"reset","")); - - //PyObject *m = PyImport_GetModuleDict(); - - PySys_SetObject("stdout",PySys_GetObject("__stdout__")); - PySys_SetObject("stderr",PySys_GetObject("__stderr__")); - - return 0; -} - - -/*! - * This function compiles a string (command) and then evaluates it in the dictionnary - * context if possible. - * Returns : - * -1 : fatal error - * 1 : incomplete text - * 0 : complete text executed with success - */ -int compile_command(const char *command,PyObject *context) -{ - PyObject *m = PyImport_AddModule("codeop"); - if(!m){ // Fatal error. No way to go on. - PyErr_Print(); - return -1; - } - PyObjWrapper v(PyObject_CallMethod(m,"compile_command","s",command)); - if(!v){ - // Error encountered. It should be SyntaxError, - //so we don't write out traceback - PyObjWrapper exception, value, tb; - PyErr_Fetch(&exception, &value, &tb); - PyErr_NormalizeException(&exception, &value, &tb); - PyErr_Display(exception, value, NULL); - return -1; - }else if (v == Py_None){ - // Incomplete text we return 1 : we need a complete text to execute - return 1; - }else{ - // Complete and correct text. We evaluate it. - //#if PY_VERSION_HEX < 0x02040000 // python version earlier than 2.4.0 - // PyObjWrapper r(PyEval_EvalCode(v,context,context)); - //#else - PyObjWrapper r(PyEval_EvalCode((PyCodeObject *)(void *)v,context,context)); - //#endif - if(!r){ - // Execution error. We return -1 - PyErr_Print(); - return -1; - } - // The command has been successfully executed. Return 0 - return 0; - } -} - - -int PyInterp_base::run(const char *command) -{ - if(_atFirst){ - int ret = 0; - ret = simpleRun("from Help import *"); - if (ret) { - _atFirst = false; - return ret; - } - ret = simpleRun("import salome"); - if (ret) { - _atFirst = false; - return ret; - } - ret = simpleRun("salome.salome_init(0,1)"); - if (ret) { - _atFirst = false; - return ret; - } - _atFirst = false; - } - return simpleRun(command); -} - - -int PyInterp_base::simpleRun(const char *command) -{ - if( !_atFirst && strcmp(command,"") != 0 ) { - _history.push_back(command); - _ith = _history.end(); - } - - // We come from C++ to enter Python world - // We need to acquire the Python global lock - //PyLockWrapper aLock(_tstate); // san - lock is centralized now - - // Reset redirected outputs before treatment - PySys_SetObject("stderr",_verr); - PySys_SetObject("stdout",_vout); - - PyObjWrapper verr(PyObject_CallMethod(_verr,"reset","")); - PyObjWrapper vout(PyObject_CallMethod(_vout,"reset","")); - - int ier = compile_command(command,_g); - - // Outputs are redirected on standards outputs (console) - PySys_SetObject("stdout",PySys_GetObject("__stdout__")); - PySys_SetObject("stderr",PySys_GetObject("__stderr__")); - - return ier; -} - - -const char * PyInterp_base::getPrevious() -{ - if(_ith != _history.begin()){ - _ith--; - return (*_ith).c_str(); - } - else - return BEGIN_HISTORY_PY; -} - - -const char * PyInterp_base::getNext() -{ - if(_ith != _history.end()){ - _ith++; - } - if (_ith == _history.end()) - return TOP_HISTORY_PY; - else - return (*_ith).c_str(); -} - - -string PyInterp_base::getverr(){ - //PyLockWrapper aLock(_tstate); - PyObjWrapper v(PycStringIO->cgetvalue(_verr)); - string aRet(PyString_AsString(v)); - return aRet; -} - - -string PyInterp_base::getvout(){ - //PyLockWrapper aLock(_tstate); - PyObjWrapper v(PycStringIO->cgetvalue(_vout)); - string aRet(PyString_AsString(v)); - return aRet; -} diff --git a/src/PyInterp/PyInterp_base.h b/src/PyInterp/PyInterp_base.h deleted file mode 100644 index 71931655c..000000000 --- a/src/PyInterp/PyInterp_base.h +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (C) 2005 OPEN CASCADE, CEA/DEN, EDF R&D, PRINCIPIA R&D -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License. -// -// This library is distributed in the hope that it will be useful -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -// -// SALOME SALOMEGUI : implementation of desktop and GUI kernel -// -// File : PyInterp_base.h -// Author : Christian CAREMOLI, Paul RASCLE, EDF -// Module : SALOME - -#ifndef _PYINTERP_BASE_H_ -#define _PYINTERP_BASE_H_ - -#include "PyInterp.h" - -#include -#include -#include - -// include order important! -// pthread then python then qt -//#include // must be before Python.h ! - -#include // must be before qt includes ... -#include // Python include needed for versions before 2.4. Included in Python.h now. -#include // Python include needed for versions before 2.4. Included in Python.h now. - -//#if PY_VERSION_HEX < 0x02040000 // python version earlier than 2.4.0 -//extern "C" PyObject * PyEval_EvalCode(PyObject *co, PyObject *g, PyObject *l); -//#endif - -/* For 2.3, use the PyGILState_ calls */ -#if (PY_VERSION_HEX >= 0x02030000) -#define USE_GILSTATE -#endif - -#define TOP_HISTORY_PY "--- top of history ---" -#define BEGIN_HISTORY_PY "--- begin of history ---" - -class PYINTERP_EXPORT PyLockWrapper -{ - PyThreadState* myThreadState; - PyThreadState* mySaveThreadState; -#if defined(USE_GILSTATE) - PyGILState_STATE _savestate ; -#endif - public: - PyLockWrapper(PyThreadState* theThreadState); - ~PyLockWrapper(); -}; - -class PYINTERP_EXPORT PyInterp_base{ - public: - static int _argc; - static char* _argv[]; - static PyObject *builtinmodule; - static PyThreadState *_gtstate; - static PyInterpreterState *_interp; - - PyInterp_base(); - ~PyInterp_base(); - - virtual void initialize(); - virtual void init_python(); - // init_python() made virtual to: - // 1. Remove dependency on KERNEL in light SALOME configuration - // 2. Allow redefinition of this method in SalomeApp_PyInterp class (it should be empty there and rely on KERNEL_PYTHON) - - virtual int run(const char *command); - - PyLockWrapper GetLockWrapper(); - - std::string getbanner(); - std::string getverr(); - std::string getvout(); - - const char * getPrevious(); - const char * getNext(); - - protected: - PyThreadState * _tstate; - PyObject * _vout; - PyObject * _verr; - PyObject * _g; - PyObject * _codeop; - std::list _history; - std::list::iterator _ith; - bool _atFirst; - - int simpleRun(const char* command); - int initRun(); - - virtual bool initState() = 0; - virtual bool initContext() = 0; -}; - - -class PYINTERP_EXPORT PyObjWrapper{ - PyObject* myObject; -public: - PyObjWrapper(PyObject* theObject): myObject(theObject) {} - PyObjWrapper(): myObject(0) {} - operator PyObject*(){ - return myObject; - } - PyObject* operator->(){ - return myObject; - } - PyObject* get(){ - return myObject; - } - bool operator!(){ - return !myObject; - } - bool operator==(PyObject* theObject){ - return myObject == theObject; - } - PyObject** operator&(){ - return &myObject; - } - PyObjWrapper& operator=(PyObjWrapper* theObjWrapper){ - Py_XDECREF(myObject); - myObject = theObjWrapper->myObject; - return *this; - } - virtual ~PyObjWrapper(){ - Py_XDECREF(myObject); - } -}; - -#endif