Salome HOME
On ajoute YACS a salome2810
[modules/gui.git] / src / Session / SALOME_Session_Server.cxx
1 // Copyright (C) 2007-2021  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  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, or (at your option) any later version.
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 #include <Container_init_python.hxx> // this include must be the first one as it includes Python.h
24 #include <Basics_Utils.hxx>
25 #include <ConnectionManager_i.hxx>
26 #include <OpUtil.hxx>
27 #include <RegistryService.hxx>
28 #include <SALOME_LifeCycleCORBA.hxx>
29 #include <SALOME_ModuleCatalog_impl.hxx>
30 #include <SALOME_NamingService.hxx>
31 #include <Utils_CorbaException.hxx>
32 #include <Utils_ORB_INIT.hxx>
33 #include <Utils_SALOME_Exception.hxx>
34 #include <Utils_SINGLETON.hxx>
35 #include <utilities.h>
36 #include "KernelBasis.hxx"
37
38 #include "Session_Session_i.hxx"
39 #include "Session_ServerCheck.hxx"
40 #include "Session_ServerLauncher.hxx"
41 #include "Session_Promises.hxx"
42 #include "Session_NS_wrapper.hxx"
43
44 #include "GUI_version.h"
45 #include "Qtx.h"
46 #include "QtxMsgHandler.h"
47 #include "QtxSplash.h"
48 #include "SALOME_Event.h"
49 #ifdef USE_SALOME_STYLE
50 #include "Style_Salome.h"
51 #endif // USE_SALOME_STYLE
52 #include "SUIT_Application.h"
53 #include "SUIT_Desktop.h"
54 #include "SUIT_ExceptionHandler.h"
55 #include "SUIT_ResourceMgr.h"
56 #include "SUIT_Session.h"
57 #include "SUIT_Tools.h"
58
59 #include <SALOMEconfig.h>
60 #include CORBA_SERVER_HEADER(SALOME_Session)
61 #include CORBA_SERVER_HEADER(SALOMEDS)
62
63 #ifdef WIN32
64 #define sleep _sleep
65 #include <windows.h>
66 #include <stdio.h>
67 #include <shellapi.h>
68 #endif
69 #include <time.h>
70 #include <memory>
71
72 #include <QApplication>
73 #include <QDir>
74 #include <QFile>
75 #include <QMutex>
76 #include <QRegExp>
77 #include <QTextStream>
78 #include <QWaitCondition>
79
80 //! CORBA server for SALOME GUI 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  * Main services offered by the servant are:
86  * - launch GUI
87  * - stop Session ( must be idle )
88  * - get session state
89  *
90  * Also, session server:
91  * - reads arguments,
92  * - defines list of embedded services to launch with their arguments,
93  * - defines list of standalone services to connect/wait,
94  * - waits for naming service to finish its initalization,
95  * - creates and runs a separate thread to launch/initialize all services.
96  */
97
98 namespace
99 {
100   std::string handleCorbaException(const CORBA::Exception &e)
101   {
102     std::string message;
103     CORBA::Any tmp;
104     tmp <<= e;
105     CORBA::TypeCode_var tc = tmp.type();
106     message += tc->name();
107     return message;
108   }
109
110   //! Custom handler to manage Qt messages
111   class MsgHandler : public QtxMsgHandlerCallback
112   {
113   public:
114     MsgHandler() {}
115     void qtMessage(QtMsgType type, const QMessageLogContext & /*context*/, const QString &message)
116     {
117       (void)message; // unused in debug mode
118       switch (type)
119       {
120       case QtDebugMsg:
121 #ifdef QT_DEBUG_MESSAGE
122         MESSAGE("Debug: " << qPrintable(message));
123 #endif
124         break;
125       case QtWarningMsg:
126         MESSAGE("Warning: " << qPrintable(message));
127         break;
128       case QtCriticalMsg:
129         MESSAGE("Critical: " << qPrintable(message));
130         break;
131       case QtFatalMsg:
132         MESSAGE("Fatal: " << qPrintable(message));
133         break;
134       case QtInfoMsg:
135       default:
136         MESSAGE("Information: " << qPrintable(message));
137         break;
138       }
139     }
140   };
141
142   //! Get version of SALOME GUI module
143   QString salomeVersion()
144   {
145     return GUI_VERSION_STR;
146   }
147
148   //! Custom resources manager, that allows customization of application name/version
149   //  via configuration/translation files.
150   class ResourceMgr : public SUIT_ResourceMgr
151   {
152   public:
153     ResourceMgr(const QString &appName = "SalomeApp") : SUIT_ResourceMgr(appName, "%1Config")
154     {
155       customize(); // activate customization
156       setCurrentFormat("xml");
157       setOption("translators", QString("%P_msg_%L.qm|%P_icons.qm|%P_images.qm"));
158     }
159
160     QString customName() const { return myCustomAppName; }
161     QString version() const { return myCustomAppVersion; }
162
163   private:
164     static void customize()
165     {
166       // Try to retrieve actual application name and version from translation files.
167       // We create temporary resource manager and load LightApp and SalomeApp translations.
168       // This procedure is supposed to be done only once, at first call.
169       if (myCustomAppName.isNull())
170       {
171         SUIT_ResourceMgr mgr("SalomeApp", "%1Config");
172         mgr.setCurrentFormat("xml");
173         mgr.setWorkingMode(IgnoreUserValues); // prevent reading data from user's file
174         mgr.loadLanguage("LightApp", "en");
175         mgr.loadLanguage("SalomeApp", "en");
176
177         // actual application name can be customized via APP_NAME resource key
178         myCustomAppName = QObject::tr("APP_NAME").trimmed();
179         if (myCustomAppName == "APP_NAME" || myCustomAppName.toLower() == "salome")
180           myCustomAppName = "SalomeApp"; // fallback name
181
182         // actual application name can be customized via APP_VERSION resource key
183         myCustomAppVersion = QObject::tr("APP_VERSION").trimmed();
184         if (myCustomAppVersion == "APP_VERSION")
185           myCustomAppVersion = myCustomAppName == "SalomeApp" ? salomeVersion() : ""; // fallback version
186       }
187     }
188
189   protected:
190     QString userFileName(const QString & /*appName*/, const bool forLoad) const
191     {
192       if (version().isEmpty())
193         return "";
194       return SUIT_ResourceMgr::userFileName(myCustomAppName, forLoad);
195     }
196
197     virtual long userFileId(const QString &_fname) const
198     {
199       //////////////////////////////////////////////////////////////////////////////////////////////
200       // In SALOME and SALOME-based applications the user preferences file is named as
201       // - <AppName>.xml.<AppVersion> on Windows
202       // - <AppName>rc.<AppVersion> on Linux
203       // where
204       //   * AppName is application name, defaults to SalomeApp. Can be customized in SALOME-based
205       //     applications, see ResourceMgr above for more details.
206       //   * AppVersion is application version, defaults to current version of SALOME GUI module
207       //     if AppName is not customize, otherwise empty. Can be customized in SALOME-based
208       //     applications, see ResourceMgr above for more details.
209       //
210       // Since version 6.5.0 of SALOME, user file is stored in the ~/.config/salome
211       // directory. For backward compatibility, when user preferences from nearest
212       // version of application is searched, user home directory is also looked through,
213       // with lower priority.
214       //
215       // Since version 6.6.0 of SALOME, user file name on Linux is no more prefixed by dot
216       // symbol since it is stored in the hidden ~/.config/salome directory. However, dot-prefixed
217       // files are also taken into account (with lower priority) for backward compatibility.
218       //
219       // Notes:
220       // - Currently the following format of version number is supported:
221       //   <major>[.<minor>[.<release>[<type><dev>]]]
222       //   Parts in square brackets are considered optional. Here:
223       //   * major   - major version id
224       //   * minor   - minor version id
225       //   * release - maintenance version id
226       //   * type    - dev or patch marker; it can be either one alphabetical symbol (from 'a' to 'z')
227       //               or 'rc' to point release candidate (case-insensitive)
228       //   * dev     - dev version or patch number
229       //   All numerical values must be of range [1-99].
230       //   Examples: 1.0, 6.5.0, 1.2.0a1, 3.3.3rc3 (release candidate 3), 11.0.0p1 (patch 1)
231       //
232       // - Versioning approach can be customized by implementing and using own resource manager class,
233       //   see QtxResurceMgr, SUIT_ResourceMgr classes, and ResourceMgr class above in this file.
234       //////////////////////////////////////////////////////////////////////////////////////////////
235
236       long id = -1;
237       if (!myCustomAppName.isEmpty())
238       {
239 #ifdef WIN32
240         // On Windows, user file name is something like SalomeApp.xml.6.5.0 where
241         // - SalomeApp is an application name (can be customized)
242         // - xml is a file format (xml or ini)
243         // - 6.5.0 is an application version, can include alfa/beta/rc marks, e.g. 6.5.0a3, 6.5.0rc1
244         QRegExp exp(QString("%1\\.%2\\.([a-zA-Z0-9.]+)").arg(myCustomAppName).arg(currentFormat()));
245 #else
246         // On Linux, user file name is something like SalomeApprc.6.5.0 where
247         // - SalomeApp is an application name (can be customized)
248         // - 6.5.0 is an application version, can include alfa/beta/rc marks, e.g. 6.5.0a3, 6.5.0rc1
249
250         // VSR 24/09/2012: issue 0021781: since version 6.6.0 user filename is not prepended with "."
251         // when it is stored in the ~/.config/<appname> directory;
252         // for backward compatibility we also check files prepended with "." with lower priority
253         QRegExp exp(QString("\\.?%1rc\\.([a-zA-Z0-9.]+)").arg(myCustomAppName));
254 #endif
255         QString fname = QFileInfo(_fname).fileName();
256         if (exp.exactMatch(fname))
257         {
258           long fid = Qtx::versionToId(exp.cap(1));
259           if (fid > 0)
260             id = fid;
261         }
262       }
263       return id;
264     }
265
266   private:
267     static QString myCustomAppName;
268     static QString myCustomAppVersion;
269   };
270   QString ResourceMgr::myCustomAppName;
271   QString ResourceMgr::myCustomAppVersion;
272
273   //! Custom session, to use custom resource manager class.
274   class Session : public SUIT_Session
275   {
276   public:
277     virtual SUIT_ResourceMgr *createResourceMgr(const QString &appName) const
278     {
279       return new ResourceMgr(appName);
280     }
281   };
282
283   //! Custom QApplication class, redefines notify() method, to transfer all events
284   //  via centralized exception handling mechanism.
285   class Application : public QApplication
286   {
287   public:
288     Application(int &argc, char **argv)
289         : QApplication(argc, argv),
290           myHandler(0)
291     {
292       myDebug = !Qtx::getenv("SALOME_DEBUG_EXCEPTIONS").isEmpty();
293     }
294
295     virtual bool notify(QObject *receiver, QEvent *e)
296     {
297       if (myDebug || !myHandler)
298       {
299         return QApplication::notify(receiver, e);
300       }
301       else
302       {
303         try
304         {
305           return myHandler->handle(receiver, e);
306         }
307         catch (std::exception &e)
308         {
309           std::cerr << "notify(): Caught exception : " << e.what() << std::endl;
310         }
311         catch (CORBA::Exception &e)
312         {
313           std::cerr << "notify(): Caught CORBA exception : " << handleCorbaException(e) << std::endl;
314         }
315         catch (...)
316         {
317           std::cerr << "notify(): Caught unknown exception : there's probably a bug in SALOME platform" << std::endl;
318         }
319         return false; // return false when exception is caught
320       }
321     }
322
323     SUIT_ExceptionHandler *handler() const { return myHandler; }
324     void setHandler(SUIT_ExceptionHandler *h) { myHandler = h; }
325
326   private:
327     SUIT_ExceptionHandler *myHandler;
328     bool myDebug;
329   };
330
331   //! Class which calls SALOME::Session::GetInterface() from another thread
332   //  to avoid mutual lock if called from the same thread as main()
333   class GetInterfaceThread : public QThread
334   {
335   public:
336     GetInterfaceThread(SALOME::Session_var s) : session(s)
337     {
338       start();
339     }
340
341   protected:
342     virtual void run()
343     {
344       if (!CORBA::is_nil(session))
345         session->GetInterface();
346       else
347         std::cerr << "FATAL ERROR: SALOME::Session object is nil! Cannot display GUI" << std::endl;
348     }
349
350   private:
351     SALOME::Session_var session;
352   };
353
354   //! Checks command line for presense of given option(s).
355   //  Option that results to \c true is specified via \a trueOption parameter.
356   //  Option that results to \c false is specified via \a falseOption parameter (empty for default).
357   //  Default value for the result (returned if both \a trueOption \a falseOption are not given) is specified via \c defValue parameter.
358   bool boolCmdOption(const QString trueOption, const QString falseOption = QString(), bool defValue = false)
359   {
360     bool value = defValue;
361
362     QStringList args = QApplication::arguments();
363     foreach (QString arg, args)
364     {
365       if (arg == trueOption)
366         value = true;
367       else if (arg == falseOption)
368         value = false;
369     }
370     return value;
371   }
372
373   // Shutdown standalone servers
374   void shutdownServers(SALOME_NamingService *theNS, bool remoteLauncher)
375   {
376     SALOME_LifeCycleCORBA lcc(theNS);
377     lcc.shutdownServers(!remoteLauncher);
378   }
379 } // end of anonymous namespace
380
381 template<class GUI_APP_STYLE>
382 int AbstractGUIAppMain(int argc, char **argv);
383
384 class GUIAppOldStyle
385 {
386 public:
387   static constexpr bool SSL_MODE = false;
388   using NamingServiceImplementation = OldStyleNS;
389   void connectToNSIfNeeded(CORBA::ORB_ptr orb) { _NS.reset(new SALOME_NamingService(orb)); }
390   void shutdownCORBAStufIfNeeded(bool shutdownAll, CORBA::ORB_ptr orb);
391   void killOtherServersIfNeeded() { SALOME_LifeCycleCORBA::killOmniNames(); }
392   SALOME::Session_var getSession();
393   void shutdownRemoteServersIfNeeded(bool remoteLauncher);
394 private:
395   std::unique_ptr<SALOME_NamingService> _NS;
396 };
397
398 class GUIAppNewStyle
399 {
400 public:
401   static constexpr bool SSL_MODE = true;
402   using NamingServiceImplementation = NewStyleNS;
403   void connectToNSIfNeeded(CORBA::ORB_ptr orb) { /*! nothing */ }
404   void shutdownCORBAStufIfNeeded(bool shutdownAll, CORBA::ORB_ptr orb) { /*! nothing */ }
405   void killOtherServersIfNeeded() { /*! nothing */ }
406   SALOME::Session_var getSession();
407   void shutdownRemoteServersIfNeeded(bool remoteLauncher) { /*! nothing */ }
408 };
409
410 void GUIAppOldStyle::shutdownCORBAStufIfNeeded(bool shutdownAll, CORBA::ORB_ptr orb)
411 {
412   try
413   {
414     orb->shutdown(0);
415   }
416   catch (...)
417   {
418     //////////////////////////////////////////////////////////////
419     // VSR: silently skip exception:
420     // CORBA.BAD_INV_ORDER.BAD_INV_ORDER_ORBHasShutdown
421     // exception is raised when orb->destroy() is called and
422     // cpp continer is launched in the embedded mode
423     //////////////////////////////////////////////////////////////
424     if (shutdownAll)
425       SALOME_LifeCycleCORBA::killOmniNames();
426     abort(); //abort program to avoid deadlock in destructors or atexit when shutdown has been interrupted
427   }
428   // Destroy ORB
429   sleep(2);
430   ORB_INIT *init = SINGLETON_<ORB_INIT>::Instance();
431   if (init)
432     init->explicit_destroy();
433 }
434
435 SALOME::Session_var GUIAppOldStyle::getSession()
436 {
437   CORBA::Object_var obj = _NS->Resolve("/Kernel/Session");
438   SALOME::Session_var session = SALOME::Session::_narrow(obj);
439   return session;
440 }
441 void GUIAppOldStyle::shutdownRemoteServersIfNeeded(bool remoteLauncher)
442 {
443   shutdownServers(_NS.get(), remoteLauncher);
444 }
445
446 SALOME::Session_var GUIAppNewStyle::getSession()
447 {
448   SALOME::Session_var session = GetSessionRefSingleton()->get_future().get();
449   return session;
450 }
451
452 // ---------------------------- MAIN -----------------------
453 template<class GUI_APP_STYLE>
454 int AbstractGUIAppMain(int argc, char **argv)
455 {
456   using NamingServiceImplementation = typename GUI_APP_STYLE::NamingServiceImplementation;
457   setSSLMode(GUI_APP_STYLE::SSL_MODE);
458   GUI_APP_STYLE self;
459   // Set-up application settings configuration (as for QSettings)
460   // Note: these are default settings which can be customized (see below)
461   QApplication::setOrganizationName("salome");
462   QApplication::setApplicationName("salome");
463   QApplication::setApplicationVersion(salomeVersion());
464
465   // Install Qt debug messages handler
466   MsgHandler msgHandler;
467   qInstallMessageHandler(QtxMsgHandler);
468
469   // Add <qtdir>/plugins dir to the pluins search path for image plugins
470   QString qtdir = Qtx::qtDir("plugins");
471   if (!qtdir.isEmpty())
472     QApplication::addLibraryPath(qtdir);
473
474   // Add application library path (to search style plugin etc...)
475   QString path = SUIT_Tools::addSlash(Qtx::getenv("GUI_ROOT_DIR")) + "bin/salome";
476   QApplication::addLibraryPath(QDir::toNativeSeparators(path));
477
478   // QSurfaceFormat should be set before creation of QApplication,
479   // so to avoid conflicts beetween SALOME and ParaView QSurfaceFormats we should merge theirs formats
480   // (see void Qtx::initDefaultSurfaceFormat()) and set the resultant format here.
481   Qtx::initDefaultSurfaceFormat();
482
483   // Create Qt application instance: this should be done as early as possible!
484   // Note: QApplication forces setting locale LC_ALL to system one: setlocale(LC_ALL, "").
485   Application app(argc, argv);
486
487   // Initialize Python (only once)
488   // Note: Python forces setting locale LC_CTYPE to system one: setlocale(LC_CTYPE, "").
489   char *py_argv[] = {(char *)""};
490   KERNEL_PYTHON::init_python(1, py_argv);
491
492   // Create auxiliary resource manager to access application settings
493   ResourceMgr resMgr;
494   resMgr.setWorkingMode(ResourceMgr::IgnoreUserValues);
495   resMgr.loadLanguage("LightApp", "en");
496   resMgr.loadLanguage("SalomeApp", "en");
497   resMgr.loadLanguage("Session");
498
499   // Set-up application settings configuration possible customized via resources
500   if (resMgr.customName() != "SalomeApp")
501   {
502     QApplication::setApplicationName(resMgr.customName());
503     QApplication::setApplicationVersion(resMgr.version());
504   }
505
506   // Force default "C" locale if requested via user's preferences
507   // Note: this does not change whole application locale (changed via setlocale() function),
508   // but only affects GUI behavior
509   resMgr.setWorkingMode(ResourceMgr::AllowUserValues); // we must take into account user preferences
510   if (resMgr.booleanValue("language", "locale", true))
511     QLocale::setDefault(QLocale::c());
512   resMgr.setWorkingMode(ResourceMgr::IgnoreUserValues);
513
514 #if defined(GLOBAL_DOUBLE_CONVERSION)
515   // VSR 30/03/2021: moved here from QtxDoubleSpinBox/QtxIntSpinBox because of crash on Qt 5.12.
516   // Disable thousands separator for spin box
517   // see issue 14540 (old id 21219)
518   QLocale locale;
519   locale.setNumberOptions(locale.numberOptions() | QLocale::OmitGroupSeparator | QLocale::RejectGroupSeparator);
520   QLocale::setDefault(locale);
521 #endif
522
523   bool isGUI = boolCmdOption("--show-desktop", "--hide-desktop", true);  // true by default
524   bool isSplash = boolCmdOption("--show-splash", "--hide-splash", true); // true by default
525
526   // Show splash screen (only if both the "GUI" and "SPLASH" options are true)
527   QtxSplash *splash = 0;
528   if (isGUI && isSplash)
529   {
530     splash = QtxSplash::splash(QPixmap());
531     splash->readSettings(&resMgr);
532     if (splash->pixmap().isNull())
533       splash->setPixmap(resMgr.loadPixmap("LightApp", QObject::tr("ABOUT_SPLASH")));
534     if (splash->pixmap().isNull())
535     {
536       delete splash;
537       splash = 0;
538     }
539     else
540     {
541       splash->setOption("%A", QObject::tr("APP_NAME"));
542       splash->setOption("%V", QObject::tr("ABOUT_VERSION").arg(resMgr.version()));
543       splash->setOption("%L", QObject::tr("ABOUT_LICENSE"));
544       splash->setOption("%C", QObject::tr("ABOUT_COPYRIGHT"));
545       splash->show();
546       QApplication::instance()->processEvents();
547     }
548   }
549
550   // Initialization
551   int result = -1;
552
553   CORBA::ORB_var orb;
554   PortableServer::POA_var poa;
555
556   SUIT_Session *aGUISession = 0;
557   GetInterfaceThread *guiThread = 0;
558   Session_ServerLauncher<NamingServiceImplementation> *myServerLauncher = nullptr;
559
560 #if defined(WIN32) && defined(UNICODE)
561   char **new_argv = NULL;
562 #endif
563
564   bool remoteLauncher = false;
565
566   try
567   {
568     // ...create ORB, get RootPOA object, NamingService, etc.
569     ORB_INIT &init = *SINGLETON_<ORB_INIT>::Instance();
570     ASSERT(SINGLETON_<ORB_INIT>::IsAlreadyExisting());
571     int orbArgc = 1;
572     if (std::string(argv[1]).find("-ORBInitRef") != std::string::npos)
573     {
574       orbArgc = 3;
575       remoteLauncher = true;
576     }
577     orb = init(orbArgc, argv);
578
579     CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
580     poa = PortableServer::POA::_narrow(obj);
581
582     PortableServer::POAManager_var pman = poa->the_POAManager();
583     pman->activate();
584     MESSAGE("POA manager activated");
585
586     self.connectToNSIfNeeded(orb);
587
588     result = 0;
589   }
590   catch (SALOME_Exception &e)
591   {
592     INFOS("run(): Caught SALOME_Exception : " << e.what());
593   }
594   catch (CORBA::SystemException &e)
595   {
596     INFOS("run(): Caught CORBA::SystemException : " << handleCorbaException(e));
597   }
598   catch (CORBA::Exception &e)
599   {
600     INFOS("run(): Caught CORBA::Exception : " << handleCorbaException(e));
601   }
602   catch (std::exception &e)
603   {
604     INFOS("run(): Caught exception : " << e.what());
605   }
606   catch (...)
607   {
608     INFOS("run(): Caught unknown exception");
609   }
610
611   QMutex _GUIMutex, _SessionMutex, _SplashMutex;
612   QWaitCondition _ServerLaunch, _SessionStarted, _SplashStarted;
613
614   // lock session mutex to ensure that GetInterface is not called
615   // until all initialization is done
616   _SessionMutex.lock();
617
618   if (!result)
619   {
620     // Start embedded servers launcher (Registry, SALOMEDS, etc.)
621     // ...lock mutex to block embedded servers launching thread until wait( mutex )
622     _GUIMutex.lock();
623     // ...create launcher
624 #if defined(WIN32) && defined(UNICODE)
625     LPWSTR *szArglist = NULL;
626     int nArgs;
627     int i;
628     szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
629     new_argv = new char *[nArgs];
630     for (i = 0; i < nArgs; i++)
631     {
632       new_argv[i] = (char *)Kernel_Utils::utf8_encode(szArglist[i]);
633     }
634     // Free memory allocated for CommandLineToArgvW arguments.
635     LocalFree(szArglist);
636     myServerLauncher = new Session_ServerLauncher<NamingServiceImplementation>(nArgs, new_argv, orb, poa, &_GUIMutex, &_ServerLaunch, &_SessionMutex, &_SessionStarted);
637 #else
638     myServerLauncher = new Session_ServerLauncher<NamingServiceImplementation>(argc, argv, orb, poa, &_GUIMutex, &_ServerLaunch, &_SessionMutex, &_SessionStarted);
639 #endif
640     // ...block this thread until launcher is ready
641     _ServerLaunch.wait(&_GUIMutex);
642
643     // Start servers check thread (splash)
644     if (splash)
645     {
646       // ...lock mutex to block splash thread until wait( mutex )
647       _SplashMutex.lock();
648       // ...create servers checking thread
649       Session_ServerCheck<NamingServiceImplementation> sc(&_SplashMutex, &_SplashStarted);
650       // ... set initial progress
651       splash->setProgress(0, sc.totalSteps());
652       // start check loop
653       while (true)
654       {
655         int step = sc.currentStep();
656         int total = sc.totalSteps();
657         QString msg = sc.currentMessage();
658         QString err = sc.error();
659         if (!err.isEmpty())
660         {
661           QtxSplash::setError(err);
662           QApplication::instance()->processEvents();
663           result = -1;
664           break;
665         }
666         QtxSplash::setStatus(msg, step);
667         QApplication::instance()->processEvents();
668         if (step >= total)
669           break;
670         // ...block this thread until servers checking is finished
671         _SplashStarted.wait(&_SplashMutex);
672       }
673       // ...unlock mutex 'cause it is no more needed
674       _SplashMutex.unlock();
675     }
676
677     // Finalize embedded servers launcher
678     // ...block this thread until launcher is finished
679     _ServerLaunch.wait(&_GUIMutex);
680     // ...unlock mutex 'cause it is no more needed
681     _GUIMutex.unlock();
682   }
683
684   // Obtain Session interface reference
685   SALOME::Session_var session = self.getSession();
686
687   bool shutdownAll = false;
688   bool shutdownSession = false;
689   bool debugExceptions = boolCmdOption("--no-exception-handler") ||
690                          resMgr.booleanValue("launch", "noexcepthandler", false);
691
692   if (!result)
693   {
694     // Launch GUI activator
695     if (isGUI)
696     {
697       if (splash)
698         splash->setStatus(QObject::tr("Activating desktop..."));
699       // ...create GUI launcher
700       MESSAGE("Session activated, Launch IAPP...");
701       guiThread = new GetInterfaceThread(session);
702     }
703
704     // GUI activation
705     // Allow multiple activation/deactivation of GUI
706     while (true)
707     {
708       MESSAGE("waiting wakeAll()");
709       _SessionStarted.wait(&_SessionMutex); // to be reseased by Launch server thread when ready:
710       // atomic operation lock - unlock on mutex
711       // unlock mutex: serverThread runs, calls _ServerLaunch->wakeAll()
712       // this thread wakes up, and lock mutex
713
714       _SessionMutex.unlock();
715
716       // Session might be shutdowning here, check status
717       SALOME::StatSession stat = session->GetStatSession();
718       shutdownSession = stat.state == SALOME::shutdown;
719       if (shutdownSession)
720       {
721         _SessionMutex.lock(); // lock mutex before leaving loop - it will be unlocked later
722         break;
723       }
724
725       // SUIT_Session creation
726       aGUISession = new Session();
727
728       // Load SalomeApp dynamic library
729       MESSAGE("creation SUIT_Application");
730       SUIT_Application *aGUIApp = aGUISession->startApplication(NamingServiceImplementation::LibName, 0, 0);
731       if (aGUIApp)
732       {
733 #ifdef USE_SALOME_STYLE
734         Style_Salome::initialize(aGUIApp->resourceMgr());
735         if (aGUIApp->resourceMgr()->booleanValue("Style", "use_salome_style", true))
736           Style_Salome::apply();
737 #endif // USE_SALOME_STYLE
738
739         if (!debugExceptions)
740           app.setHandler(aGUISession->handler()); // after loading SalomeApp application
741                                                   // aGUISession contains SalomeApp_ExceptionHandler
742
743         // Run GUI loop
744         MESSAGE("run(): starting the main event loop");
745
746         if (splash)
747           splash->finish(aGUIApp->desktop());
748
749         result = app.exec();
750
751         splash = 0;
752
753         if (result == SUIT_Session::NORMAL)
754         {
755           // desktop is explicitly closed by user from GUI
756           // exit flags says if it's necessary to shutdown all servers
757           // all session server only
758           shutdownAll = aGUISession->exitFlags();
759         }
760         else
761         {
762           // desktop might be closed from:
763           // - StopSesion() (temporarily) or
764           // - Shutdown() (permanently)
765           stat = session->GetStatSession();
766           shutdownSession = stat.state == SALOME::shutdown;
767           // normally "shutdown standalone servers" flag should be false here, if we come from
768           // StopSesion() or from Shutdown();
769           // but we also have to check if somebody explicitly programmatically closed session,
770           // asking to kill servers also
771           shutdownAll = aGUISession->exitFlags();
772         }
773         if (shutdownAll || shutdownSession)
774         {
775           _SessionMutex.lock(); // lock mutex before leaving loop - it will be unlocked later
776           break;
777         }
778       }
779
780       delete aGUISession;
781       aGUISession = 0;
782
783       // Prepare _GUIMutex for a new GUI activation
784       _SessionMutex.lock();
785     }
786   }
787
788   // unlock Session mutex
789   _SessionMutex.unlock();
790
791   // Shutdown embedded servers
792   if (myServerLauncher)
793     myServerLauncher->ShutdownAll();
794
795   // Shutdown standalone servers
796   if (shutdownAll)
797     self.shutdownRemoteServersIfNeeded(remoteLauncher);
798
799   // Kill embedded servers
800   if (myServerLauncher)
801     myServerLauncher->KillAll();
802
803   // Unregister session server
804   SALOME_Session_i *sessionServant =
805       dynamic_cast<SALOME_Session_i *>(poa->reference_to_servant(session.in()));
806   if (sessionServant)
807     sessionServant->NSunregister();
808
809   delete aGUISession;
810   delete guiThread;
811   delete myServerLauncher;
812 #if defined(WIN32) && defined(UNICODE)
813   delete[] new_argv;
814 #endif
815   self.shutdownCORBAStufIfNeeded(shutdownAll,orb);
816   // Finalize Python
817   if (Py_IsInitialized())
818   {
819     PyGILState_Ensure();
820     Py_Finalize();
821   }
822   // Kill omniNames process
823   if (shutdownAll)
824     self.killOtherServersIfNeeded();
825
826   MESSAGE("Salome_Session_Server:endofserver");
827   return result;
828 }