|
|
|
|
@ -15,10 +15,12 @@
|
|
|
|
|
#include "call_camera_capture.h" |
|
|
|
|
#include <cstdio> |
|
|
|
|
#include <cstring> |
|
|
|
|
#include <cerrno> |
|
|
|
|
#ifdef _WIN32 |
|
|
|
|
#include <QStandardPaths> |
|
|
|
|
#include <windows.h> |
|
|
|
|
#include <tlhelp32.h> |
|
|
|
|
#include <io.h> |
|
|
|
|
#endif |
|
|
|
|
#include "mainwindow.h" |
|
|
|
|
#include "../db/db_manager.h" |
|
|
|
|
@ -30,6 +32,28 @@
|
|
|
|
|
static UtunNode* g_ctrl_node = nullptr; |
|
|
|
|
static MainWindow* g_mainWindow = nullptr; |
|
|
|
|
|
|
|
|
|
// GUI EXE не создаёт консоль; подключаем только родительскую, сохраняя перенаправленные потоки.
|
|
|
|
|
static bool attach_parent_console(void) { |
|
|
|
|
if (!AttachConsole(ATTACH_PARENT_PROCESS)) { |
|
|
|
|
const DWORD error = GetLastError(); |
|
|
|
|
if (error != ERROR_ACCESS_DENIED) { |
|
|
|
|
if (error != ERROR_INVALID_HANDLE && error != ERROR_INVALID_PARAMETER) |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "Windows parent console attach failed: error=%lu", (unsigned long)error); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
FILE* streams[] = {stdin, stdout, stderr}; |
|
|
|
|
const char* devices[] = {"CONIN$", "CONOUT$", "CONOUT$"}; |
|
|
|
|
for (int i = 0; i < 3; ++i) { |
|
|
|
|
const int fd = _fileno(streams[i]); |
|
|
|
|
const HANDLE handle = fd < 0 ? INVALID_HANDLE_VALUE : (HANDLE)_get_osfhandle(fd); |
|
|
|
|
if (handle && handle != INVALID_HANDLE_VALUE && GetFileType(handle) != FILE_TYPE_UNKNOWN) continue; |
|
|
|
|
if (!freopen(devices[i], i == 0 ? "r" : "w", streams[i])) |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "Windows console stream reopen failed: stream=%d errno=%d", i, errno); |
|
|
|
|
} |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static DWORD count_threads(void) { |
|
|
|
|
DWORD pid = GetCurrentProcessId(), count = 0; |
|
|
|
|
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); |
|
|
|
|
@ -75,6 +99,10 @@ static struct ShutdownSentinel {
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[]) { |
|
|
|
|
if (argc >= 2 && std::strcmp(argv[1], "--call-camera-worker") == 0) return call_camera_worker_main(argc, argv); |
|
|
|
|
debug_config_init(); |
|
|
|
|
#ifdef _WIN32 |
|
|
|
|
const bool consoleAttached = attach_parent_console(); |
|
|
|
|
#endif |
|
|
|
|
#ifdef Q_OS_LINUX |
|
|
|
|
/* На Wayland композитор владеет позицией окна (move() игнорируется) —
|
|
|
|
|
* для полноценного ручного move/resize с пропорцией запускаемся через XWayland. */ |
|
|
|
|
@ -87,7 +115,7 @@ int main(int argc, char *argv[]) {
|
|
|
|
|
app.setDesktopFileName("org.utun.vibechat"); |
|
|
|
|
app.setWindowIcon(QIcon(":/icons/app_icon.png")); |
|
|
|
|
app.setQuitOnLastWindowClosed(false); |
|
|
|
|
debug_config_init(); |
|
|
|
|
const bool minimized = app.arguments().contains(QStringLiteral("--minimized")); |
|
|
|
|
|
|
|
|
|
QString cfgDir = QCoreApplication::applicationDirPath(); |
|
|
|
|
#ifdef _WIN32 |
|
|
|
|
@ -218,6 +246,7 @@ int main(int argc, char *argv[]) {
|
|
|
|
|
debug_apply_global_level(lvl.toUtf8().constData()); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "vibechat: version=%s", qPrintable(app.applicationVersion())); |
|
|
|
|
#ifdef _WIN32 |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "Windows console: attached=%d", consoleAttached); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Windows storage: reason=%s config=%s db=%s log=%s lock=%s", |
|
|
|
|
qPrintable(storageReason), qPrintable(cfgPath), qPrintable(dbPath), qPrintable(debugFile), |
|
|
|
|
qPrintable(cfgDir + "/vibechat.lock")); |
|
|
|
|
@ -228,7 +257,8 @@ int main(int argc, char *argv[]) {
|
|
|
|
|
DbManager db; |
|
|
|
|
MainWindow w(nullptr, &db, cfgPath, dbPath, debugFile, |
|
|
|
|
cfg.debugLevel(), cfg.debugCategories()); |
|
|
|
|
w.show(); |
|
|
|
|
if (minimized) w.showMinimized(); else w.show(); |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "GUI startup: minimized_requested=%d minimized=%d", minimized, w.isMinimized()); |
|
|
|
|
|
|
|
|
|
#ifdef _WIN32 |
|
|
|
|
g_ctrl_node = w.utunNode(); |
|
|
|
|
|