2026-03-26 08:30:31 +08:00
|
|
|
|
#include "mainwindow.h"
|
|
|
|
|
|
#include "SingleInstanceManager.h"
|
|
|
|
|
|
#include "AuthView.h"
|
2026-04-02 09:52:45 +08:00
|
|
|
|
#include "AuthManager.h"
|
|
|
|
|
|
#include "HolePitPositionPresenter.h"
|
|
|
|
|
|
#include "IYHolePitPositionStatus.h"
|
|
|
|
|
|
#include "VrLog.h"
|
2026-03-26 08:30:31 +08:00
|
|
|
|
|
|
|
|
|
|
#include <QApplication>
|
|
|
|
|
|
#include <QIcon>
|
|
|
|
|
|
#include <QMessageBox>
|
|
|
|
|
|
#include <QObject>
|
|
|
|
|
|
#include <cstdio>
|
2026-04-02 09:52:45 +08:00
|
|
|
|
#include <cstring>
|
2026-03-26 08:30:31 +08:00
|
|
|
|
|
2026-04-02 09:52:45 +08:00
|
|
|
|
#ifdef Q_OS_UNIX
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
// 无桌面模式下的状态监听器,将状态信息输出到日志
|
|
|
|
|
|
class HeadlessStatusListener : public IYHolePitPositionStatus
|
2026-03-26 08:30:31 +08:00
|
|
|
|
{
|
2026-04-02 09:52:45 +08:00
|
|
|
|
public:
|
|
|
|
|
|
void OnStatusUpdate(const std::string& msg) override {
|
|
|
|
|
|
LOG_INFO("[Headless] Status: %s\n", msg.c_str());
|
|
|
|
|
|
}
|
|
|
|
|
|
void OnDetectionResult(const HolePitPositionResult& result) override {
|
|
|
|
|
|
LOG_INFO("[Headless] DetectionResult received, errorCode=%d\n", result.errorCode);
|
|
|
|
|
|
}
|
|
|
|
|
|
void OnCamera1StatusChanged(bool connected) override {
|
|
|
|
|
|
LOG_INFO("[Headless] Camera1: %s\n", connected ? "connected" : "disconnected");
|
|
|
|
|
|
}
|
|
|
|
|
|
void OnCamera2StatusChanged(bool connected) override {
|
|
|
|
|
|
LOG_INFO("[Headless] Camera2: %s\n", connected ? "connected" : "disconnected");
|
|
|
|
|
|
}
|
|
|
|
|
|
void OnRobotConnectionChanged(bool connected) override {
|
|
|
|
|
|
LOG_INFO("[Headless] Robot: %s\n", connected ? "connected" : "disconnected");
|
|
|
|
|
|
}
|
|
|
|
|
|
void OnSerialConnectionChanged(bool connected) override {
|
|
|
|
|
|
LOG_INFO("[Headless] Serial: %s\n", connected ? "connected" : "disconnected");
|
|
|
|
|
|
}
|
|
|
|
|
|
void OnCameraCountChanged(int count) override {
|
|
|
|
|
|
LOG_INFO("[Headless] CameraCount: %d\n", count);
|
|
|
|
|
|
}
|
|
|
|
|
|
void OnWorkStatusChanged(WorkStatus status) override {
|
|
|
|
|
|
LOG_INFO("[Headless] WorkStatus changed: %d\n", static_cast<int>(status));
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2026-03-26 08:30:31 +08:00
|
|
|
|
|
2026-04-02 09:52:45 +08:00
|
|
|
|
#ifdef Q_OS_UNIX
|
|
|
|
|
|
// 检测设备文件是否存在
|
|
|
|
|
|
static bool deviceExists(const char* path)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct stat st;
|
|
|
|
|
|
return stat(path, &st) == 0;
|
|
|
|
|
|
}
|
2026-03-26 08:30:31 +08:00
|
|
|
|
|
2026-04-02 09:52:45 +08:00
|
|
|
|
// 检测是否有可用的显示设备(X11、Wayland、framebuffer、DRM 任意一种即可)
|
|
|
|
|
|
static bool detectDisplay()
|
|
|
|
|
|
{
|
|
|
|
|
|
// X11 / Wayland 环境变量
|
|
|
|
|
|
const char* display = std::getenv("DISPLAY");
|
|
|
|
|
|
const char* waylandDisp = std::getenv("WAYLAND_DISPLAY");
|
|
|
|
|
|
if ((display && strlen(display) > 0) ||
|
|
|
|
|
|
(waylandDisp && strlen(waylandDisp) > 0)) {
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2026-03-26 08:30:31 +08:00
|
|
|
|
|
2026-04-02 09:52:45 +08:00
|
|
|
|
// Framebuffer(嵌入式 ARM 常见)
|
|
|
|
|
|
if (deviceExists("/dev/fb0")) {
|
|
|
|
|
|
return true;
|
2026-03-26 08:30:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-02 09:52:45 +08:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
|
|
{
|
|
|
|
|
|
bool hasDisplay = true;
|
|
|
|
|
|
#ifdef Q_OS_UNIX
|
|
|
|
|
|
hasDisplay = detectDisplay();
|
|
|
|
|
|
if (!hasDisplay) {
|
|
|
|
|
|
qputenv("QT_QPA_PLATFORM", "offscreen");
|
|
|
|
|
|
fprintf(stderr, "[Main] No display detected, running in headless mode.\n");
|
|
|
|
|
|
fflush(stderr);
|
2026-03-26 08:30:31 +08:00
|
|
|
|
}
|
2026-04-02 09:52:45 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
QApplication a(argc, argv);
|
2026-03-26 08:30:31 +08:00
|
|
|
|
|
2026-04-02 09:52:45 +08:00
|
|
|
|
SingleInstanceManager instanceManager("HolePitPositionApp_SingleInstance_Key");
|
|
|
|
|
|
|
|
|
|
|
|
if (hasDisplay) {
|
|
|
|
|
|
// ---- 有桌面:完整 UI 模式 ----
|
|
|
|
|
|
a.setWindowIcon(QIcon(":/common/resource/logo.png"));
|
|
|
|
|
|
|
|
|
|
|
|
if (instanceManager.isAnotherInstanceRunning()) {
|
|
|
|
|
|
QMessageBox::information(nullptr,
|
|
|
|
|
|
QObject::tr("应用程序已运行"),
|
|
|
|
|
|
QObject::tr("坑孔定位检测应用程序已经在运行中,请勿重复启动!"),
|
|
|
|
|
|
QMessageBox::Ok);
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!AuthView::CheckAndShow(nullptr)) {
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
2026-03-26 08:30:31 +08:00
|
|
|
|
|
2026-04-02 09:52:45 +08:00
|
|
|
|
MainWindow w;
|
|
|
|
|
|
w.show();
|
|
|
|
|
|
return a.exec();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// ---- 无桌面:只启动业务逻辑 ----
|
|
|
|
|
|
if (instanceManager.isAnotherInstanceRunning()) {
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 无UI模式下直接检查授权有效性
|
|
|
|
|
|
if (!AuthManager::CheckLicenseValid()) {
|
|
|
|
|
|
fprintf(stderr, "[Main] Authorization check failed, exiting.\n");
|
|
|
|
|
|
fflush(stderr);
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static HeadlessStatusListener listener;
|
|
|
|
|
|
static HolePitPositionPresenter presenter;
|
|
|
|
|
|
presenter.SetStatusCallback<IYHolePitPositionStatus>(&listener);
|
|
|
|
|
|
presenter.Init();
|
|
|
|
|
|
return a.exec();
|
|
|
|
|
|
}
|
2026-03-26 08:30:31 +08:00
|
|
|
|
}
|