nekoray_Mahdi-zarei/src/main.cpp
parhelia512 4942c25f18 improve
2025-09-30 01:28:29 +08:00

272 lines
8.2 KiB
C++

#include <csignal>
#include <QApplication>
#include <QCryptographicHash>
#include <QDir>
#include <QTranslator>
#include <QMessageBox>
#include <QStandardPaths>
#include <QLocalSocket>
#include <QLocalServer>
#include <QThread>
#include <3rdparty/WinCommander.hpp>
#include "include/global/Configs.hpp"
#include "include/ui/mainwindow_interface.h"
#ifdef Q_OS_WIN
#include "include/sys/windows/MiniDump.h"
#include "include/sys/windows/eventHandler.h"
#include <qfontdatabase.h>
#endif
#ifdef Q_OS_LINUX
#include "include/sys/linux/desktopinfo.h"
#include <qfontdatabase.h>
#endif
void signal_handler(int signum) {
if (GetMainWindow()) {
GetMainWindow()->prepare_exit();
qApp->quit();
}
}
QTranslator* trans = nullptr;
QTranslator* trans_qt = nullptr;
void loadTranslate(const QString& locale) {
QT_TRANSLATE_NOOP("QPlatformTheme", "Cancel");
QT_TRANSLATE_NOOP("QPlatformTheme", "Apply");
QT_TRANSLATE_NOOP("QPlatformTheme", "Yes");
QT_TRANSLATE_NOOP("QPlatformTheme", "No");
QT_TRANSLATE_NOOP("QPlatformTheme", "OK");
if (trans != nullptr) {
trans->deleteLater();
}
if (trans_qt != nullptr) {
trans_qt->deleteLater();
}
//
trans = new QTranslator;
trans_qt = new QTranslator;
QLocale::setDefault(QLocale(locale));
//
if (trans->load(":/translations/" + locale + ".qm")) {
QCoreApplication::installTranslator(trans);
}
}
#define LOCAL_SERVER_PREFIX "throne-"
int main(int argc, char* argv[]) {
// Core dump
#ifdef Q_OS_WIN
Windows_SetCrashHandler();
#endif
QApplication::setAttribute(Qt::AA_DontUseNativeDialogs);
QApplication::setQuitOnLastWindowClosed(false);
QApplication a(argc, argv);
#if !defined(Q_OS_MACOS) && (QT_VERSION >= QT_VERSION_CHECK(6,9,0))
// Load the emoji fonts
int fontId = QFontDatabase::addApplicationFont(":/font/notoEmoji");
if (fontId >= 0)
{
QStringList fontFamilies = QFontDatabase::applicationFontFamilies(fontId);
QFontDatabase::setApplicationEmojiFontFamilies(fontFamilies);
} else
{
qDebug() << "could not load noto font!";
}
#endif
// Clean
QDir::setCurrent(QApplication::applicationDirPath());
if (QFile::exists("updater.old")) {
QFile::remove("updater.old");
}
// Flags
Configs::dataStore->argv = QApplication::arguments();
if (Configs::dataStore->argv.contains("-many")) Configs::dataStore->flag_many = true;
if (Configs::dataStore->argv.contains("-appdata")) {
Configs::dataStore->flag_use_appdata = true;
int appdataIndex = Configs::dataStore->argv.indexOf("-appdata");
if (Configs::dataStore->argv.size() > appdataIndex + 1 && !Configs::dataStore->argv.at(appdataIndex + 1).startsWith("-")) {
Configs::dataStore->appdataDir = Configs::dataStore->argv.at(appdataIndex + 1);
}
}
if (Configs::dataStore->argv.contains("-tray")) Configs::dataStore->flag_tray = true;
if (Configs::dataStore->argv.contains("-debug")) Configs::dataStore->flag_debug = true;
if (Configs::dataStore->argv.contains("-flag_restart_tun_on")) Configs::dataStore->flag_restart_tun_on = true;
if (Configs::dataStore->argv.contains("-flag_restart_dns_set")) Configs::dataStore->flag_dns_set = true;
#ifdef NKR_CPP_USE_APPDATA
Configs::dataStore->flag_use_appdata = true; // Example: Package & MacOS
#endif
#ifdef NKR_CPP_DEBUG
Configs::dataStore->flag_debug = true;
#endif
// dirs & clean
auto wd = QDir(QApplication::applicationDirPath());
if (Configs::dataStore->flag_use_appdata) {
QApplication::setApplicationName("Throne");
if (!Configs::dataStore->appdataDir.isEmpty()) {
wd.setPath(Configs::dataStore->appdataDir);
} else {
wd.setPath(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation));
}
}
if (!wd.exists()) wd.mkpath(wd.absolutePath());
if (!wd.exists("config")) wd.mkdir("config");
QDir::setCurrent(wd.absoluteFilePath("config"));
QDir("temp").removeRecursively();
#ifdef Q_OS_LINUX
QApplication::addLibraryPath(QApplication::applicationDirPath() + "/usr/plugins");
#endif
// dispatchers
DS_cores = new QThread;
DS_cores->start();
// icons
QIcon::setFallbackSearchPaths(QStringList{
":/icon",
});
// icon for no theme
if (QIcon::themeName().isEmpty()) {
QIcon::setThemeName("breeze");
}
// Dir
QDir dir;
bool dir_success = true;
if (!dir.exists("profiles")) {
dir_success &= dir.mkdir("profiles");
}
if (!dir.exists("groups")) {
dir_success &= dir.mkdir("groups");
}
if (!dir.exists(ROUTES_PREFIX_NAME)) {
dir_success &= dir.mkdir(ROUTES_PREFIX_NAME);
}
if (!dir_success) {
QMessageBox::critical(nullptr, "Error", "No permission to write " + dir.absolutePath());
return 1;
}
// migrate the old config file
if (QFile::exists("groups/nekobox.json"))
{
QFile::rename("groups/nekobox.json", "configs.json");
}
// Load dataStore
Configs::dataStore->fn = "configs.json";
auto isLoaded = Configs::dataStore->Load();
if (!isLoaded) {
Configs::dataStore->Save();
}
#ifdef Q_OS_WIN
if (Configs::dataStore->windows_set_admin && !Configs::IsAdmin() && !Configs::dataStore->disable_run_admin)
{
Configs::dataStore->windows_set_admin = false; // so that if permission denied, we will run as user on the next run
Configs::dataStore->Save();
WinCommander::runProcessElevated(QApplication::applicationFilePath(), {}, "", WinCommander::SW_NORMAL, false);
QApplication::quit();
return 0;
}
#endif
// Datastore & Flags
if (Configs::dataStore->start_minimal) Configs::dataStore->flag_tray = true;
// load routing
Configs::dataStore->routing = std::make_unique<Configs::Routing>();
Configs::dataStore->routing->fn = ROUTES_PREFIX + "Default";
isLoaded = Configs::dataStore->routing->Load();
if (!isLoaded) {
Configs::dataStore->routing->Save();
}
// Translate
QString locale;
switch (Configs::dataStore->language) {
case 1: // English
break;
case 2:
locale = "zh_CN";
break;
case 3:
locale = "fa_IR"; // farsi(iran)
break;
case 4:
locale = "ru_RU"; // Russian
break;
default:
locale = QLocale().name();
}
QGuiApplication::tr("QT_LAYOUT_DIRECTION");
loadTranslate(locale);
// Check if another instance is running
QByteArray hashBytes = QCryptographicHash::hash(wd.absolutePath().toUtf8(), QCryptographicHash::Md5).toBase64(QByteArray::OmitTrailingEquals);
hashBytes.replace('+', '0').replace('/', '1');
auto serverName = LOCAL_SERVER_PREFIX + QString::fromUtf8(hashBytes);
qDebug() << "server name: " << serverName;
QLocalSocket socket;
socket.connectToServer(serverName);
if (socket.waitForConnected(250))
{
qDebug() << "Another instance is running, let's wake it up and quit";
socket.disconnectFromServer();
return 0;
}
// QLocalServer
QLocalServer server(qApp);
server.setSocketOptions(QLocalServer::WorldAccessOption);
if (!server.listen(serverName)) {
qWarning() << "Failed to start QLocalServer! Error:" << server.errorString();
return 1;
}
QObject::connect(&server, &QLocalServer::newConnection, qApp, [&] {
auto s = server.nextPendingConnection();
qDebug() << "Another instance tried to wake us up on " << serverName << s;
s->close();
// raise main window
MW_dialog_message("", "Raise");
});
QObject::connect(qApp, &QApplication::aboutToQuit, [&]
{
server.close();
QLocalServer::removeServer(serverName);
});
#ifdef Q_OS_LINUX
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
#endif
#ifdef Q_OS_WIN
auto eventFilter = new PowerOffTaskkillFilter(signal_handler);
a.installNativeEventFilter(eventFilter);
#endif
#ifdef Q_OS_MACOS
QObject::connect(qApp, &QGuiApplication::commitDataRequest, [&](QSessionManager &manager)
{
Q_UNUSED(manager);
signal_handler(0);
});
#endif
UI_InitMainWindow();
return QApplication::exec();
}