int main(int pArgc, char *pArgv[]) { int res; // Create the application SharedTools::QtSingleApplication *app = new SharedTools::QtSingleApplication(QFileInfo(pArgv[0]).baseName(), pArgc, pArgv); // Some general initialisations OpenCOR::initApplication(app); #if defined(Q_OS_WIN) // Do nothing... #elif defined(Q_OS_LINUX) || defined(Q_OS_MAC) // Try to run OpenCOR as a console application // Note: in the case of Windows, we have two binaries (.com and .exe which // are for the pure console and GUI versions of OpenCOR, resp.). This // means that when a console window is open, to enter something like: // C:\>OpenCOR // will effectively call OpenCOR.com. From there, should there be no // argument that requires console treatment, the GUI version of // OpenCOR will then be launched. This is, unfortunately, the only way // to have OpenCOR behave as both a console and GUI application on // Windows, hence the ../winConsole/main.cpp file which is used to // generate the console version of OpenCOR... if (OpenCOR::consoleApplication(app, &res)) { // OpenCOR was run as a proper console application, so... delete app; return res; } #else #error Unsupported platform #endif // Send a message (containing the arguments that were passed to this // instance of OpenCOR minus the first argument since it corresponds to the // full path to the executable which we are not interested in) to the // 'official' instance of OpenCOR, should there be one. If there is no // 'official' instance of OpenCOR, then just carry on as normal, otherwise // exit since we only want one instance of OpenCOR at any given time QStringList appArguments = app->arguments(); appArguments.removeFirst(); QString arguments = appArguments.join("|"); if (app->isRunning()) { app->sendMessage(arguments); delete app; return 0; } // Specify where to find non-OpenCOR plugins (only required on Windows) #ifdef Q_OS_WIN app->addLibraryPath( QDir(app->applicationDirPath()).canonicalPath() +QDir::separator()+QString("..") +QDir::separator()+"plugins"); #endif // Remove all 'global' instances, in case OpenCOR previously crashed or // something (and therefore didn't remove all of them before quitting) removeInstances(); // Create the main window OpenCOR::MainWindow *win = new OpenCOR::MainWindow(); // Keep track of the main window (required by QtSingleApplication so that it // can do what it's supposed to be doing) app->setActivationWindow(win); // Make sure that OpenCOR can handle a file opening request, as well as a // message sent by another instance of itself QObject::connect(app, SIGNAL(fileOpenRequest(const QString &)), win, SLOT(fileOpenRequest(const QString &))); QObject::connect(app, SIGNAL(messageReceived(const QString &)), win, SLOT(messageReceived(const QString &))); // Handle the arguments win->handleArguments(arguments); // Show the main window win->show(); // Execute the application res = app->exec(); // Keep track of the application file and directory paths (in case we need // to restart OpenCOR) QString appFilePath = app->applicationFilePath(); QString appDirPath = app->applicationDirPath(); // Delete the main window delete win; // Remove all 'global' instances that were created and used during this // session removeInstances(); // Delete the application delete app; // We are done with the execution of the application, so now the question is // whether we need to restart // Note: we do this here rather than 'within' the GUI because once we have // launched a new instance of OpenCOR, we want this instance of // OpenCOR to finish as soon as possible which will be the case here // since all that remains to be done is to return the result of the // execution of the application... if (res == OpenCOR::NeedRestart) // Restart OpenCOR, but without providing any of the argument with which // OpenCOR was originally started, since we want to reset everything QProcess::startDetached(appFilePath, QStringList(), appDirPath); // We are done, so... return res; }
int main(int pArgC, char *pArgV[]) { // Initialise Qt's message pattern OpenCOR::initQtMessagePattern(); // Determine whether we should try the CLI version of OpenCOR: // - Windows: we never try the CLI version of OpenCOR. We go straight for // its GUI version. // - Linux: we always try the CLI version of OpenCOR and then go for its // GUI version, if needed. // - OS X: we try the CLI version of OpenCOR unless the user double clicks // on the OpenCOR bundle or opens it from the command line by // entering something like: // open OpenCOR.app // in which case we go for its GUI version. // Note #1: on Windows, we have two binaries (.com and .exe that are for the // CLI and GUI versions of OpenCOR, respectively). This means that // when a console window is open, to enter something like: // C:\>OpenCOR // will effectively call OpenCOR.com. From there, should there be // no argument that requires CLI treatment, then the GUI version of // OpenCOR will be run. This is, unfortunately, the only way to // have OpenCOR to behave as both a CLI and a GUI application on // Windows, hence the [OpenCOR]/windows/main.cpp file, which is // used to generate the CLI version of OpenCOR... // Note #2: on OS X, if we were to try to open the OpenCOR bundle from the // command line, then we would get an error message similar to: // LSOpenURLsWithRole() failed with error -10810 for the file [SomePath]/OpenCOR.app. // Fortunately, when double clicking on the OpenCOR bundle or // opening it from the command line, a special argument in the form // of -psn_0_1234567 is passed to OpenCOR, so we can use that to // determine whether we need to force OpenCOR to be run in GUI mode // or whether we first try the CLI version of OpenCOR, and then its // GUI version, if needed... #if defined(Q_OS_WIN) bool tryCliVersion = false; #elif defined(Q_OS_LINUX) bool tryCliVersion = true; #elif defined(Q_OS_MAC) bool tryCliVersion = (pArgC == 1) || memcmp(pArgV[1], "-psn_", 5); #else #error Unsupported platform #endif // Run the CLI version of OpenCOR, if possible/needed if (tryCliVersion) { // Initialise the plugins path OpenCOR::initPluginsPath(pArgV[0]); // Create and initialise the CLI version of OpenCOR OpenCOR::CliApplication *cliApp = new OpenCOR::CliApplication(pArgC, pArgV); OpenCOR::initApplication(); // Try to run the CLI version of OpenCOR int res; bool runCliApplication = cliApp->run(&res); delete cliApp; if (runCliApplication) { // OpenCOR was run as a CLI application, so leave return res; } // Note: at this stage, we tried the CLI version of OpenCOR, but in the // end we need to go for its GUI version, so start over but with // the GUI version of OpenCOR this time... } // Make sure that we always use indirect rendering on Linux // Note: indeed, depending on which plugins are selected, OpenCOR may need // LLVM. If that's the case, and in case the user's video card uses a // driver that relies on LLVM (e.g. Gallium3D and Mesa 3D), then there // may be a conflict between the version of LLVM used by OpenCOR and // the one used by the video card. One way to address this issue is by // using indirect rendering... #ifdef Q_OS_LINUX qputenv("LIBGL_ALWAYS_INDIRECT", "1"); #endif // Initialise the plugins path OpenCOR::initPluginsPath(pArgV[0]); // Create the GUI version of OpenCOR OpenCOR::GuiApplication *guiApp = new OpenCOR::GuiApplication(QFileInfo(pArgV[0]).baseName(), pArgC, pArgV); // Send a message (containing the arguments that were passed to this // instance of OpenCOR minus the first one since it corresponds to the full // path to our executable, which we are not interested in) to our 'official' // instance of OpenCOR, should there be one (if there is none, then just // carry on as normal, otherwise exit since we want only one instance of // OpenCOR at any given time) QStringList appArguments = guiApp->arguments(); appArguments.removeFirst(); QString arguments = appArguments.join("|"); if (guiApp->isRunning()) { guiApp->sendMessage(arguments); delete guiApp; return 0; } // Initialise the GUI version of OpenCOR QString appDate = QString(); OpenCOR::initApplication(&appDate); // Check whether we want to check for new versions at startup and, if so, // whether a new version of OpenCOR is available QSettings settings; #ifndef QT_DEBUG settings.beginGroup("CheckForUpdatesWindow"); bool checkForUpdatesAtStartup = settings.value(OpenCOR::SettingsCheckForUpdatesAtStartup, true).toBool(); bool includeSnapshots = settings.value(OpenCOR::SettingsIncludeSnapshots, false).toBool(); settings.endGroup(); if (checkForUpdatesAtStartup) { OpenCOR::CheckForUpdatesEngine *checkForUpdatesEngine = new OpenCOR::CheckForUpdatesEngine(appDate); checkForUpdatesEngine->check(); if ( ( includeSnapshots && checkForUpdatesEngine->hasNewerVersion()) || (!includeSnapshots && checkForUpdatesEngine->hasNewerOfficialVersion())) { // Retrieve the language to be used to show the check for updates // window QString locale = OpenCOR::locale(); QLocale::setDefault(QLocale(locale)); QTranslator qtTranslator; QTranslator appTranslator; qtTranslator.load(":qt_"+locale); guiApp->installTranslator(&qtTranslator); appTranslator.load(":app_"+locale); guiApp->installTranslator(&appTranslator); // Show the check for updates window // Note: checkForUpdatesEngine gets deleted by // checkForUpdatesWindow... OpenCOR::CheckForUpdatesWindow checkForUpdatesWindow(checkForUpdatesEngine); settings.beginGroup(checkForUpdatesWindow.objectName()); checkForUpdatesWindow.loadSettings(&settings); settings.endGroup(); checkForUpdatesWindow.exec(); settings.beginGroup(checkForUpdatesWindow.objectName()); checkForUpdatesWindow.saveSettings(&settings); settings.endGroup(); } else { delete checkForUpdatesEngine; } } #endif // Create and show our splash screen, if we are not in debug mode #ifndef QT_DEBUG OpenCOR::SplashScreenWindow *splashScreen = new OpenCOR::SplashScreenWindow(); splashScreen->show(); #endif // Create our main window OpenCOR::MainWindow *win = new OpenCOR::MainWindow(appDate); // Keep track of our main window (required by QtSingleApplication so that it // can do what it's supposed to be doing) guiApp->setActivationWindow(win); // Handle our arguments win->handleArguments(appArguments); // Show our main window win->show(); // By default, we can and should execute our application bool canExecuteAplication = true; // Close and delete our splash screen once our main window is visible, if we // are not in debug mode #ifndef QT_DEBUG splashScreen->closeAndDeleteAfter(win); // Make sure that our main window is in the foreground, unless the user // decided to close our main window while we were showing our splash screen // Note: indeed, on Linux, to show our splash screen may result in our main // window being shown in the background... if (!win->shuttingDown()) win->showSelf(); else canExecuteAplication = false; #endif // Execute our application, if possible int res; if (canExecuteAplication) res = guiApp->exec(); else res = 0; // Keep track of our application file and directory paths (in case we need // to restart OpenCOR) QString appFilePath = guiApp->applicationFilePath(); QString appDirPath = guiApp->applicationDirPath(); // Delete our main window delete win; // We use QtWebKit, and QWebPage in particular, which results in some leak // messages being generated on Windows when leaving OpenCOR. This is because // an object cache is shared between all QWebPage instances. So to destroy a // QWebPage instance doesn't clear the cache, hence the leak messages. // However, those messages are 'only' warnings, so we can safely live with // them. Still, it doesn't look 'good', so we clear the memory caches, thus // avoiding those leak messages... // Note: the below must absolutely be done after calling guiApp->exec() and // before deleting guiApp... #ifdef Q_OS_WIN QWebSettings::clearMemoryCaches(); #endif // Delete our application delete guiApp; // We are done with the execution of our application, so now the question is // whether we need to restart // Note: we do this here rather than 'within' the GUI because once we have // launched a new instance of OpenCOR, we want this instance of // OpenCOR to finish as soon as possible, which will be the case here // since all that remains to be done is to return the result of the // execution of our application... if ((res == OpenCOR::CleanRestart) || (res == OpenCOR::NormalRestart)) { // We want to restart, so the question is whether we want a normal // restart or a clean one if (res == OpenCOR::CleanRestart) { // We want a clean restart, so clear all the user settings (indeed, // this will ensure that the various windows are, for instance, // properly reset with regards to their dimensions) settings.clear(); } // Restart OpenCOR, but without providing any of the arguments that were // originally passed to us since we want to reset everything QProcess::startDetached(appFilePath, QStringList(), appDirPath); } // We are done running the GUI version of OpenCOR, so leave return res; }