]> SALOME platform Git repositories - modules/gui.git/blob - src/Session/SALOME_Session_Server.cxx
Salome HOME
Join modifications from BR_Dev_For_4_0 tag V4_1_1.
[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.salome-platform.org/ or email : webmaster.salome@opencascade.com
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 "SALOME_ModuleCatalog_impl.hxx"
35 #include "OpUtil.hxx"
36 #include "RegistryService.hxx"
37 #include "ConnectionManager_i.hxx"
38
39 #include <iostream>
40 #ifndef WNT
41 #include <unistd.h>
42 #include <iostream.h>
43 #include <string.h>
44 #endif
45
46 #include <qdir.h>
47 #include <qfile.h>
48 #include <qapplication.h>
49 #include <qwaitcondition.h>
50 #include <qregexp.h>
51
52 #include "Utils_SALOME_Exception.hxx"
53 #include "Utils_CorbaException.hxx"
54 #include "SALOME_Event.hxx"
55
56 #include <SALOMEconfig.h>
57 #include CORBA_SERVER_HEADER(SALOME_Session)
58 #include CORBA_SERVER_HEADER(SALOMEDS)
59
60 #include <utilities.h>
61 #include "Session_Session_i.hxx"
62 #include "Session_ServerLauncher.hxx"
63 #include "Session_ServerCheck.hxx"
64
65 #include <QtxSplash.h>
66 #include "SUIT_Tools.h"
67 #include "SUIT_Session.h"
68 #include "SUIT_Application.h"
69 #include "SUIT_Desktop.h"
70 #include "SUIT_MessageBox.h"
71 #include "SUIT_ResourceMgr.h"
72 #include "SUIT_ExceptionHandler.h"
73
74 /*! - read arguments, define list of server to launch with their arguments.
75  * - wait for naming service
76  * - create and run a thread for launch of all servers
77  *
78 */
79
80 //! CORBA server for SALOME Session
81 /*!
82  * SALOME_Session Server launches a SALOME session servant.
83  * The servant registers to the Naming Service.
84  * See SALOME_Session.idl for interface specification.
85  *
86  * Main services offered by the servant are:
87  * - launch GUI
88  * - stop Session ( must be idle )
89  * - get session state
90  */
91
92 PyObject* salome_shared_modules_module = 0;
93
94 void MessageOutput( QtMsgType type, const char* msg )
95 {
96   switch ( type )
97   {
98   case QtDebugMsg:
99     MESSAGE( "Debug: " << msg );
100     break;
101   case QtWarningMsg:
102     MESSAGE( "Warning: " << msg );
103     break;
104   case QtFatalMsg:
105     MESSAGE( "Fatal: " << msg );
106     break;
107   }
108 }
109
110 /* XPM */
111 static const char* pixmap_not_found_xpm[] = {
112 "16 16 3 1",
113 "       c None",
114 ".      c #000000",
115 "+      c #A80000",
116 "                ",
117 "                ",
118 "    .     .     ",
119 "   .+.   .+.    ",
120 "  .+++. .+++.   ",
121 "   .+++.+++.    ",
122 "    .+++++.     ",
123 "     .+++.      ",
124 "    .+++++.     ",
125 "   .+++.+++.    ",
126 "  .+++. .+++.   ",
127 "   .+.   .+.    ",
128 "    .     .     ",
129 "                ",
130 "                ",
131 "                "};
132
133 QString salomeVersion()
134 {
135   QString path( ::getenv( "GUI_ROOT_DIR" ) );
136   if ( !path.isEmpty() )
137     path += QDir::separator();
138   path += QString( "bin/salome/VERSION" );
139
140   QFile vf( path );
141   if ( !vf.open( IO_ReadOnly ) )
142     return QString::null;
143
144   QString line;
145   vf.readLine( line, 1024 );
146   vf.close();
147
148   if ( line.isEmpty() )
149     return QString::null;
150
151   while ( !line.isEmpty() && line.at( line.length() - 1 ) == QChar( '\n' ) )
152     line.remove( line.length() - 1, 1 );
153
154   QString ver;
155   int idx = line.findRev( ":" );
156   if ( idx != -1 )
157     ver = line.mid( idx + 1 ).stripWhiteSpace();
158
159   return ver;
160 }
161
162 class SALOME_ResourceMgr : public SUIT_ResourceMgr
163 {
164 public:
165   SALOME_ResourceMgr( const QString& app, const QString& resVarTemplate ) : SUIT_ResourceMgr( app, resVarTemplate )
166   {
167     setCurrentFormat( "xml" );
168     setOption( "translators", QString( "%P_msg_%L.qm|%P_icons.qm|%P_images.qm" ) );
169     setDefaultPixmap( QPixmap( pixmap_not_found_xpm ) );
170   }
171   static void initResourceMgr()
172   {
173     if ( myExtAppName.isNull() || myExtAppVersion.isNull() ) {
174       SALOME_ResourceMgr resMgr( "SalomeApp", QString( "%1Config" ) );
175       resMgr.loadLanguage( "LightApp",  "en" );
176       resMgr.loadLanguage( "SalomeApp", "en" );
177
178       myExtAppName = QObject::tr( "APP_NAME" ).stripWhiteSpace();
179       if ( myExtAppName == "APP_NAME" || myExtAppName.lower() == "salome" ) 
180         myExtAppName = "SalomeApp";
181       myExtAppVersion = QObject::tr( "APP_VERSION" );
182       if ( myExtAppVersion == "APP_VERSION" ) {
183         if ( myExtAppName != "SalomeApp" )
184           myExtAppVersion = "";
185         else myExtAppVersion = salomeVersion();
186       }
187     }
188   }
189   QString version() const { return myExtAppVersion; }
190
191 protected:
192   QString userFileName( const QString& appName, const bool for_load ) const
193   { 
194     if ( version().isNull()  ) return ""; 
195     return SUIT_ResourceMgr::userFileName( myExtAppName, for_load );
196   }
197
198   virtual int userFileId( const QString& _fname ) const
199   {
200     if ( !myExtAppName.isEmpty() ) {
201       QRegExp exp( QString( "\\.%1rc\\.([a-zA-Z0-9.]+)$" ).arg( myExtAppName ) );
202       QRegExp vers_exp( "^([0-9]+)([A-Za-z]?)([0-9]*)$" );
203       
204       QString fname = QFileInfo( _fname ).fileName();
205       if( exp.exactMatch( fname ) ) {
206         QStringList vers = QStringList::split( ".", exp.cap( 1 ) );
207         int major=0, minor=0;
208         major = vers[0].toInt();
209         minor = vers[1].toInt();
210         if( vers_exp.search( vers[2] )==-1 )
211           return -1;
212         int release = 0, dev1 = 0, dev2 = 0;
213         release = vers_exp.cap( 1 ).toInt();
214         dev1 = vers_exp.cap( 2 )[ 0 ].latin1();
215         dev2 = vers_exp.cap( 3 ).toInt();
216         
217         int dev = dev1*100+dev2, id = major;
218         id*=100; id+=minor;
219         id*=100; id+=release;
220         id*=10000;
221         if ( dev > 0 ) id+=dev-10000;
222         return id;
223       }
224     }
225
226     return -1;
227   }
228
229 public:
230   static QString myExtAppName;
231   static QString myExtAppVersion;
232 };
233
234 QString SALOME_ResourceMgr::myExtAppName    = QString::null;
235 QString SALOME_ResourceMgr::myExtAppVersion = QString::null;
236
237 class SALOME_Session : public SUIT_Session
238 {
239 public:
240   SALOME_Session() : SUIT_Session() {}
241   virtual ~SALOME_Session() {}
242
243 protected:
244   virtual SUIT_ResourceMgr* createResourceMgr( const QString& appName ) const
245   {
246     SALOME_ResourceMgr::initResourceMgr();
247     SALOME_ResourceMgr* resMgr = new SALOME_ResourceMgr( appName, QString( "%1Config" ) );
248     return resMgr;
249   }
250 };
251
252 class SALOME_QApplication : public QApplication
253 {
254 public:
255   SALOME_QApplication( int& argc, char** argv ) : QApplication( argc, argv ), myHandler ( 0 ) {}
256
257   virtual bool notify( QObject* receiver, QEvent* e )
258   {
259 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) < 0x060101
260     // Disable GUI user actions while python command is executed
261     if (SUIT_Session::IsPythonExecuted()) {
262       // Disable mouse and keyboard events
263       QEvent::Type aType = e->type();
264       if (aType == QEvent::MouseButtonPress || aType == QEvent::MouseButtonRelease ||
265           aType == QEvent::MouseButtonDblClick || aType == QEvent::MouseMove ||
266           aType == QEvent::Wheel || aType == QEvent::ContextMenu ||
267           aType == QEvent::KeyPress || aType == QEvent::KeyRelease ||
268           aType == QEvent::Accel || aType == QEvent::AccelOverride)
269         return false;
270     }
271 #endif
272
273     return myHandler ? myHandler->handle( receiver, e ) :
274       QApplication::notify( receiver, e );
275   }
276   SUIT_ExceptionHandler* handler() const { return myHandler; }
277   void setHandler( SUIT_ExceptionHandler* h ) { myHandler = h; }
278
279 private:
280   SUIT_ExceptionHandler* myHandler;
281 };
282
283 // class which calls SALOME::Session::GetInterface() from another thread
284 // to avoid mutual lock ( if called from the same thread as main()
285 class GetInterfaceThread : public QThread
286 {
287 public:
288   GetInterfaceThread( SALOME::Session_var s ) : session ( s )
289   {
290     start();
291   }
292 protected:
293   virtual void run()
294   {
295     if ( !CORBA::is_nil( session ) )
296       session->GetInterface();
297     else
298       printf( "\nFATAL ERROR: SALOME::Session object is nil! Can not display GUI\n\n" );
299   }
300 private:
301   SALOME::Session_var session;
302 };
303
304 // returns true if 'str' is found in argv
305 bool isFound( const char* str, int argc, char** argv )
306 {
307   for ( int i = 1; i <= ( argc-1 ); i++ )
308     if ( !strcmp( argv[i], str ) )
309       return true;
310   return false;
311 }
312
313 void killOmniNames()
314 {
315     QString fileName( ::getenv ("OMNIORB_CONFIG") );
316     QString portNumber;
317     if ( !fileName.isEmpty() ) 
318     {
319       QFile aFile( fileName );
320       if ( aFile.open(IO_ReadOnly) ) {
321         QRegExp re("InitRef = .*:([0-9]+)$");
322         QTextStream stream ( &aFile );
323         while ( !stream.atEnd() ) {
324           QString textLine = stream.readLine();
325           if ( re.search( textLine ) > -1 )
326             portNumber = re.cap(1);
327         }
328         aFile.close();
329       }
330     }
331
332     if ( !portNumber.isEmpty() ) 
333     {
334       QString cmd ;
335       cmd = QString( "ps -eo pid,command | grep -v grep | grep -E \"omniNames.*%1\" | awk '{cmd=sprintf(\"kill -9 %s\",$1); system(cmd)}'" ).arg( portNumber );
336       system ( cmd.latin1() );
337     }
338
339     /////////////////// NPAL 18309  (Kill Notifd) ////////////////////////////
340     if ( !portNumber.isEmpty() ) 
341     {
342       QString cmd = QString("import pickle, os; ");
343       cmd += QString("from killSalomeWithPort import getPiDict; ");
344       cmd += QString("filedict=getPiDict(%1); ").arg(portNumber);
345       cmd += QString("f=open(filedict, 'r'); ");
346       cmd += QString("pids=pickle.load(f); ");
347       cmd += QString("m={}; ");
348       cmd += QString("[ m.update(i) for i in pids ]; ");
349       cmd += QString("pids=filter(lambda a: 'notifd' in m[a], m.keys()); ");
350       cmd += QString("[ os.kill(pid, 9) for pid in pids ]; ");
351       cmd += QString("os.remove(filedict); ");
352       cmd  = QString("python -c \"%1\" > /dev/null").arg(cmd);
353       system( cmd.latin1() );
354     }
355
356 }
357
358 // shutdown standalone servers
359 void shutdownServers( SALOME_NamingService* theNS )
360 {
361   // get each Container from NamingService => shutdown it
362   // (the order is inverse to the order of servers initialization)
363   
364   CORBA::Object_var objS = theNS->Resolve("/Kernel/Session");
365   SALOME::Session_var session = SALOME::Session::_narrow(objS);
366   if (!CORBA::is_nil(session)) {
367     session->ping();
368     
369     string hostname = GetHostname();
370     //string containerName = "/Containers/" + hostname;
371     
372     // 1) SuperVisionContainer
373     //string containerNameSV = containerName + "/SuperVisionContainer";
374     //CORBA::Object_var objSV = theNS->Resolve(containerNameSV.c_str());
375     //Engines::Container_var SVcontainer = Engines::Container::_narrow(objSV) ;
376     //if ( !CORBA::is_nil(SVcontainer) && ( session->getPID() != SVcontainer->getPID() ) )
377     //  SVcontainer->Shutdown();
378     
379     // 2) FactoryServerPy
380     //string containerNameFSP = containerName + "/FactoryServerPy";
381     //CORBA::Object_var objFSP = theNS->Resolve(containerNameFSP.c_str());
382     //Engines::Container_var FSPcontainer = Engines::Container::_narrow(objFSP) ;
383     //if ( !CORBA::is_nil(FSPcontainer) && ( session->getPID() != FSPcontainer->getPID() ) )
384     //  FSPcontainer->Shutdown();
385     
386     // 3) FactoryServer
387     //string containerNameFS = containerName + "/FactoryServer";
388     //CORBA::Object_var objFS = theNS->Resolve(containerNameFS.c_str());
389     //Engines::Container_var FScontainer = Engines::Container::_narrow(objFS) ;
390     //if ( !CORBA::is_nil(FScontainer) && ( session->getPID() != FScontainer->getPID() ) )
391     //  FScontainer->Shutdown();
392     
393     // 4) ContainerManager
394     //CORBA::Object_var objCM=theNS->Resolve("/ContainerManager");
395     //Engines::ContainerManager_var contMan=Engines::ContainerManager::_narrow(objCM);
396     //if ( !CORBA::is_nil(contMan) && ( session->getPID() != contMan->getPID() ) )
397     //  contMan->ShutdownWithExit();
398
399     // 4) SalomeLauncher
400     CORBA::Object_var objSL = theNS->Resolve("/SalomeLauncher");
401     Engines::SalomeLauncher_var launcher = Engines::SalomeLauncher::_narrow(objSL);
402     if (!CORBA::is_nil(launcher) && (session->getPID() != launcher->getPID()))
403       launcher->Shutdown();
404
405     // 5) ConnectionManager
406     CORBA::Object_var objCnM=theNS->Resolve("/ConnectionManager");
407     Engines::ConnectionManager_var connMan=Engines::ConnectionManager::_narrow(objCnM);
408     if ( !CORBA::is_nil(connMan) && ( session->getPID() != connMan->getPID() ) )
409       connMan->ShutdownWithExit();
410     
411     // 6) SALOMEDS
412     CORBA::Object_var objSDS = theNS->Resolve("/myStudyManager");
413     SALOMEDS::StudyManager_var studyManager = SALOMEDS::StudyManager::_narrow(objSDS) ;
414     if ( !CORBA::is_nil(studyManager) && ( session->getPID() != studyManager->getPID() ) )
415       studyManager->Shutdown();
416     
417     // 7) ModuleCatalog
418     CORBA::Object_var objMC=theNS->Resolve("/Kernel/ModulCatalog");
419     SALOME_ModuleCatalog::ModuleCatalog_var catalog = SALOME_ModuleCatalog::ModuleCatalog::_narrow(objMC);
420     if ( !CORBA::is_nil(catalog) && ( session->getPID() != catalog->getPID() ) )
421       catalog->shutdown();
422     
423     // 8) Registry
424     CORBA::Object_var objR = theNS->Resolve("/Registry");
425     Registry::Components_var registry = Registry::Components::_narrow(objR);
426     if ( !CORBA::is_nil(registry) && ( session->getPID() != registry->getPID() ) )
427       registry->Shutdown();
428     
429     // 9) Kill OmniNames
430     //killOmniNames();
431   }
432 }
433
434 // ---------------------------- MAIN -----------------------
435 int main( int argc, char **argv )
436 {
437   // Install Qt debug messages handler
438   qInstallMsgHandler( MessageOutput );
439   
440   // Create Qt application instance;
441   // this should be done the very first!
442   SALOME_QApplication _qappl( argc, argv );
443   ASSERT( QObject::connect( &_qappl, SIGNAL( lastWindowClosed() ), &_qappl, SLOT( quit() ) ) );
444
445   // Add application library path (to search style plugin etc...)
446   QString path = QDir::convertSeparators( SUIT_Tools::addSlash( QString( ::getenv( "GUI_ROOT_DIR" ) ) ) + QString( "bin/salome" ) );
447   _qappl.addLibraryPath( path );
448   
449   // Set SALOME style to the application
450   _qappl.setStyle( "salome" );
451
452   bool isGUI    = isFound( "GUI",    argc, argv );
453   bool isSplash = isFound( "SPLASH", argc, argv );
454   // Show splash screen (only if both the "GUI" and "SPLASH" parameters are set)
455   QtxSplash* splash = 0;
456   if ( isGUI && isSplash ) {
457     // ...create resource manager
458     SUIT_ResourceMgr resMgr( "SalomeApp", QString( "%1Config" ) );
459     resMgr.setCurrentFormat( "xml" );
460     resMgr.loadLanguage( "LightApp", "en" );
461     // ...get splash preferences
462     QString splashIcon;
463     resMgr.value( "splash", "image", splashIcon );
464     QPixmap px( splashIcon );
465     if ( px.isNull() ) // try to get splash pixmap from resources
466       px = resMgr.loadPixmap( "LightApp", QObject::tr( "ABOUT_SPLASH" ) );
467     if ( !px.isNull() ) {
468       // ...set splash pixmap
469       splash = QtxSplash::splash( px );
470       // ... set margin
471       int splashMargin;
472       if ( resMgr.value( "splash", "margin", splashMargin ) && splashMargin > 0 ) {
473         splash->setMargin( splashMargin );
474       }
475       // ...set splash text colors
476       QString splashTextColors;
477       if ( resMgr.value( "splash", "text_colors", splashTextColors ) && !splashTextColors.isEmpty() ) {
478         QStringList colors = QStringList::split( "|", splashTextColors );
479         QColor c1, c2;
480         if ( colors.count() > 0 ) c1 = QColor( colors[0] );
481         if ( colors.count() > 1 ) c2 = QColor( colors[1] );
482         splash->setTextColors( c1, c2 );
483       }
484       else {
485         splash->setTextColors( Qt::white, Qt::black );
486       }
487       // ...set splash progress colors
488       QString splashProgressColors;
489       if ( resMgr.value( "splash", "progress_colors", splashProgressColors ) && !splashProgressColors.isEmpty() ) {
490         QStringList colors = QStringList::split( "|", splashProgressColors );
491         QColor c1, c2;
492         int gradType = QtxSplash::Vertical;
493         if ( colors.count() > 0 ) c1 = QColor( colors[0] );
494         if ( colors.count() > 1 ) c2 = QColor( colors[1] );
495         if ( colors.count() > 2 ) gradType = colors[2].toInt();
496         splash->setProgressColors( c1, c2, gradType );
497       }
498       // ...set splash text font
499       QFont f = splash->font();
500       f.setBold( true );
501       splash->setFont( f );
502       // ...show splash initial status
503       QString splashInfo;
504       if ( resMgr.value( "splash", "info", splashInfo, false ) && !splashInfo.isEmpty() ) {
505         splashInfo.replace( QRegExp( "%A" ),  QObject::tr( "APP_NAME" ) );
506         splashInfo.replace( QRegExp( "%V" ),  QObject::tr( "ABOUT_VERSION" ).arg( salomeVersion() ) );
507         splashInfo.replace( QRegExp( "%L" ),  QObject::tr( "ABOUT_LICENSE" ) );
508         splashInfo.replace( QRegExp( "%C" ),  QObject::tr( "ABOUT_COPYRIGHT" ) );
509         splashInfo.replace( QRegExp( "\\\\n" ), "\n" );
510         splash->message( splashInfo );
511       }
512       // ...set 'hide on click' flag
513 #ifdef _DEBUG_
514       splash->setHideOnClick( true );
515 #endif
516       // ...show splash
517       splash->show();
518       qApp->processEvents();
519     }
520   }
521
522   // Initialization
523   int result = -1;
524
525   CORBA::ORB_var orb;
526   PortableServer::POA_var poa;
527
528   SUIT_Session* aGUISession = 0;
529   SALOME_NamingService* _NS = 0;
530   GetInterfaceThread* guiThread = 0;
531   Session_ServerLauncher* myServerLauncher = 0;
532
533   try {
534     // ...initialize Python (only once)
535     int   _argc   = 1;
536     char* _argv[] = {""};
537     KERNEL_PYTHON::init_python( _argc,_argv );
538     PyEval_RestoreThread( KERNEL_PYTHON::_gtstate );
539     if ( !KERNEL_PYTHON::salome_shared_modules_module ) // import only once
540       KERNEL_PYTHON::salome_shared_modules_module = PyImport_ImportModule( "salome_shared_modules" );
541     if ( !KERNEL_PYTHON::salome_shared_modules_module ) {
542       INFOS( "salome_shared_modules_module == NULL" );
543       PyErr_Print();
544     }
545     PyEval_ReleaseThread( KERNEL_PYTHON::_gtstate );
546
547     // ...create ORB, get RootPOA object, NamingService, etc.
548     ORB_INIT &init = *SINGLETON_<ORB_INIT>::Instance();
549     ASSERT( SINGLETON_<ORB_INIT>::IsAlreadyExisting() );
550     int orbArgc = 1;
551     orb = init( orbArgc, argv );
552
553     // ...install SALOME thread event handler
554     SALOME_Event::GetSessionThread();
555
556     CORBA::Object_var obj = orb->resolve_initial_references( "RootPOA" );
557     poa = PortableServer::POA::_narrow( obj );
558
559     PortableServer::POAManager_var pman = poa->the_POAManager();
560     pman->activate() ;
561     MESSAGE( "pman->activate()" );
562
563     _NS = new SALOME_NamingService( orb );
564
565     result = 0;
566   }
567   catch ( SALOME_Exception& e ) {
568     INFOS( "run(): SALOME::SALOME_Exception is caught: "<<e.what() );
569   }
570   catch ( CORBA::SystemException& e ) {
571     INFOS( "Caught CORBA::SystemException." );
572   }
573   catch ( CORBA::Exception& e ) {
574     INFOS( "Caught CORBA::Exception." );
575     CORBA::Any tmp;
576     tmp<<= e;
577     CORBA::TypeCode_var tc = tmp.type();
578     const char *p = tc->name();
579     INFOS ( "run(): CORBA exception of the kind : "<<p<< " is caught" );
580   }
581   catch ( exception& e ) {
582     INFOS( "run(): An exception has been caught: " <<e.what() );
583   }
584   catch (...) {
585     INFOS( "Caught unknown exception." );
586   }
587
588   QMutex _GUIMutex, _SessionMutex, _SplashMutex;
589   QWaitCondition _ServerLaunch, _SessionStarted, _SplashStarted;
590
591   // lock session mutex to ensure that GetInterface is not called
592   // until all initialization is done
593   _SessionMutex.lock();
594
595   if ( !result ) {
596     // Start embedded servers launcher (Registry, SALOMEDS, etc.)
597     // ...lock mutex to block embedded servers launching thread until wait( mutex )
598     _GUIMutex.lock();  
599     // ...create launcher
600     myServerLauncher = new Session_ServerLauncher( argc, argv, orb, poa, &_GUIMutex, &_ServerLaunch, &_SessionMutex, &_SessionStarted );
601     // ...block this thread until launcher is ready
602     _ServerLaunch.wait( &_GUIMutex );
603     
604     // Start servers check thread (splash)
605     if ( splash ) {
606       // ...lock mutex to block splash thread until wait( mutex )
607       _SplashMutex.lock();
608       // ...create servers checking thread
609       Session_ServerCheck sc( &_SplashMutex, &_SplashStarted );
610       // ...block this thread until servers checking is finished
611       _SplashStarted.wait( &_SplashMutex );
612       // ...unlock mutex 'cause it is no more needed
613       _SplashMutex.unlock();
614       // get servers checking thread status
615       result = splash->error();
616       QString info = splash->message().isEmpty() ? "%1" : QString( "%1\n%2" ).arg( splash->message() );
617       splash->setStatus( info.arg( "Activating desktop..." ) );
618     }
619
620     // Finalize embedded servers launcher 
621     // ...block this thread until launcher is finished
622     _ServerLaunch.wait( &_GUIMutex );
623     // ...unlock mutex 'cause it is no more needed
624     _GUIMutex.unlock();
625   }
626
627   bool shutdown = false;
628   if ( !result ) {
629     // Launch GUI activator
630     if ( isGUI ) {
631       // ...retrieve Session interface reference
632       CORBA::Object_var obj = _NS->Resolve( "/Kernel/Session" );
633       SALOME::Session_var session = SALOME::Session::_narrow( obj ) ;
634       ASSERT ( ! CORBA::is_nil( session ) );
635       // ...create GUI launcher
636       MESSAGE( "Session activated, Launch IAPP..." );
637       guiThread = new GetInterfaceThread( session );
638     }
639
640     // GUI activation
641     // Allow multiple activation/deactivation of GUI
642     while ( true ) {
643       MESSAGE( "waiting wakeAll()" );
644       _SessionStarted.wait( &_SessionMutex ); // to be reseased by Launch server thread when ready:
645       // atomic operation lock - unlock on mutex
646       // unlock mutex: serverThread runs, calls _ServerLaunch->wakeAll()
647       // this thread wakes up, and lock mutex
648
649       _SessionMutex.unlock();
650
651       // SUIT_Session creation
652       aGUISession = new SALOME_Session();
653
654       // Load SalomeApp dynamic library
655       MESSAGE( "creation SUIT_Application" );
656       SUIT_Application* aGUIApp = aGUISession->startApplication( "SalomeApp", 0, 0 );
657       if ( aGUIApp )
658       {
659         if ( !isFound( "noexcepthandler", argc, argv ) )
660           _qappl.setHandler( aGUISession->handler() ); // after loading SalomeApp application
661                                                        // aGUISession contains SalomeApp_ExceptionHandler
662         // Run GUI loop
663         MESSAGE( "run(): starting the main event loop" );
664
665         if ( splash )
666           splash->finish( aGUIApp->desktop() );
667           
668         result = _qappl.exec();
669         
670         if ( splash )
671           delete splash;
672         splash = 0;
673
674         if ( result == SUIT_Session::NORMAL ) { // desktop is closed by user from GUI
675           shutdown = aGUISession->exitFlags();
676           break;
677         }
678       }
679
680       delete aGUISession;
681       aGUISession = 0;
682
683       // Prepare _GUIMutex for a new GUI activation
684       _SessionMutex.lock();
685     }
686   }
687
688   // unlock Session mutex
689   _SessionMutex.unlock();
690   
691   if ( shutdown )
692     shutdownServers( _NS );
693
694   if ( myServerLauncher )
695     myServerLauncher->KillAll(); // kill embedded servers
696
697   delete aGUISession;
698   delete guiThread;
699   delete myServerLauncher;
700   delete _NS;
701
702   PyGILState_STATE gstate = PyGILState_Ensure();
703   Py_Finalize();
704
705   try 
706     {
707       orb->destroy();
708     }
709   catch(...) 
710     {
711       //////////////////////////////////////////////////////////////
712       // VSR: silently skip exception:
713       // CORBA.BAD_INV_ORDER.BAD_INV_ORDER_ORBHasShutdown 
714       // exception is raised when orb->destroy() is called and
715       // cpp continer is launched in the embedded mode
716       //////////////////////////////////////////////////////////////
717       // std::cerr << "Caught unexpected exception on destroy : ignored !!" << std::endl;
718     }
719
720   if ( shutdown )
721     killOmniNames();
722
723   return result;
724 }