// Squawk messenger. // Copyright (C) 2019 Yury Gubich // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include "root.h" #include #include #include #include #include #include const std::vector Root::appIconSizes({ 16, 24, 32, 48, 64, 96, 128, 256, 512 }); Root::Root(int& argc, char *argv[]) : QApplication(argc, argv), signalCatcher(this), defaultTranslator(), currentTranslator(), appIcon(), settings(), componentsInitialized(false), global(nullptr), coreThread(nullptr), core(nullptr), gui(nullptr) { setApplicationName("squawk"); setOrganizationName("macaw.me"); setApplicationDisplayName("Squawk"); setApplicationVersion("0.2.3"); setDesktopFileName("squawk"); initializeTranslation(); initializeAppIcon(); global = new Shared::Global(); //important to instantiate after initialization of translations; } Root::~Root() { if (componentsInitialized) { delete gui; if (core != nullptr) delete core; delete coreThread; } delete global; } void Root::initializeTranslation() { defaultTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); installTranslator(&defaultTranslator); QStringList shares = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation); bool found = false; for (QString share : shares) { found = currentTranslator.load(QLocale(), QLatin1String("squawk"), ".", share + "/l10n"); if (found) break; } if (!found) currentTranslator.load(QLocale(), QLatin1String("squawk"), ".", QCoreApplication::applicationDirPath()); installTranslator(¤tTranslator); } void Root::initializeAppIcon() { for (std::vector::size_type i = 0; i < appIconSizes.size(); ++i) appIcon.addFile(":images/logo.svg", QSize(appIconSizes[i], appIconSizes[i])); Root::setWindowIcon(appIcon); } bool Root::initializeSettings() { QVariant vs = settings.value("style"); if (vs.isValid()) { QString style = vs.toString().toLower(); if (style != "system") Shared::Global::setStyle(style); } if (Shared::Global::supported("colorSchemeTools")) { QVariant vt = settings.value("theme"); if (vt.isValid()) { QString theme = vt.toString(); if (theme.toLower() != "system") Shared::Global::setTheme(theme); } } QString path = Shared::downloadsPathCheck(); if (path.size() > 0) { settings.setValue("downloadsPath", path); } else { qDebug() << "couldn't initialize directory for downloads, quitting"; return false; } return true; } int Root::run() { if (!componentsInitialized) initializeComponents(); coreThread->start(); int result = exec(); qDebug("Event loop stopped"); if (result == 0) { processEvents(); //I dont like all of this mess if (coreThread->isRunning()) { //but it's the best solution for now if (core != nullptr) { //Ideally, following line should never appear in the log qDebug() << "Core is still seems to be running, killing manually"; core->deleteLater(); coreThread->quit(); processEvents(); core = nullptr; } coreThread->wait(); } } return result; } void Root::initializeComponents() { core = new Core::Squawk(); coreThread = new QThread(); core->moveToThread(coreThread); gui = new Application(core); QObject::connect(&signalCatcher, &SignalCatcher::interrupt, gui, &Application::quit); QObject::connect(coreThread, &QThread::started, core, &Core::Squawk::start); QObject::connect(gui, &Application::quitting, core, &Core::Squawk::stop); QObject::connect(core, &Core::Squawk::quit, core, &Core::Squawk::deleteLater); QObject::connect(core, &Core::Squawk::destroyed, this, &Root::onCoreDestroyed); QObject::connect(core, &Core::Squawk::destroyed, coreThread, &QThread::quit, Qt::QueuedConnection); QObject::connect(coreThread, &QThread::finished, this, &Root::quit, Qt::QueuedConnection); componentsInitialized = true; } bool Root::notify(QObject* receiver, QEvent* e) { try { return QApplication::notify(receiver, e); } catch(const std::runtime_error& e) { qDebug() << "std::runtime_error in thread:" << QThread::currentThreadId(); qDebug() << "error message:" << e.what(); } catch(const std::exception& e) { qDebug() << "std::exception in thread:" << QThread::currentThreadId(); qDebug() << "error message:" << e.what(); } catch(const int& e) { qDebug() << "integer exception in thread:" << QThread::currentThreadId(); qDebug() << "thrown integer:" << std::to_string(e).c_str(); } catch(...) { qDebug() << "unhandled exception thread:" << QThread::currentThreadId(); } qDebug() << "Squawk is crashing..."; exit(1); return false; } void Root::onCoreDestroyed() { core = nullptr; }