mirror of
https://git.jami.net/savoirfairelinux/jami-client-qt.git
synced 2025-07-03 23:25:28 +02:00
451 lines
14 KiB
C++
451 lines
14 KiB
C++
![]() |
/*
|
||
|
* Copyright (C) 2015-2020 by Savoir-faire Linux
|
||
|
* Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>
|
||
|
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
|
||
|
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
|
||
|
*
|
||
|
* 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 <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#include "mainapplication.h"
|
||
|
|
||
|
#include "accountadapter.h"
|
||
|
#include "accountlistmodel.h"
|
||
|
#include "accountstomigratelistmodel.h"
|
||
|
#include "audiocodeclistmodel.h"
|
||
|
#include "audioinputdevicemodel.h"
|
||
|
#include "audiomanagerlistmodel.h"
|
||
|
#include "audiooutputdevicemodel.h"
|
||
|
#include "avadapter.h"
|
||
|
#include "bannedlistmodel.h"
|
||
|
#include "calladapter.h"
|
||
|
#include "clientwrapper.h"
|
||
|
#include "contactadapter.h"
|
||
|
#include "conversationsadapter.h"
|
||
|
#include "deviceitemlistmodel.h"
|
||
|
#include "pluginitemlistmodel.h"
|
||
|
#include "preferenceitemlistmodel.h"
|
||
|
#include "distantrenderer.h"
|
||
|
#include "globalinstances.h"
|
||
|
#include "globalsystemtray.h"
|
||
|
#include "messagesadapter.h"
|
||
|
#include "namedirectory.h"
|
||
|
#include "pixbufmanipulator.h"
|
||
|
#include "previewrenderer.h"
|
||
|
#include "qrimageprovider.h"
|
||
|
#include "settingsadaptor.h"
|
||
|
#include "tintedbuttonimageprovider.h"
|
||
|
#include "utils.h"
|
||
|
#include "version.h"
|
||
|
#include "videocodeclistmodel.h"
|
||
|
#include "videoformatfpsmodel.h"
|
||
|
#include "videoformatresolutionmodel.h"
|
||
|
#include "videoinputdevicemodel.h"
|
||
|
|
||
|
#include <QFontDatabase>
|
||
|
#include <QQmlContext>
|
||
|
#include <QtWebEngine>
|
||
|
|
||
|
#include <locale.h>
|
||
|
|
||
|
#ifdef Q_OS_WIN
|
||
|
#include <windows.h>
|
||
|
#endif
|
||
|
|
||
|
#if defined _MSC_VER && !COMPILE_ONLY
|
||
|
#include <gnutls/gnutls.h>
|
||
|
#endif
|
||
|
|
||
|
MainApplication::MainApplication(int &argc, char **argv)
|
||
|
: QApplication(argc, argv)
|
||
|
, engine_(new QQmlApplicationEngine())
|
||
|
{
|
||
|
QObject::connect(this, &QApplication::aboutToQuit, [this] { exitApp(); });
|
||
|
}
|
||
|
|
||
|
void
|
||
|
MainApplication::applicationInitialization()
|
||
|
{
|
||
|
/*
|
||
|
* Some attributes are needed to be set before the creation of the application.
|
||
|
*/
|
||
|
QApplication::setApplicationName("Ring");
|
||
|
QApplication::setOrganizationDomain("jami.net");
|
||
|
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
|
||
|
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||
|
QApplication::setQuitOnLastWindowClosed(false);
|
||
|
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
|
||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||
|
QApplication::setHighDpiScaleFactorRoundingPolicy(
|
||
|
Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor);
|
||
|
/*
|
||
|
* Initialize QtWebEngine.
|
||
|
*/
|
||
|
QtWebEngine::initialize();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void
|
||
|
MainApplication::consoleDebug()
|
||
|
{
|
||
|
#ifdef Q_OS_WIN
|
||
|
AllocConsole();
|
||
|
SetConsoleCP(CP_UTF8);
|
||
|
|
||
|
freopen("CONOUT$", "w", stdout);
|
||
|
freopen("CONOUT$", "w", stderr);
|
||
|
|
||
|
COORD coordInfo;
|
||
|
coordInfo.X = 130;
|
||
|
coordInfo.Y = 9000;
|
||
|
|
||
|
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coordInfo);
|
||
|
SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void
|
||
|
MainApplication::vsConsoleDebug()
|
||
|
{
|
||
|
#ifdef _MSC_VER
|
||
|
/*
|
||
|
* Print debug to output window if using VS.
|
||
|
*/
|
||
|
QObject::connect(&LRCInstance::behaviorController(),
|
||
|
&lrc::api::BehaviorController::debugMessageReceived,
|
||
|
[](const QString &message) {
|
||
|
OutputDebugStringA((message + "\n").toStdString().c_str());
|
||
|
});
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void
|
||
|
MainApplication::fileDebug(QFile *debugFile)
|
||
|
{
|
||
|
QObject::connect(&LRCInstance::behaviorController(),
|
||
|
&lrc::api::BehaviorController::debugMessageReceived,
|
||
|
[debugFile](const QString &message) {
|
||
|
if (debugFile->open(QIODevice::WriteOnly | QIODevice::Append)) {
|
||
|
auto msg = (message + "\n").toStdString().c_str();
|
||
|
debugFile->write(msg, qstrlen(msg));
|
||
|
debugFile->close();
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
void
|
||
|
MainApplication::exitApp()
|
||
|
{
|
||
|
GlobalSystemTray::instance().hide();
|
||
|
#ifdef Q_OS_WIN
|
||
|
FreeConsole();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
char **
|
||
|
MainApplication::parseInputArgument(int &argc, char *argv[], char *argToParse)
|
||
|
{
|
||
|
/*
|
||
|
* Forcefully append argToParse.
|
||
|
*/
|
||
|
int oldArgc = argc;
|
||
|
argc = argc + 1 + 1;
|
||
|
char **newArgv = new char *[argc];
|
||
|
for (int i = 0; i < oldArgc; i++) {
|
||
|
newArgv[i] = argv[i];
|
||
|
}
|
||
|
newArgv[oldArgc] = argToParse;
|
||
|
newArgv[oldArgc + 1] = nullptr;
|
||
|
return newArgv;
|
||
|
}
|
||
|
|
||
|
QString
|
||
|
MainApplication::getDebugFilePath()
|
||
|
{
|
||
|
QDir logPath(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
|
||
|
/*
|
||
|
* Since logPath will be .../Ring, we use cdUp to remove it.
|
||
|
*/
|
||
|
logPath.cdUp();
|
||
|
return QString(logPath.absolutePath() + "/jami/jami.log");
|
||
|
}
|
||
|
|
||
|
void
|
||
|
MainApplication::loadTranslations()
|
||
|
{
|
||
|
auto appDir = qApp->applicationDirPath() + "/";
|
||
|
const auto locale_name = QLocale::system().name();
|
||
|
const auto locale_lang = locale_name.split('_')[0];
|
||
|
|
||
|
QTranslator *qtTranslator_lang = new QTranslator(this);
|
||
|
QTranslator *qtTranslator_name = new QTranslator(this);
|
||
|
if (locale_name != locale_lang) {
|
||
|
if (qtTranslator_lang->load("qt_" + locale_lang,
|
||
|
QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
|
||
|
installTranslator(qtTranslator_lang);
|
||
|
}
|
||
|
qtTranslator_name->load("qt_" + locale_name,
|
||
|
QLibraryInfo::location(QLibraryInfo::TranslationsPath));
|
||
|
installTranslator(qtTranslator_name);
|
||
|
|
||
|
QTranslator *lrcTranslator_lang = new QTranslator(this);
|
||
|
QTranslator *lrcTranslator_name = new QTranslator(this);
|
||
|
if (locale_name != locale_lang) {
|
||
|
if (lrcTranslator_lang->load(appDir + "share/libringclient/translations/lrc_" + locale_lang))
|
||
|
installTranslator(lrcTranslator_lang);
|
||
|
}
|
||
|
if (lrcTranslator_name->load(appDir + "share/libringclient/translations/lrc_" + locale_name))
|
||
|
installTranslator(lrcTranslator_name);
|
||
|
|
||
|
QTranslator *mainTranslator_lang = new QTranslator(this);
|
||
|
QTranslator *mainTranslator_name = new QTranslator(this);
|
||
|
if (locale_name != locale_lang) {
|
||
|
if (mainTranslator_lang->load(appDir + "share/ring/translations/ring_client_windows_"
|
||
|
+ locale_lang))
|
||
|
installTranslator(mainTranslator_lang);
|
||
|
}
|
||
|
if (mainTranslator_name->load(appDir + "share/ring/translations/ring_client_windows_"
|
||
|
+ locale_name))
|
||
|
installTranslator(mainTranslator_name);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
MainApplication::initLrc()
|
||
|
{
|
||
|
/*
|
||
|
* Init mainwindow and finish splash when mainwindow shows up.
|
||
|
*/
|
||
|
std::atomic_bool isMigrating(false);
|
||
|
LRCInstance::init(
|
||
|
[this, &isMigrating] {
|
||
|
/*
|
||
|
* TODO: splash screen for account migration.
|
||
|
*/
|
||
|
isMigrating = true;
|
||
|
while (isMigrating) {
|
||
|
this->processEvents();
|
||
|
}
|
||
|
},
|
||
|
[this, &isMigrating] {
|
||
|
while (!isMigrating) {
|
||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||
|
}
|
||
|
isMigrating = false;
|
||
|
});
|
||
|
LRCInstance::subscribeToDebugReceived();
|
||
|
LRCInstance::getAPI().holdConferences = false;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
MainApplication::processInputArgument(bool &startMinimized)
|
||
|
{
|
||
|
debugFile_ = std::make_unique<QFile>(getDebugFilePath());
|
||
|
QString uri = "";
|
||
|
|
||
|
for (auto string : QCoreApplication::arguments()) {
|
||
|
if (string.startsWith("jami:")) {
|
||
|
uri = string;
|
||
|
} else {
|
||
|
if (string == "-m" || string == "--minimized") {
|
||
|
startMinimized = true;
|
||
|
}
|
||
|
auto dbgFile = string == "-f" || string == "--file";
|
||
|
auto dbgConsole = string == "-c" || string == "--vsconsole";
|
||
|
if (dbgFile || dbgConsole) {
|
||
|
if (dbgFile) {
|
||
|
debugFile_->open(QIODevice::WriteOnly | QIODevice::Truncate);
|
||
|
debugFile_->close();
|
||
|
fileDebug(debugFile_.get());
|
||
|
}
|
||
|
#ifdef _MSC_VER
|
||
|
if (dbgConsole) {
|
||
|
vsConsoleDebug();
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
MainApplication::setApplicationFont()
|
||
|
{
|
||
|
QFont font;
|
||
|
font.setFamily("Segoe UI");
|
||
|
setFont(font);
|
||
|
QFontDatabase::addApplicationFont(":/images/FontAwesome.otf");
|
||
|
}
|
||
|
|
||
|
void
|
||
|
MainApplication::qmlInitialization()
|
||
|
{
|
||
|
/*
|
||
|
* Register accountListModel type.
|
||
|
*/
|
||
|
QML_REGISTERTYPE(AccountListModel, 1, 0);
|
||
|
QML_REGISTERTYPE(DeviceItemListModel, 1, 0);
|
||
|
QML_REGISTERTYPE(PluginItemListModel, 1, 0);
|
||
|
QML_REGISTERTYPE(PreferenceItemListModel, 1, 0);
|
||
|
QML_REGISTERTYPE(BannedListModel, 1, 0);
|
||
|
QML_REGISTERTYPE(VideoCodecListModel, 1, 0);
|
||
|
QML_REGISTERTYPE(AudioCodecListModel, 1, 0);
|
||
|
QML_REGISTERTYPE(AccountsToMigrateListModel, 1, 0);
|
||
|
QML_REGISTERTYPE(AudioInputDeviceModel, 1, 0);
|
||
|
QML_REGISTERTYPE(AudioOutputDeviceModel, 1, 0);
|
||
|
QML_REGISTERTYPE(AudioManagerListModel, 1, 0);
|
||
|
QML_REGISTERTYPE(VideoInputDeviceModel, 1, 0);
|
||
|
QML_REGISTERTYPE(VideoFormatResolutionModel, 1, 0);
|
||
|
QML_REGISTERTYPE(VideoFormatFpsModel, 1, 0);
|
||
|
/*
|
||
|
* Register QQuickItem type.
|
||
|
*/
|
||
|
QML_REGISTERTYPE(PreviewRenderer, 1, 0);
|
||
|
QML_REGISTERTYPE(VideoCallPreviewRenderer, 1, 0);
|
||
|
QML_REGISTERTYPE(DistantRenderer, 1, 0);
|
||
|
QML_REGISTERTYPE(PhotoboothPreviewRender, 1, 0)
|
||
|
|
||
|
/*
|
||
|
* Adapter - qmlRegisterSingletonType.
|
||
|
* Note: in future, if lrc is fully compatible with qml (C++ struct
|
||
|
* is readable in qml), the adapters can be optimized away.
|
||
|
*/
|
||
|
QML_REGISTERSINGLETONTYPE_URL(QStringLiteral("qrc:/src/constant/JamiTheme.qml"),
|
||
|
JamiTheme,
|
||
|
1,
|
||
|
0);
|
||
|
QML_REGISTERSINGLETONTYPE(CallAdapter, 1, 0);
|
||
|
|
||
|
QML_REGISTERSINGLETONTYPE(MessagesAdapter, 1, 0);
|
||
|
QML_REGISTERSINGLETONTYPE(ConversationsAdapter, 1, 0);
|
||
|
QML_REGISTERSINGLETONTYPE(AvAdapter, 1, 0);
|
||
|
QML_REGISTERSINGLETONTYPE(ContactAdapter, 1, 0);
|
||
|
QML_REGISTERSINGLETONTYPE(ClientWrapper, 1, 0);
|
||
|
|
||
|
//QML_REGISTERSINGLETONTYPE_WITH_INSTANCE(AccountAdapter, 1, 0);
|
||
|
//QML_REGISTERSINGLETONTYPE_WITH_INSTANCE(UtilsAdapter, 1, 0);
|
||
|
QML_REGISTERUNCREATABLE(AccountAdapter, 1, 0);
|
||
|
QML_REGISTERUNCREATABLE(UtilsAdapter, 1, 0);
|
||
|
QML_REGISTERUNCREATABLE(SettingsAdaptor, 1, 0);
|
||
|
QML_REGISTERUNCREATABLE(NameDirectory, 1, 0);
|
||
|
QML_REGISTERUNCREATABLE(LRCInstance, 1, 0);
|
||
|
|
||
|
/*
|
||
|
* Lrc models - qmlRegisterUncreatableType & Q_DECLARE_METATYPE.
|
||
|
* This to make lrc models recognizable in qml.
|
||
|
*/
|
||
|
QML_REGISTERUNCREATABLE_IN_NAMESPACE(NewAccountModel, lrc::api, 1, 0);
|
||
|
QML_REGISTERUNCREATABLE_IN_NAMESPACE(BehaviorController, lrc::api, 1, 0);
|
||
|
QML_REGISTERUNCREATABLE_IN_NAMESPACE(DataTransferModel, lrc::api, 1, 0);
|
||
|
QML_REGISTERUNCREATABLE_IN_NAMESPACE(AVModel, lrc::api, 1, 0);
|
||
|
QML_REGISTERUNCREATABLE_IN_NAMESPACE(ContactModel, lrc::api, 1, 0);
|
||
|
QML_REGISTERUNCREATABLE_IN_NAMESPACE(ConversationModel, lrc::api, 1, 0);
|
||
|
QML_REGISTERUNCREATABLE_IN_NAMESPACE(NewCallModel, lrc::api, 1, 0);
|
||
|
QML_REGISTERUNCREATABLE_IN_NAMESPACE(PluginModel, lrc::api, 1, 0);
|
||
|
QML_REGISTERUNCREATABLE_IN_NAMESPACE(NewDeviceModel, lrc::api, 1, 0);
|
||
|
QML_REGISTERUNCREATABLE_IN_NAMESPACE(NewCodecModel, lrc::api, 1, 0);
|
||
|
QML_REGISTERUNCREATABLE_IN_NAMESPACE(PeerDiscoveryModel, lrc::api, 1, 0);
|
||
|
|
||
|
/*
|
||
|
* Client models - qmlRegisterUncreatableType & Q_DECLARE_METATYPE.
|
||
|
* This to make client models recognizable in qml.
|
||
|
*/
|
||
|
QML_REGISTERUNCREATABLE(RenderManager, 1, 0);
|
||
|
|
||
|
/*
|
||
|
* Namespaces - qmlRegisterUncreatableMetaObject.
|
||
|
*/
|
||
|
QML_REGISTERNAMESPACE(lrc::api::staticMetaObject, "Lrc", 1, 0);
|
||
|
QML_REGISTERNAMESPACE(lrc::api::account::staticMetaObject, "Account", 1, 0);
|
||
|
QML_REGISTERNAMESPACE(lrc::api::call::staticMetaObject, "Call", 1, 0);
|
||
|
QML_REGISTERNAMESPACE(lrc::api::datatransfer::staticMetaObject, "Datatransfer", 1, 0);
|
||
|
QML_REGISTERNAMESPACE(lrc::api::interaction::staticMetaObject, "Interaction", 1, 0);
|
||
|
QML_REGISTERNAMESPACE(lrc::api::video::staticMetaObject, "Video", 1, 0);
|
||
|
QML_REGISTERNAMESPACE(lrc::api::profile::staticMetaObject, "Profile", 1, 0);
|
||
|
|
||
|
/*
|
||
|
* Add image provider.
|
||
|
*/
|
||
|
engine_->addImageProvider(QLatin1String("qrImage"), new QrImageProvider());
|
||
|
engine_->addImageProvider(QLatin1String("tintedPixmap"), new TintedButtonImageProvider());
|
||
|
|
||
|
engine_->load(QUrl(QStringLiteral("qrc:/src/MainApplicationWindow.qml")));
|
||
|
}
|
||
|
|
||
|
MainApplication::~MainApplication() {}
|
||
|
|
||
|
bool
|
||
|
MainApplication::applicationSetup()
|
||
|
{
|
||
|
#ifdef Q_OS_LINUX
|
||
|
if (!getenv("QT_QPA_PLATFORMTHEME"))
|
||
|
setenv("QT_QPA_PLATFORMTHEME", "gtk3", true);
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* Start debug console.
|
||
|
*/
|
||
|
for (auto string : QCoreApplication::arguments()) {
|
||
|
if (string == "-d" || string == "--debug") {
|
||
|
consoleDebug();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Remove old version files.
|
||
|
*/
|
||
|
Utils::removeOldVersions();
|
||
|
|
||
|
/*
|
||
|
* Load translations.
|
||
|
*/
|
||
|
loadTranslations();
|
||
|
|
||
|
/*
|
||
|
* Set font.
|
||
|
*/
|
||
|
setApplicationFont();
|
||
|
|
||
|
#if defined _MSC_VER && !COMPILE_ONLY
|
||
|
gnutls_global_init();
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* Init pixmap manipulator.
|
||
|
*/
|
||
|
GlobalInstances::setPixmapManipulator(std::make_unique<PixbufManipulator>());
|
||
|
|
||
|
/*
|
||
|
* Init lrc and its possible migration ui.
|
||
|
*/
|
||
|
initLrc();
|
||
|
|
||
|
/*
|
||
|
* Process input argument.
|
||
|
*/
|
||
|
bool startMinimized{false};
|
||
|
processInputArgument(startMinimized);
|
||
|
|
||
|
/*
|
||
|
* Create jami.net settings in Registry if it is not presented.
|
||
|
*/
|
||
|
QSettings settings("jami.net", "Jami");
|
||
|
|
||
|
/*
|
||
|
* Initialize qml components.
|
||
|
*/
|
||
|
qmlInitialization();
|
||
|
|
||
|
return true;
|
||
|
}
|