source: subsurface/subsurface-desktop-main.cpp

Last change on this file was a8fbceac, checked in by Lubomir I. Ivanov <neolit123@…>, 6 days ago

subsurface-startup: expose print_version() in the header

The Windows auto-verbose + log file creation if starting
from a non-terminal has the problem that the print_version()
call is never made becase 'verbose' is updated programatically
in windows.c and not by the user (by passing -v).

To work around the issue:

  • move the windows console creation call before *everything* else
  • then immediatelly install the message handler
  • then see if 'verbose' is set and explicitly call print_version()

print_version() now also has a flag (version_printed), to avoid
printing the version multiple times, if the user decided to add
an extra -v to the Desktop shortcut.

Signed-off-by: Lubomir I. Ivanov <neolit123@…>

  • Property mode set to 100644
File size: 7.2 KB
Line 
1// SPDX-License-Identifier: GPL-2.0
2/* main.c */
3#include <locale.h>
4#include <stdio.h>
5#include <string.h>
6#include <stdlib.h>
7#include <time.h>
8
9#include "core/dive.h"
10#include "core/qt-gui.h"
11#include "core/subsurfacestartup.h"
12#include "desktop-widgets/mainwindow.h"
13#include "desktop-widgets/tab-widgets/maintab.h"
14#include "profile-widget/profilewidget2.h"
15#include "desktop-widgets/preferences/preferencesdialog.h"
16#include "desktop-widgets/diveplanner.h"
17#include "core/color.h"
18#include "core/qthelper.h"
19#include "core/downloadfromdcthread.h" // for fill_computer_list
20
21#include <QStringList>
22#include <QApplication>
23#include <QLoggingCategory>
24#include <QOpenGLContext>
25#include <QOffscreenSurface>
26#include <QOpenGLFunctions>
27#include <QQuickWindow>
28#include <git2.h>
29
30static bool filesOnCommandLine = false;
31static void validateGL();
32static void messageHandler(QtMsgType type, const QMessageLogContext &ctx, const QString &msg);
33
34int main(int argc, char **argv)
35{
36        subsurface_console_init();
37        qInstallMessageHandler(messageHandler);
38        if (verbose) /* print the version if the Win32 console_init() code enabled verbose. */
39                print_version();
40
41        int i;
42        bool no_filenames = true;
43        QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
44        QApplication *application = new QApplication(argc, argv);
45        (void)application;
46        QStringList files;
47        QStringList importedFiles;
48        QStringList arguments = QCoreApplication::arguments();
49
50        const char *default_directory = system_default_directory();
51        const char *default_filename = system_default_filename();
52        subsurface_mkdir(default_directory);
53
54        for (i = 1; i < arguments.length(); i++) {
55                QString a = arguments.at(i);
56                if (a.isEmpty())
57                        continue;
58                if (a.at(0) == '-') {
59                        parse_argument(a.toLocal8Bit().data());
60                        continue;
61                }
62                if (imported) {
63                        importedFiles.push_back(a);
64                } else {
65                        no_filenames = false;
66                        files.push_back(a);
67                }
68        }
69        if (subsurface_user_is_root() && !force_root) {
70                printf("You are running Subsurface as root. This is not recommended.\n");
71                printf("If you insist to do so, run with option --allow_run_as_root.\n");
72                exit(0);
73        }
74        validateGL();
75#if !LIBGIT2_VER_MAJOR && LIBGIT2_VER_MINOR < 22
76        git_threads_init();
77#else
78        git_libgit2_init();
79#endif
80        /*
81         * Initialize the random number generator - not really secure as
82         * this is based only on current time, but it should not matter
83         * that much in our context. Moreover this is better than
84         * the constant numbers we used to get before.
85         */
86        qsrand(time(NULL));
87        setup_system_prefs();
88        copy_prefs(&default_prefs, &prefs);
89        fill_profile_color();
90        fill_computer_list();
91        parse_xml_init();
92        taglist_init_global();
93        init_ui();
94        if (no_filenames) {
95                if (prefs.default_file_behavior == LOCAL_DEFAULT_FILE) {
96                        QString defaultFile(prefs.default_filename);
97                        if (!defaultFile.isEmpty())
98                                files.push_back(QString(prefs.default_filename));
99                } else if (prefs.default_file_behavior == CLOUD_DEFAULT_FILE) {
100                        QString cloudURL;
101                        if (getCloudURL(cloudURL) == 0)
102                                files.push_back(cloudURL);
103                }
104        }
105        MainWindow *m = MainWindow::instance();
106        filesOnCommandLine = !files.isEmpty() || !importedFiles.isEmpty();
107        if (verbose && !files.isEmpty())
108                qDebug() << "loading dive data from" << files;
109        m->loadFiles(files);
110        if (verbose && !importedFiles.isEmpty())
111                qDebug() << "importing dive data from" << importedFiles;
112        m->importFiles(importedFiles);
113
114        if (verbose > 0)
115                print_files();
116        if (!quit)
117                run_ui();
118        exit_ui();
119        taglist_free(g_tag_list);
120        parse_xml_exit();
121        free((void *)default_directory);
122        free((void *)default_filename);
123        subsurface_console_exit();
124        free_prefs();
125        return 0;
126}
127
128bool haveFilesOnCommandLine()
129{
130        return filesOnCommandLine;
131}
132
133#define VALIDATE_GL_PREFIX  "validateGL(): "
134
135void validateGL()
136{
137        QString quickBackend = qgetenv("QT_QUICK_BACKEND");
138        /* an empty QT_QUICK_BACKEND env. variable means OpenGL (default).
139         * only validate OpenGL; for everything else print out and return.
140         * https://doc.qt.io/qt-5/qtquick-visualcanvas-adaptations.html
141         */
142        if (!quickBackend.isEmpty()) {
143                if (verbose) {
144                        qDebug() << QStringLiteral(VALIDATE_GL_PREFIX "'QT_QUICK_BACKEND' is set to '%1'. "
145                                "Skipping validation.").arg(quickBackend).toUtf8().data();
146                }
147                return;
148        }
149        GLint verMajor = -1, verMinor;
150        const char *glError = NULL;
151        QOpenGLContext ctx;
152        QOffscreenSurface surface;
153        QOpenGLFunctions *func;
154        const char *verChar;
155        float verFloat;
156
157        surface.setFormat(ctx.format());
158        surface.create();
159        if (!ctx.create()) {
160                glError = "Cannot create OpenGL context";
161                goto exit;
162        }
163        if (verbose)
164                qDebug() << QStringLiteral(VALIDATE_GL_PREFIX "created OpenGLContext.").toUtf8().data();
165        ctx.makeCurrent(&surface);
166        func = ctx.functions();
167        if (!func) {
168                glError = "Cannot obtain QOpenGLFunctions";
169                goto exit;
170        }
171        if (verbose)
172                qDebug() << QStringLiteral(VALIDATE_GL_PREFIX "obtained QOpenGLFunctions.").toUtf8().data();
173        // detect version for legacy profiles
174        verChar = (const char *)func->glGetString(GL_VERSION);
175        if (verChar) {
176                // detect GLES, show a warning and return early as we don't handle it's versioning
177                if (strstr(verChar, " ES ") != NULL) {
178                         qWarning() << QStringLiteral(VALIDATE_GL_PREFIX "WARNING: Detected OpenGL ES!\n"
179                         "Attempting to run with the available profile!\n"
180                         "If this fails try manually setting the environment variable\n"
181                         "'QT_QUICK_BACKEND' with the value of 'software'\n"
182                         "before running Subsurface!\n").toUtf8().data();
183                         return;
184                }
185                if (sscanf(verChar, "%f", &verFloat) == 1) {
186                        verMajor = (GLint)verFloat;
187                        verMinor = (GLint)roundf((verFloat - verMajor) * 10.f);
188                }
189        }
190        // attempt to detect version using the newer API
191        if (verMajor == -1) {
192                func->glGetIntegerv(GL_MAJOR_VERSION, &verMajor);
193                func->glGetIntegerv(GL_MINOR_VERSION, &verMinor);
194        }
195        if (verMajor == -1) {
196                glError = "Cannot detect OpenGL version";
197                goto exit;
198        }
199        if (verbose)
200                qDebug() << QStringLiteral(VALIDATE_GL_PREFIX "detected OpenGL version %1.%2.").arg(verMajor).arg(verMinor).toUtf8().data();
201        if (verMajor * 10 + verMinor < 21) { // set 2.1 as the minimal version
202                glError = "OpenGL 2.1 or later is required";
203                goto exit;
204        }
205
206exit:
207        ctx.makeCurrent(NULL);
208        surface.destroy();
209        if (glError) {
210#if QT_VERSION < QT_VERSION_CHECK(5, 8, 0)
211                qWarning() << QStringLiteral(VALIDATE_GL_PREFIX "ERROR: %1.\n"
212                        "Cannot automatically fallback to a software renderer!\n"
213                        "Set the environment variable 'QT_QUICK_BACKEND' with the value of 'software'\n"
214                        "before running Subsurface!\n").arg(glError).toUtf8().data();
215                exit(0);
216#else
217                qWarning() << QStringLiteral(VALIDATE_GL_PREFIX "WARNING: %1. Using a software renderer!").arg(glError).toUtf8().data();
218                QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software);
219#endif
220        }
221}
222
223// install this message handler primarily so that the Windows build can log to files
224void messageHandler(QtMsgType type, const QMessageLogContext &ctx, const QString &msg)
225{
226        Q_UNUSED(ctx);
227        QByteArray localMsg = msg.toLocal8Bit();
228        switch (type) {
229        case QtDebugMsg:
230                fprintf(stdout, "%s\n", localMsg.constData());
231                break;
232        case QtInfoMsg:
233                fprintf(stdout, "%s\n", localMsg.constData());
234                break;
235        case QtWarningMsg:
236                fprintf(stderr, "%s\n", localMsg.constData());
237                break;
238        case QtCriticalMsg:
239                fprintf(stderr, "%s\n", localMsg.constData());
240                break;
241        case QtFatalMsg:
242                fprintf(stderr, "%s\n", localMsg.constData());
243                abort();
244        }
245}
Note: See TracBrowser for help on using the repository browser.