diff --git a/tools/chatgui/src/main.cpp b/tools/chatgui/src/main.cpp index ede51b60..f15caf66 100644 --- a/tools/chatgui/src/main.cpp +++ b/tools/chatgui/src/main.cpp @@ -14,6 +14,8 @@ #include "gui_language.h" #include #ifdef _WIN32 +#include +#include #include #include #endif @@ -85,9 +87,44 @@ int main(int argc, char *argv[]) { app.setQuitOnLastWindowClosed(false); debug_config_init(); + QString cfgDir = QCoreApplication::applicationDirPath(); +#ifdef _WIN32 + QString storageReason; + if (!QFile::exists(cfgDir + "/vibechat.cfg") && !QFile::exists(cfgDir + "/chatgui.cfg")) { + storageReason = QStringLiteral("config missing in executable directory"); + } else { + /* Реальная проверка записи учитывает ACL Windows, а не только атрибуты каталога. */ + QTemporaryFile probe(cfgDir + "/.vibechat-write-XXXXXX"); + if (!probe.open()) { + storageReason = QStringLiteral("executable directory is not writable: %1").arg(probe.errorString()); + } else if (!probe.remove()) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Cannot remove write probe %s: %s", + qPrintable(probe.fileName()), qPrintable(probe.errorString())); + return 1; + } + } + if (!storageReason.isEmpty()) { + cfgDir = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); + if (cfgDir.isEmpty() || !QDir().mkpath(cfgDir)) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Cannot create LocalAppData directory %s; fallback reason: %s", + qPrintable(cfgDir), qPrintable(storageReason)); + return 1; + } + } else { + storageReason = QStringLiteral("config found in writable executable directory"); + } +#endif + /* Блокировка до любых изменений конфига/БД; предупреждение после загрузки языка. */ - QLockFile lock(QCoreApplication::applicationDirPath() + "/vibechat.lock"); + QLockFile lock(cfgDir + "/vibechat.lock"); const bool locked = lock.tryLock(); +#ifdef _WIN32 + if (!locked && lock.error() != QLockFile::LockFailedError) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Cannot lock data directory %s: error=%d; selection reason: %s", + qPrintable(cfgDir), static_cast(lock.error()), qPrintable(storageReason)); + return 1; + } +#endif app.setStyle(QStyleFactory::create("Fusion")); QPalette p; @@ -108,7 +145,6 @@ int main(int argc, char *argv[]) { p.setColor(QPalette::Disabled, QPalette::ButtonText, QColor(127, 127, 127)); app.setPalette(p); - QString cfgDir = QCoreApplication::applicationDirPath(); QString cfgPath = cfgDir + "/vibechat.cfg"; /* миграция: старый конфиг chatgui.cfg → vibechat.cfg */ if (locked && !QFile::exists(cfgPath) && QFile::exists(cfgDir + "/chatgui.cfg")) @@ -166,13 +202,13 @@ int main(int argc, char *argv[]) { QString dbPath = cfg.dbPath(); if (dbPath.isEmpty()) dbPath = "chat_data"; if (!QDir::isAbsolutePath(dbPath)) - dbPath = QCoreApplication::applicationDirPath() + "/" + dbPath; + dbPath = cfgDir + "/" + dbPath; QDir(dbPath).mkpath("."); QString debugFile = cfg.debugFile(); if (debugFile.isEmpty()) debugFile = "chatgui.log"; if (!QDir::isAbsolutePath(debugFile)) - debugFile = QCoreApplication::applicationDirPath() + "/" + debugFile; + debugFile = cfgDir + "/" + debugFile; /* ранняя инициализация лога в GUI-потоке: SoundManager::init() вызывается в * конструкторе MainWindow ДО старта utun-потока, поэтому без этого его диагностика @@ -183,6 +219,11 @@ int main(int argc, char *argv[]) { if (lvl.isEmpty()) lvl = QStringLiteral("info"); debug_apply_global_level(lvl.toUtf8().constData()); DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "vibechat: version=%s", qPrintable(app.applicationVersion())); +#ifdef _WIN32 + 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")); +#endif DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "GUI language: preference=%s system=%s selected=%s", qPrintable(cfg.language()), qPrintable(QLocale::system().uiLanguages().join(',')), qPrintable(language)); diff --git a/tools/chatgui/src/mainwindow.cpp b/tools/chatgui/src/mainwindow.cpp index 9b543a68..e98a8c25 100644 --- a/tools/chatgui/src/mainwindow.cpp +++ b/tools/chatgui/src/mainwindow.cpp @@ -53,6 +53,9 @@ extern "C" { #include #include #include +#ifdef _WIN32 +#include +#endif #include #include #include @@ -362,7 +365,11 @@ void MainWindow::setupSoundFromConfig() { } if (soundDir.isEmpty()) soundDir = "sounds"; +#ifdef _WIN32 + QDir binDir(QFileInfo(m_cfgPath).absolutePath()); +#else QDir binDir(QApplication::applicationDirPath()); +#endif QString baseDir = QDir::isAbsolutePath(soundDir) ? soundDir : binDir.absoluteFilePath(soundDir); auto resolvePath = [&baseDir](const QString& f) { return f.isEmpty() ? QString() : QDir::cleanPath(baseDir + "/" + f); };