QGC4.3.0 - 阅读main.cc(2)

Line81 ~ 93

// To shut down QGC on Ctrl+C on Linux
#ifdef Q_OS_LINUX
#include <csignal>

void sigHandler(int s)
{
    std::signal(s, SIG_DFL);
    qgcApp()->mainRootWindow()->close();
    QEvent event{QEvent::Quit};
    qgcApp()->event(&event);
}

#endif /* Q_OS_LINUX */

 如果顶层CMakeListst.txt中set(LINUX TRUE),那么在后面find_package查找Qt6::Core时,将会包括qsystemdection.h,从而define Q_OS_LINUX

<csignal>头文件包含signal.h,signal.h及signal相关文档,请参考:

Standard library header <csignal> - cppreference.com

标准库 - signal.h - 《阮一峰《C 语言教程》》 - 书栈网 · BookStack

分析sigHandler函数每一行作用如下:

std::signal(s, SIG_DFL);

注意SIG_DFL是一个函数指针的宏,定义一个默认的信号处理函数,当信号s发生时,调用sigHandler函数,而sigHandler函数会调用默认处理函数。

qgcApp()->mainRootWindow()->close();

关闭主窗口,但不关闭程序。

QEvent event{QEvent::Quit};

 生成Quit事件。

qgcApp()->event(&event);

根据bool QGCApplication::event(QEvent *e)源码,当事件为Quit,检查主窗口(root qml元素)的_forceClose属性,如果为true则认为标准QGC退出流程走完了,如果不为true说明还未走完流程

实际上当sigHandler走到qgcApp()->event(&event),说明了qgcApp()->mainRootWindow()->close();引起的QGC退出流程走完了,此时_forceClose为true,走return QApplication::event(e)

所谓退出流程没有走完就调用QGCApplication::event,指的是OSX系统在点击退出按钮时,直接发出Quit信号,而不先发出close使得MainRootWindow.qml中的QGC标准退出流程不执行,因此需要通过调用close函数,使得QGC标准退出流程得以执行。QGCApplication::event源码如下:

bool QGCApplication::event(QEvent *e)
{
    if (e->type() == QEvent::Quit) {
        // On OSX if the user selects Quit from the menu (or Command-Q) the ApplicationWindow does not signal closing. Instead you get a Quit event here only.
        // This in turn causes the standard QGC shutdown sequence to not run. So in this case we close the window ourselves such that the
        // signal is sent and the normal shutdown sequence runs.
        bool forceClose = _mainRootWindow->property("_forceClose").toBool();
        qDebug() << "Quit event" << forceClose;
        // forceClose
        //  true:   Standard QGC shutdown sequence is complete. Let the app quit normally by falling through to the base class processing.
        //  false:  QGC shutdown sequence has not been run yet. Don't let this event close the app yet. Close the main window to kick off the normal shutdown.
        if (!forceClose) {
            //
            _mainRootWindow->close();
            e->ignore();
            return true;
        }
    }
    return QApplication::event(e);
}

 在line162 ~ 165有:

#ifdef Q_OS_LINUX
    std::signal(SIGINT, sigHandler);
    std::signal(SIGTERM, sigHandler);
#endif /* Q_OS_LINUX */

此处signal函数作用是将信号和信号处理函数进行绑定,、

SIGINT: ctrl + C

SIGTERM: kill进程

Line134 ~ 135

// install the message handler
AppMessages::installHandler();
AppMessages::installHandler函数定义如下:
void AppMessages::installHandler()
{
    old_handler = qInstallMessageHandler(msgHandler);

    // Force creation of debug model on installing thread
    Q_UNUSED(*debug_model);
}

其中QtMessageHandler qInstallMessageHandler(QtMessageHandler handler)作用是安装一个Qt消息处理函数handler,并返回一个指向原来安装的消息处理函数指针。具体内容参考官方文档:

<QtLogging> - Qt Logging Types | Qt Core 6.7.1

A message handler is a function that prints out debug, info, warning, critical, and fatal messages from Qt's logging infrastructure. By default, Qt uses a standard message handler that formats and prints messages to different sinks specific to the operating system and Qt configuration. Installing your own message handler allows you to assume full control, and for instance log messages to the file system.

消息处理程序是一个函数,用于从Qt的日志记录基础设施中打印出调试、信息、警告、关键和致命消息。默认情况下,Qt使用标准消息处理程序,该处理程序将消息格式化并打印到特定于操作系统和Qt配置的不同接收器。安装您自己的消息处理程序允许您承担完全控制权,例如将消息记录到文件系统中。

查看自定义消息处理函数msgHandler:

static void msgHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    const char symbols[] = { 'D', 'E', '!', 'X', 'I' };
    QString output = QString("[%1] at %2:%3 - \"%4\"").arg(symbols[type]).arg(context.file).arg(context.line).arg(msg);

    // Avoid recursion
    if (!QString(context.category).startsWith("qt.quick")) {
        debug_model->log(output);
    }

    if (old_handler != nullptr) {
        old_handler(type, context, msg);
    }
    if(type == QtFatalMsg ) abort();
}

根据<QtLogging> - Qt Logging Types | Qt Core 6.7.1

其中明确指出QtMsgType枚举值如下:

对应symbols的5个符号:

Debug ------  QtDebugMsg ------ D ------- qDebug()

Warning ---- QtWarningMsg ---- E ------- qWarning()

Critical -----  QtCriticalMsg ------ ! ------- qCritical()

Fatal --------  QtFatalMsg ------- X ------- qFatal()

Info -------    QtInfoMsg ---------- I ------- qInfo()

QMessageLogContext记录了log信息所在的code line,file name,function name等关键信息。

因此自定义消息处理函数msgHandler作用如下:

1)根据MsgType、context.file、context.line、msg信息打包成一条日志字符串。

2)调用debug_model->log函数记录到日志文件

3)调用old_handler(应为默认消息处理函数),进行默认处理

4)如果类型为Fatal,调用abort()强制退出程序。

Line145 ~ 160

#ifdef Q_OS_WIN
    // Set our own OpenGL buglist
    qputenv("QT_OPENGL_BUGLIST", ":/opengl/resources/opengl/buglist.json");

    // Allow for command line override of renderer
    for (int i = 0; i < argc; i++) {
        const QString arg(argv[i]);
        if (arg == QStringLiteral("-angle")) {
            QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
            break;
        } else if (arg == QStringLiteral("-swrast")) {
            QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
            break;
        }
    }
#endif

关于qputenv请参考官方文档:

<QtEnvironmentVariables> Proxy Page | Qt Core 6.7.1

bool qputenv(const char *varName, QByteArrayView value)

此函数设置名为 varName 的环境变量的值。如果变量不存在,它将创建该变量。如果无法设置变量,则返回 0。请注意,此环境变量随程序运行而存在,随程序退出而消息,但是都不能再windows系统的环境变量界面观察到。

:/opengl/resources/opengl/buglist.json

实际上指的是resources/opengl/resources/opengl/buglist.json

阅读json文件,可知其中描述的是哪些显卡设备在哪些条件下,无法正常驱动openGL完成QGC显示界面工作。搜索QT_OPENGL_BUGLIST,后面似乎并没有使用到?

后面对main函数命令参数进行解析,如果有-angle参数,将会调用

QCoreApplication::setAttribute 设置 Qt::AA_UseOpenGLES

有一篇博客对此做出解释:Qt中的渲染 - 敲什么敲 - 博客园 (cnblogs.com)

Qt::AA_UseOpenGLES 使用 Angle 库来将 DirectX 11或者DirectX 9的接口转成OpenGL ES2.0的API,从而使得windows上显卡驱动不满足要求的设备也能够正常运行。

Qt::AA_UseSoftwareOpenGL使用纯软件实现渲染,不依赖于显卡驱动,当然也没硬件加速

值得注意的是在Qt官方文档中,对QT_OPENGL_BUGLIST进行了说明:

Qt for Windows - Graphics Acceleration | Qt 6.7

It is possible to provide a JSON-format configuration file specifying which OpenGL implementation to use depending on the graphics card and driver version. The location is given by the environment variable QT_OPENGL_BUGLIST. Relative paths are resolved using QLibraryInfo::SettingsPath or QStandardPaths::ConfigLocation. The file utilizes the format of the driver bug list used in The Chromium Projects. It consists of a list of entries each of which specifies a set of conditions and a list of feature keywords. Typically, device id and vendor id are used to match a specific graphics card. They can be found in the output of the qtdiag6 or dxdiag tool.

Line167 ~ 185

// The following calls to qRegisterMetaType are done to silence debug output which warns
    // that we use these types in signals, and without calling qRegisterMetaType we can't queue
    // these signals. In general we don't queue these signals, but we do what the warning says
    // anyway to silence the debug output.
#ifndef NO_SERIAL_LINK
    qRegisterMetaType<QSerialPort::SerialPortError>();
#endif
#ifdef QGC_ENABLE_BLUETOOTH
    qRegisterMetaType<QBluetoothSocket::SocketError>();
    qRegisterMetaType<QBluetoothServiceInfo>();
#endif
    qRegisterMetaType<QAbstractSocket::SocketError>();
#ifndef __mobile__
#ifndef NO_SERIAL_LINK
    qRegisterMetaType<QGCSerialPortInfo>();
#endif
#endif

qRegisterMetaType<Vehicle::MavCmdResultFailureCode_t>("Vehicle::MavCmdResultFailureCode_t");

 以上对自定义类型调用qRegisterMetaType注册到元对象系统,使得在作为signal参数时不出现debug 输出,对于queued类型connections还需要进行Q_DECLARE_METATYPE声明,对于auto类型connections只需调用qRegisterMetaType。

  • 18
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值