Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}