]> SALOME platform Git repositories - modules/gui.git/blob - src/Session/SALOME_Session_Server.cxx
Salome HOME
ENV: Windows porting
[modules/gui.git] / src / Session / SALOME_Session_Server.cxx
1 // SALOME Session : implementation of Session.idl
2 //
3 // Copyright (C) 2003 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
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.
10 //
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.
15 //
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
19 //
20 // See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
21 //
22 //
23 //
24 // File : SALOME_Session_Server.cxx
25 // Author : Paul RASCLE, EDF
26 // Module : SALOME
27
28 #include <Container_init_python.hxx>
29 #include "Utils_ORB_INIT.hxx"
30 #include "Utils_SINGLETON.hxx"
31 #include "SALOME_NamingService.hxx"
32 #include "SALOMETraceCollector.hxx"
33
34 #include "InquireServersQThread.h" // splash
35
36 #include <iostream>
37 #ifndef WNT
38 #include <unistd.h>
39 #endif
40
41 #include <qdir.h>
42 #include <qfile.h>
43 #include <qapplication.h>
44 #include <qwaitcondition.h>
45
46 #include "Utils_SALOME_Exception.hxx"
47 #include "Utils_CorbaException.hxx"
48 #include "SALOME_Event.hxx"
49
50 #include <SALOMEconfig.h>
51 #include CORBA_SERVER_HEADER(SALOME_Session)
52 #include CORBA_SERVER_HEADER(SALOMEDS)
53
54 #include <utilities.h>
55 #include "Session_Session_i.hxx"
56 #include "Session_ServerLauncher.hxx"
57
58 #include "SUIT_Tools.h"
59 #include "SUIT_Session.h"
60 #include "SUIT_Application.h"
61 #include "SUIT_MessageBox.h"
62
63 #include "SUIT_ExceptionHandler.h"
64
65 extern "C" int HandleSignals( QApplication *theQApplication );
66
67 /*! - read arguments, define list of server to launch with their arguments.
68  * - wait for naming service
69  * - create and run a thread for launch of all servers
70  *
71 */
72
73 //! CORBA server for SALOME Session
74 /*!
75  * SALOME_Session Server launches a SALOME session servant.
76  * The servant registers to the Naming Service.
77  * See SALOME_Session.idl for interface specification.
78  *
79  * Main services offered by the servant are:
80  * - launch GUI
81  * - stop Session ( must be idle )
82  * - get session state
83  */
84
85 QString salomeVersion()
86 {
87   QString path( ::getenv( "GUI_ROOT_DIR" ) );
88   if ( !path.isEmpty() )
89     path += QDir::separator();
90   path += QString( "bin/salome/VERSION" );
91
92   QFile vf( path );
93   if ( !vf.open( IO_ReadOnly ) )
94     return QString::null;
95
96   QString line;
97   vf.readLine( line, 1024 );
98   vf.close();
99
100   if ( line.isEmpty() )
101     return QString::null;
102
103   while ( !line.isEmpty() && line.at( line.length() - 1 ) == QChar( '\n' ) )
104     line.remove( line.length() - 1, 1 );
105
106   QString ver;
107   int idx = line.findRev( ":" );
108   if ( idx != -1 )
109     ver = line.mid( idx + 1 ).stripWhiteSpace();
110
111   return ver;
112 }
113
114 PyObject* salome_shared_modules_module = 0;
115
116 void MessageOutput( QtMsgType type, const char* msg )
117 {
118   switch ( type )
119   {
120   case QtDebugMsg:
121     MESSAGE( "Debug: " << msg );
122     break;
123   case QtWarningMsg:
124     MESSAGE( "Warning: " << msg );
125     break;
126   case QtFatalMsg:
127     MESSAGE( "Fatal: " << msg );
128     break;
129   }
130 }
131
132 /* XPM */
133 static const char* pixmap_not_found_xpm[] = {
134 "16 16 3 1",
135 "       c None",
136 ".      c #000000",
137 "+      c #A80000",
138 "                ",
139 "                ",
140 "    .     .     ",
141 "   .+.   .+.    ",
142 "  .+++. .+++.   ",
143 "   .+++.+++.    ",
144 "    .+++++.     ",
145 "     .+++.      ",
146 "    .+++++.     ",
147 "   .+++.+++.    ",
148 "  .+++. .+++.   ",
149 "   .+.   .+.    ",
150 "    .     .     ",
151 "                ",
152 "                ",
153 "                "};
154
155 class SALOME_Session : public SUIT_Session
156 {
157 public:
158   SALOME_Session() : SUIT_Session() {}
159   virtual ~SALOME_Session() {}
160
161 protected:
162   virtual SUIT_ResourceMgr* createResourceMgr( const QString& appName ) const
163   {
164     SUIT_ResourceMgr* resMgr = new SUIT_ResourceMgr( appName, QString( "%1Config" ) );
165     resMgr->setVersion( salomeVersion() );
166     resMgr->setCurrentFormat( "xml" );
167     resMgr->setOption( "translators", QString( "%P_msg_%L.qm|%P_icons.qm|%P_images.qm" ) );
168     static QPixmap defaultPixmap( pixmap_not_found_xpm );
169     resMgr->setDefaultPixmap( defaultPixmap );
170     return resMgr;
171   }
172 };
173
174 class SALOME_QApplication : public QApplication
175 {
176 public:
177   SALOME_QApplication( int& argc, char** argv ) : QApplication( argc, argv ), myHandler ( 0 ) {}
178
179   virtual bool notify( QObject* receiver, QEvent* e )
180   {
181     return myHandler ? myHandler->handle( receiver, e ) :
182       QApplication::notify( receiver, e );
183   }
184   SUIT_ExceptionHandler* handler() const { return myHandler; }
185   void setHandler( SUIT_ExceptionHandler* h ) { myHandler = h; }
186
187 private:
188   SUIT_ExceptionHandler* myHandler;
189 };
190
191 // class which calls SALOME::Session::GetInterface() from another thread
192 // to avoid mutual lock ( if called from the same thread as main()
193 class GetInterfaceThread : public QThread
194 {
195 public:
196   GetInterfaceThread( SALOME::Session_var s ) : session ( s ) {}
197 protected:
198   virtual void run()
199   {
200     if ( !CORBA::is_nil( session ) )
201       session->GetInterface();
202     else
203       printf( "\nFATAL ERROR: SALOME::Session object is nil! Can not display GUI\n\n" );
204   }
205 private:
206   SALOME::Session_var session;
207 };
208
209 // returns true if 'str' is found in argv
210 bool isFound( const char* str, int argc, char** argv )
211 {
212   for ( int i = 1; i <= ( argc-1 ); i++ )
213     if ( !strcmp( argv[i], str ) )
214       return true;
215   return false;
216 }
217
218 // ---------------------------- MAIN -----------------------
219 int main( int argc, char **argv )
220 {
221   qInstallMsgHandler( MessageOutput );
222
223   // QApplication should be create before all other operations
224   // When uses QApplication::libraryPaths() ( example, QFile::encodeName() )
225   // qApp used for detection of the executable dir path.
226   SALOME_QApplication _qappl( argc, argv );
227   ASSERT( QObject::connect( &_qappl, SIGNAL( lastWindowClosed() ), &_qappl, SLOT( quit() ) ) );
228
229   QString path = QDir::convertSeparators( SUIT_Tools::addSlash( QString( ::getenv( "GUI_ROOT_DIR" ) ) ) + QString( "bin/salome" ) );
230   _qappl.addLibraryPath( path );
231   
232   _qappl.setStyle( "salome" );
233
234   int result = -1;
235
236   CORBA::ORB_var orb;
237   PortableServer::POA_var poa;
238
239   SUIT_Session* aGUISession = 0;
240   SALOME_NamingService* _NS = 0;
241   GetInterfaceThread* guiThread = 0;
242   SALOMETraceCollector* myThreadTrace = 0;
243   Session_ServerLauncher* myServerLauncher = 0;
244
245   try {
246     
247     // Python initialisation : only once
248
249     int _argc = 1;
250     char* _argv[] = {""};
251     KERNEL_PYTHON::init_python( _argc,_argv );
252     PyEval_RestoreThread( KERNEL_PYTHON::_gtstate );
253     if ( !KERNEL_PYTHON::salome_shared_modules_module ) // import only once
254       KERNEL_PYTHON::salome_shared_modules_module = PyImport_ImportModule( "salome_shared_modules" );
255     if ( !KERNEL_PYTHON::salome_shared_modules_module )
256     {
257       INFOS( "salome_shared_modules_module == NULL" );
258       PyErr_Print();
259       PyErr_Clear();
260     }
261     PyEval_ReleaseThread( KERNEL_PYTHON::_gtstate );
262
263     // Create ORB, get RootPOA object, NamingService, etc.
264     ORB_INIT &init = *SINGLETON_<ORB_INIT>::Instance();
265     ASSERT( SINGLETON_<ORB_INIT>::IsAlreadyExisting() );
266     int orbArgc = 1;
267     orb = init( orbArgc, argv );
268     myThreadTrace = SALOMETraceCollector::instance( orb );
269
270     // Install SALOME thread event handler
271     SALOME_Event::GetSessionThread();
272
273     CORBA::Object_var obj = orb->resolve_initial_references( "RootPOA" );
274     poa = PortableServer::POA::_narrow( obj );
275
276     PortableServer::POAManager_var pman = poa->the_POAManager();
277     pman->activate() ;
278     INFOS( "pman->activate()" );
279
280     _NS = new SALOME_NamingService( orb );
281
282     result = 0;
283   }
284   catch ( SALOME_Exception& e ) {
285     INFOS( "run(): SALOME::SALOME_Exception is caught: "<<e.what() );
286   }
287   catch ( CORBA::SystemException& e ) {
288     INFOS( "Caught CORBA::SystemException." );
289   }
290   catch ( CORBA::Exception& e ) {
291     INFOS( "Caught CORBA::Exception." );
292     CORBA::Any tmp;
293     tmp<<= e;
294     CORBA::TypeCode_var tc = tmp.type();
295     const char *p = tc->name();
296     INFOS ( "run(): CORBA exception of the kind : "<<p<< " is caught" );
297   }
298   catch ( exception& e ) {
299     INFOS( "run(): An exception has been caught: " <<e.what() );
300   }
301   catch (...) {
302     INFOS( "Caught unknown exception." );
303   }
304
305   // CORBA Servant Launcher
306   QMutex _GUIMutex;
307   QWaitCondition _ServerLaunch, _SessionStarted;
308
309   if ( !result )
310   {
311     _GUIMutex.lock();  // to block Launch server thread until wait( mutex )
312
313     // Activate embedded CORBA servers: Registry, SALOMEDS, etc.
314     myServerLauncher = new Session_ServerLauncher( argc, argv, orb, poa, &_GUIMutex, &_ServerLaunch, &_SessionStarted );
315     myServerLauncher->start();
316
317     _ServerLaunch.wait( &_GUIMutex ); // to be reseased by Launch server thread when ready:
318     
319     // show splash screen if "SPLASH" parameter was passed ( default )
320     if ( isFound( "SPLASH", argc, argv ) )
321     {
322       // create temporary resource manager just to load splash icon
323       SUIT_ResourceMgr resMgr( "SalomeApp", QString( "%1Config" ) );
324       resMgr.setVersion( salomeVersion() );
325       resMgr.setCurrentFormat( "xml" );
326       resMgr.loadLanguage( "SalomeApp", "en" );
327
328       // create splash object: widget ( splash with progress bar ) and "pinging" thread
329       InquireServersGUI splash;
330       splash.setPixmap( resMgr.loadPixmap( "SalomeApp", QObject::tr( "ABOUT" ) ) );
331       SUIT_Tools::centerWidget( &splash, _qappl.desktop() );
332       
333       _qappl.setMainWidget( &splash );
334       QObject::connect( &_qappl, SIGNAL( lastWindowClosed() ), &_qappl, SLOT( quit() ) );
335       splash.show(); // display splash with running progress bar
336       _qappl.exec(); // wait untill splash closes ( progress runs till end or Cancel is pressed )
337       
338       result = splash.getExitStatus(); // 1 is error
339     }
340     else
341       _SessionStarted.wait();
342   }
343
344   // call Session::GetInterface() if "GUI" parameter was passed ( default )
345   if ( !result && isFound( "GUI", argc, argv ) )
346   {
347     CORBA::Object_var obj = _NS->Resolve( "/Kernel/Session" );
348     SALOME::Session_var session = SALOME::Session::_narrow( obj ) ;
349     ASSERT ( ! CORBA::is_nil( session ) );
350
351     INFOS( "Session activated, Launch IAPP..." );
352     guiThread = new GetInterfaceThread( session );
353     guiThread->start();
354   }
355
356   if ( !result )
357   {
358
359     // GUI activation
360     // Allow multiple activation/deactivation of GUI
361     while ( true )
362     {
363       MESSAGE( "waiting wakeAll()" );
364       _ServerLaunch.wait( &_GUIMutex ); // to be reseased by Launch server thread when ready:
365       // atomic operation lock - unlock on mutex
366       // unlock mutex: serverThread runs, calls _ServerLaunch->wakeAll()
367       // this thread wakes up, and lock mutex
368
369       _GUIMutex.unlock();
370
371       // SUIT_Session creation
372       aGUISession = new SALOME_Session();
373
374       // Load SalomeApp dynamic library
375       INFOS( "creation SUIT_Application" );
376       SUIT_Application* aGUIApp = aGUISession->startApplication( "SalomeApp", 0, 0 );
377       if ( aGUIApp )
378       {
379         _qappl.setHandler( aGUISession->handler() ); // after loading SalomeApp application
380                                                      // aGUISession contains SalomeApp_ExceptionHandler
381         // Run GUI loop
382         MESSAGE( "run(): starting the main event loop" );
383         result = _qappl.exec();
384
385         if ( result == SUIT_Session::FROM_GUI ) // desktop is closed by user from GUI
386           break;
387       }
388
389       delete aGUISession;
390       aGUISession = 0;
391
392       // Prepare _GUIMutex for a new GUI activation
393       _GUIMutex.lock();
394     }
395   }
396
397   if ( myServerLauncher )
398     myServerLauncher->KillAll(); // kill embedded servers
399
400   delete aGUISession;
401   delete guiThread;
402   delete myServerLauncher;
403   delete _NS;
404   delete myThreadTrace;
405
406   return result;
407 }