1 // SALOME Session : implementation of Session.idl
3 // Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
24 // File : SALOME_Session_Server.cxx
25 // Author : Paul RASCLE, EDF
29 #include <Container_init_python.hxx>
30 #include "Utils_ORB_INIT.hxx"
31 #include "Utils_SINGLETON.hxx"
32 #include "SALOME_NamingService.hxx"
33 #include "SALOMETraceCollector.hxx"
35 #include "InquireServersQThread.h" // splash
42 #include <qapplication.h>
43 #include <qwaitcondition.h>
45 #include "Utils_SALOME_Exception.hxx"
46 #include "Utils_CorbaException.hxx"
47 #include "SALOME_Event.hxx"
49 #include <SALOMEconfig.h>
50 #include CORBA_SERVER_HEADER(SALOME_Session)
51 #include CORBA_SERVER_HEADER(SALOMEDS)
53 #include <utilities.h>
54 #include "Session_Session_i.hxx"
55 #include "Session_ServerLauncher.hxx"
57 #include "SUIT_Session.h"
58 #include "SUIT_Application.h"
59 #include "SUIT_MessageBox.h"
60 #include "SUIT_Tools.h"
63 #include "SUIT_ExceptionHandler.h"
66 extern "C" int HandleSignals(QApplication *theQApplication);
68 /*! - read arguments, define list of server to launch with their arguments.
69 * - wait for naming service
70 * - create and run a thread for launch of all servers
74 //! CORBA server for SALOME Session
76 * SALOME_Session Server launches a SALOME session servant.
77 * The servant registers to the Naming Service.
78 * See SALOME_Session.idl for interface specification.
80 * Main services offered by the servant are:
82 * - stop Session (must be idle)
86 QString salomeVersion()
88 QString path( ::getenv( "GUI_ROOT_DIR" ) );
89 if ( !path.isEmpty() )
90 path += QDir::separator();
91 path += QString( "bin/salome/VERSION" );
94 if ( !vf.open( IO_ReadOnly ) )
98 vf.readLine( line, 1024 );
101 if ( line.isEmpty() )
102 return QString::null;
104 while ( !line.isEmpty() && line.at( line.length() - 1 ) == QChar( '\n' ) )
105 line.remove( line.length() - 1, 1 );
108 int idx = line.findRev( ":" );
110 ver = line.mid( idx + 1 ).stripWhiteSpace();
115 PyObject *salome_shared_modules_module = NULL;
117 void MessageOutput( QtMsgType type, const char *msg )
121 MESSAGE( "Debug: " << msg );
124 MESSAGE( "Warning: " << msg );
127 MESSAGE( "Fatal: " << msg );
132 class SALOME_Session : public SUIT_Session
135 SALOME_Session() : SUIT_Session() {}
136 virtual ~SALOME_Session() {}
139 virtual SUIT_ResourceMgr* createResourceMgr( const QString& appName ) const
141 SUIT_ResourceMgr* resMgr = new SUIT_ResourceMgr( appName, QString( "%1Config" ) );
142 resMgr->setVersion( salomeVersion() );
143 resMgr->setCurrentFormat( "xml" );
144 resMgr->setOption( "translators", QString( "%P_msg_%L.qm|%P_icons.qm|%P_images.qm" ) );
149 class SALOME_QApplication : public QApplication
152 SALOME_QApplication( int& argc, char** argv ) : QApplication( argc, argv )
157 virtual bool notify( QObject* receiver, QEvent* e )
159 return myHandler ? myHandler->handle( receiver, e ) :
160 QApplication::notify( receiver, e );
162 SUIT_ExceptionHandler* handler() const { return myHandler; }
163 void setHandler( SUIT_ExceptionHandler* h ) { myHandler = h; }
166 SUIT_ExceptionHandler* myHandler;
169 // class which calls SALOME::Session::GetInterface() from another thread
170 // to avoid mutual lock (if called from the same thread as main()
171 class GetInterfaceThread : public QThread
174 GetInterfaceThread( SALOME::Session_var s ) : session ( s ) {}
178 if ( !CORBA::is_nil( session ) )
179 session->GetInterface();
181 printf( "\nFATAL ERROR: SALOME::Session object is nil! Can not display GUI\n\n" );
184 SALOME::Session_var session;
187 // returns true if 'str' is found in argv
188 bool isFound( const char* str, int argc, char** argv )
190 for ( int i = 1; i <= (argc-1); i++ )
191 if ( !strcmp( argv[i], str ) )
196 // ---------------------------- MAIN -----------------------
197 int main(int argc, char **argv)
199 qInstallMsgHandler( MessageOutput );
201 // QApplication should be create before all other operations
202 // When uses QApplication::libraryPaths() (example, QFile::encodeName())
203 // qApp used for detection of the executable dir path.
204 SALOME_QApplication _qappl( argc, argv );
205 ASSERT( QObject::connect(&_qappl, SIGNAL( lastWindowClosed() ), &_qappl, SLOT( quit() ) ) );
206 QString path( ::getenv( "GUI_ROOT_DIR" ) );
207 if ( !path.isEmpty() )
208 path += QDir::separator();
209 path += QString( "bin/salome" );
210 _qappl.addLibraryPath( path );
211 _qappl.setStyle( "salome" );
214 Python initialisation : only once
218 char* _argv[] = {""};
219 KERNEL_PYTHON::init_python(_argc,_argv);
220 PyEval_RestoreThread(KERNEL_PYTHON::_gtstate);
221 if ( !KERNEL_PYTHON::salome_shared_modules_module ) // import only once
223 KERNEL_PYTHON::salome_shared_modules_module =
224 PyImport_ImportModule("salome_shared_modules");
226 if ( !KERNEL_PYTHON::salome_shared_modules_module )
228 INFOS("salome_shared_modules_module == NULL");
232 PyEval_ReleaseThread(KERNEL_PYTHON::_gtstate);
236 // 1. create ORB, get RootPOA object, NamingService, etc.
237 ORB_INIT &init = *SINGLETON_<ORB_INIT>::Instance() ;
238 ASSERT(SINGLETON_<ORB_INIT>::IsAlreadyExisting()) ;
240 CORBA::ORB_var &orb = init( orbArgc , argv ) ;
241 SALOMETraceCollector *myThreadTrace = SALOMETraceCollector::instance(orb);
242 GetInterfaceThread* guiThread = 0;
246 SALOME_Event::GetSessionThread();
248 CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
249 PortableServer::POA_var poa = PortableServer::POA::_narrow(obj);
251 PortableServer::POAManager_var pman = poa->the_POAManager() ;
253 INFOS("pman->activate()");
255 SALOME_NamingService *_NS = new SALOME_NamingService(orb);
257 // CORBA Servant Launcher
259 QWaitCondition _ServerLaunch, _SessionStarted;
260 _GUIMutex.lock(); // to block Launch server thread until wait(mutex)
262 // 2. activate embedded CORBA servers: Registry, SALOMEDS, etc.
263 Session_ServerLauncher* myServerLauncher
264 = new Session_ServerLauncher(argc, argv, orb, poa, &_GUIMutex, &_ServerLaunch, &_SessionStarted);
265 myServerLauncher->start();
267 _ServerLaunch.wait(&_GUIMutex); // to be reseased by Launch server thread when ready
269 // show splash screen if "SPLASH" parameter was passed (default)
270 if ( isFound( "SPLASH", argc, argv ) )
272 // create temporary resource manager just to load splash icon
273 SUIT_ResourceMgr resMgr( "SalomeApp", QString( "%1Config" ) );
274 resMgr.setVersion( salomeVersion() );
275 resMgr.setCurrentFormat( "xml" );
276 resMgr.loadLanguage( "SalomeApp", "en" );
277 // create splash object: widget (splash with progress bar) and "pinging" thread
278 InquireServersGUI splash;
279 splash.setPixmap( resMgr.loadPixmap( "SalomeApp", QObject::tr( "ABOUT" ) ) );
280 SUIT_Tools::centerWidget( &splash, _qappl.desktop() );
282 _qappl.setMainWidget( &splash );
283 QObject::connect( &_qappl, SIGNAL( lastWindowClosed() ), &_qappl, SLOT( quit() ) );
284 splash.show(); // display splash with running progress bar
285 _qappl.exec(); // wait untill splash closes (progress runs till end or Cancel is pressed)
291 if ( splash.getExitStatus() ) // 1 is error
292 exit( splash.getExitStatus() ); // quit applicaiton
295 _SessionStarted.wait();
297 // call Session::GetInterface() if "GUI" parameter was passed (default)
298 if ( isFound( "GUI", argc, argv ) )
300 CORBA::Object_var obj = _NS->Resolve("/Kernel/Session");
301 SALOME::Session_var session = SALOME::Session::_narrow( obj ) ;
302 ASSERT (! CORBA::is_nil( session ) );
304 INFOS("Session activated, Launch IAPP...");
305 guiThread = new GetInterfaceThread( session );
310 // Allow multiple activation/deactivation of GUI
313 MESSAGE("waiting wakeAll()");
314 _ServerLaunch.wait(&_GUIMutex); // to be reseased by Launch server thread when ready:
315 // atomic operation lock - unlock on mutex
316 // unlock mutex: serverThread runs, calls _ServerLaunch->wakeAll()
317 // this thread wakes up, and lock mutex
321 // 3.1 SUIT_Session creation
322 SUIT_Session* aGUISession = new SALOME_Session();
323 INFOS("creation SUIT_Application");
328 // T2.12 - catch exceptions thrown on attempts to modified a locked study
329 MESSAGE("run(): starting the main event loop");
331 // 3.2 load SalomeApp dynamic library
332 SUIT_Application* aGUIApp = aGUISession->startApplication( "SalomeApp", 0, 0 );
335 _qappl.setHandler( aGUISession->handler() ); // after loading SalomeApp application
336 // aGUISession contains SalomeApp_ExceptionHandler
337 result = _qappl.exec();
339 if ( result == SUIT_Session::FROM_GUI ) // desktop is closed by user from GUI
343 // Prepare _GUIMutex for a new GUI activation
348 myServerLauncher->KillAll(); // kill embedded servers
350 catch (SALOME_Exception& e)
352 INFOS("run(): SALOME::SALOME_Exception is caught: "<<e.what());
354 catch (CORBA::SystemException& e)
356 INFOS("Caught CORBA::SystemException.");
358 catch (CORBA::Exception& e)
360 INFOS("Caught CORBA::Exception.");
363 CORBA::TypeCode_var tc = tmp.type();
364 const char *p = tc->name();
365 INFOS ("run(): CORBA exception of the kind : "<<p<< " is caught");
369 INFOS("run(): An exception has been caught: " <<e.what());
373 INFOS("Caught unknown exception.");
375 delete myThreadTrace;