2021-07-06 10:20:46 -04:00
|
|
|
/*
|
2025-02-06 21:47:26 -04:00
|
|
|
* Copyright (C) 2015-2025 Savoir-faire Linux Inc.
|
2020-08-03 13:27:42 -04:00
|
|
|
*
|
|
|
|
* 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"
|
|
|
|
|
2024-02-01 16:43:55 -05:00
|
|
|
#include "global.h"
|
2021-03-30 15:15:36 -04:00
|
|
|
#include "qmlregister.h"
|
2020-09-01 14:31:31 -04:00
|
|
|
#include "appsettingsmanager.h"
|
2024-04-15 13:58:17 -04:00
|
|
|
#include "spellcheckdictionarymanager.h"
|
2020-09-17 16:08:52 -04:00
|
|
|
#include "connectivitymonitor.h"
|
2021-03-30 15:15:36 -04:00
|
|
|
#include "systemtray.h"
|
2023-11-16 15:27:07 -05:00
|
|
|
#include "previewengine.h"
|
2023-11-23 13:22:37 -05:00
|
|
|
#include "crashreporter.h"
|
2021-03-30 15:15:36 -04:00
|
|
|
|
2023-12-21 14:37:32 -05:00
|
|
|
#include <QWKQuick/qwkquickglobal.h>
|
|
|
|
|
2020-08-31 15:57:10 -04:00
|
|
|
#include <QAction>
|
2020-09-17 16:08:52 -04:00
|
|
|
#include <QCommandLineParser>
|
|
|
|
#include <QCoreApplication>
|
2020-08-03 13:27:42 -04:00
|
|
|
#include <QFontDatabase>
|
2020-08-31 15:57:10 -04:00
|
|
|
#include <QMenu>
|
2020-08-03 13:27:42 -04:00
|
|
|
#include <QQmlContext>
|
2021-04-08 16:03:25 -04:00
|
|
|
#include <QResource>
|
2022-08-10 10:36:39 -04:00
|
|
|
#include <QTimer>
|
2021-04-08 16:03:25 -04:00
|
|
|
#include <QTranslator>
|
|
|
|
#include <QLibraryInfo>
|
2022-03-16 17:36:17 -04:00
|
|
|
#include <QQuickWindow>
|
2020-08-03 13:27:42 -04:00
|
|
|
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
#include <windows.h>
|
|
|
|
#endif
|
|
|
|
|
2020-11-27 11:49:34 -05:00
|
|
|
#ifdef Q_OS_UNIX
|
|
|
|
#include "globalinstances.h"
|
|
|
|
#include "dbuserrorhandler.h"
|
|
|
|
#endif
|
|
|
|
|
2024-02-01 16:43:55 -05:00
|
|
|
Q_LOGGING_CATEGORY(clientLog, "client")
|
2024-01-03 19:05:55 -05:00
|
|
|
|
|
|
|
static const QtMessageHandler QT_DEFAULT_MESSAGE_HANDLER = qInstallMessageHandler(0);
|
|
|
|
|
|
|
|
void
|
|
|
|
messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
|
|
|
|
{
|
|
|
|
const static std::string fmt[5] = {"DBG", "WRN", "CRT", "FTL", "INF"};
|
|
|
|
const QByteArray localMsg = msg.toUtf8();
|
|
|
|
const auto ts = QString::number(QDateTime::currentMSecsSinceEpoch());
|
2024-02-15 17:38:36 -05:00
|
|
|
const auto tid = QString::number(reinterpret_cast<quintptr>(QThread::currentThreadId()), 16);
|
2024-01-03 19:05:55 -05:00
|
|
|
|
|
|
|
QString fileLineInfo = "";
|
2024-02-01 16:43:55 -05:00
|
|
|
const auto isQml = QString(context.category) == QLatin1String("qml");
|
2024-01-03 19:05:55 -05:00
|
|
|
#ifdef QT_DEBUG
|
2024-02-01 16:43:55 -05:00
|
|
|
// In debug mode, always include file URI (including line info).
|
|
|
|
// Only do this when the level Info/Debug, as it is already included in the constructed
|
|
|
|
// message for the other levels.
|
2024-01-22 18:25:29 -05:00
|
|
|
if (type == QtDebugMsg || type == QtInfoMsg || !isQml) {
|
2024-02-01 16:43:55 -05:00
|
|
|
auto fileName = isQml ? context.file : QUrl::fromLocalFile(context.file).toString();
|
|
|
|
fileLineInfo = QString(" %1:%2").arg(!fileName.isEmpty() ? fileName : "unknown",
|
|
|
|
context.line ? QString::number(context.line) : "0");
|
|
|
|
}
|
2024-01-03 19:05:55 -05:00
|
|
|
#else
|
|
|
|
// In release mode, include file and line info only for QML category which will always
|
|
|
|
// be available and provide a link to the source code in QtCreator.
|
2024-02-01 16:43:55 -05:00
|
|
|
if (isQml) {
|
2024-01-03 19:05:55 -05:00
|
|
|
fileLineInfo = QString("[%1:%2]").arg(context.file ? context.file : "unknown",
|
|
|
|
context.line ? QString::number(context.line) : "0");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2024-02-15 17:38:36 -05:00
|
|
|
const auto fmtMsg = QString("[%1][%2][%3]:%4 %5")
|
|
|
|
.arg(ts, fmt[type].c_str(), tid, fileLineInfo, localMsg.constData());
|
2024-01-03 19:05:55 -05:00
|
|
|
|
|
|
|
(*QT_DEFAULT_MESSAGE_HANDLER)(type, context, fmtMsg);
|
|
|
|
}
|
|
|
|
|
2022-03-16 17:36:17 -04:00
|
|
|
static QString
|
|
|
|
getRenderInterfaceString()
|
|
|
|
{
|
|
|
|
using GAPI = QSGRendererInterface::GraphicsApi;
|
|
|
|
switch (QQuickWindow::graphicsApi()) {
|
|
|
|
case GAPI::Direct3D11Rhi:
|
|
|
|
return "Direct3D11Rhi";
|
|
|
|
case GAPI::MetalRhi:
|
|
|
|
return "MetalRhi";
|
|
|
|
case GAPI::OpenGLRhi:
|
|
|
|
return "OpenGLRhi";
|
|
|
|
case GAPI::VulkanRhi:
|
|
|
|
return "VulkanRhi";
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2021-02-23 16:22:00 -05:00
|
|
|
void
|
|
|
|
ScreenInfo::setCurrentFocusWindow(QWindow* window)
|
|
|
|
{
|
|
|
|
if (window && !currentFocusWindow_) {
|
|
|
|
currentFocusWindow_ = window;
|
2021-09-08 10:31:38 -04:00
|
|
|
set_devicePixelRatio(currentFocusWindow_->screen()->devicePixelRatio());
|
2021-02-23 16:22:00 -05:00
|
|
|
|
2023-05-16 14:02:14 -04:00
|
|
|
QObject::connect(currentFocusWindow_,
|
|
|
|
&QWindow::screenChanged,
|
|
|
|
this,
|
|
|
|
&ScreenInfo::onScreenChanged,
|
|
|
|
Qt::UniqueConnection);
|
2021-02-23 16:22:00 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-16 14:02:14 -04:00
|
|
|
void
|
|
|
|
ScreenInfo::onScreenChanged()
|
|
|
|
{
|
|
|
|
currentFocusWindowScreen_ = currentFocusWindow_->screen();
|
|
|
|
set_devicePixelRatio(currentFocusWindowScreen_->devicePixelRatio());
|
|
|
|
|
|
|
|
QObject::connect(currentFocusWindowScreen_,
|
|
|
|
&QScreen::physicalDotsPerInchChanged,
|
|
|
|
this,
|
|
|
|
&ScreenInfo::onPhysicalDotsPerInchChanged,
|
|
|
|
Qt::UniqueConnection);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ScreenInfo::onPhysicalDotsPerInchChanged()
|
|
|
|
{
|
|
|
|
set_devicePixelRatio(currentFocusWindowScreen_->devicePixelRatio());
|
|
|
|
}
|
|
|
|
|
2020-09-01 14:31:31 -04:00
|
|
|
MainApplication::MainApplication(int& argc, char** argv)
|
2023-11-22 15:42:20 -05:00
|
|
|
: QApplication(argc, argv)
|
2020-08-03 13:27:42 -04:00
|
|
|
{
|
2022-03-08 14:44:53 -05:00
|
|
|
const char* qtVersion = qVersion();
|
|
|
|
if (strncmp(qtVersion, QT_VERSION_STR, strnlen(qtVersion, sizeof qtVersion)) != 0) {
|
2024-02-01 16:43:55 -05:00
|
|
|
C_FATAL << "Qt build version mismatch!" << QT_VERSION_STR;
|
2022-03-08 14:44:53 -05:00
|
|
|
}
|
|
|
|
|
2022-01-21 14:42:35 -05:00
|
|
|
parseArguments();
|
2024-01-03 19:05:55 -05:00
|
|
|
|
|
|
|
// Adjust the log levels as needed (as logging categories are added).
|
|
|
|
// Note: the following will cause detailed Qt logging and effectively spam the console
|
|
|
|
// without using `qt.*=false`. It may be useful for debugging Qt/QtQuick issues.
|
|
|
|
QLoggingCategory::setFilterRules("\n"
|
|
|
|
"*.debug=true\n"
|
2024-02-01 16:43:55 -05:00
|
|
|
"libclient.debug=false\n"
|
2024-01-03 19:05:55 -05:00
|
|
|
"qt.*=false\n"
|
|
|
|
"qml.debug=false\n"
|
2024-02-23 17:25:18 -05:00
|
|
|
"default.debug=false\n"
|
|
|
|
"client.debug=false\n"
|
2024-01-03 19:05:55 -05:00
|
|
|
"\n");
|
|
|
|
// These can be set in the environment as well.
|
|
|
|
// e.g. QT_LOGGING_RULES="*.debug=false;qml.debug=true"
|
|
|
|
|
|
|
|
// Tab align the log messages.
|
|
|
|
qSetMessagePattern("%{category}\t%{message}");
|
|
|
|
|
|
|
|
// Registration is done late here contrary to suggested practice in order to
|
|
|
|
// allow for the arguments to be parsed first in case we want to influence
|
|
|
|
// the logging features.
|
|
|
|
qInstallMessageHandler(messageHandler);
|
|
|
|
|
2024-02-01 16:43:55 -05:00
|
|
|
C_INFO << "Using Qt runtime version:" << qtVersion;
|
2020-08-03 13:27:42 -04:00
|
|
|
}
|
|
|
|
|
2021-12-22 17:36:29 -05:00
|
|
|
MainApplication::~MainApplication()
|
|
|
|
{
|
|
|
|
engine_.reset();
|
|
|
|
lrcInstance_.reset();
|
2023-11-23 13:22:37 -05:00
|
|
|
|
|
|
|
// Allow the crash reporter to do implementation-specific cleanup before the application exits.
|
|
|
|
delete crashReporter_;
|
2021-12-22 17:36:29 -05:00
|
|
|
}
|
2021-05-14 15:04:12 -04:00
|
|
|
|
2020-11-27 11:49:34 -05:00
|
|
|
bool
|
2020-09-01 14:31:31 -04:00
|
|
|
MainApplication::init()
|
2020-08-03 13:27:42 -04:00
|
|
|
{
|
2023-11-23 13:22:37 -05:00
|
|
|
// Let's make sure we can provide postmortem debugging information prior
|
|
|
|
// to any other initialization. This won't do anything if crashpad isn't
|
|
|
|
// enabled.
|
|
|
|
settingsManager_ = new AppSettingsManager(this);
|
2024-04-15 13:58:17 -04:00
|
|
|
spellCheckDictionaryManager_ = new SpellCheckDictionaryManager(settingsManager_, this);
|
2023-11-23 13:22:37 -05:00
|
|
|
crashReporter_ = new CrashReporter(settingsManager_, this);
|
|
|
|
|
2022-01-25 14:57:26 -05:00
|
|
|
// This 2-phase initialisation prevents ephemeral instances from
|
2024-12-01 20:03:37 -04:00
|
|
|
// performing unnecessary tasks, like initializing the WebEngine.
|
2022-01-25 14:57:26 -05:00
|
|
|
engine_.reset(new QQmlApplicationEngine(this));
|
|
|
|
|
2023-12-21 14:37:32 -05:00
|
|
|
QWK::registerTypes(engine_.get());
|
|
|
|
|
2023-11-14 17:53:00 -05:00
|
|
|
connectivityMonitor_ = new ConnectivityMonitor(this);
|
|
|
|
systemTray_ = new SystemTray(settingsManager_, this);
|
2023-11-16 15:27:07 -05:00
|
|
|
previewEngine_ = new PreviewEngine(connectivityMonitor_, this);
|
2023-11-14 17:53:00 -05:00
|
|
|
|
2023-11-22 15:42:20 -05:00
|
|
|
// These should should be QueuedConnection to ensure that the
|
|
|
|
// they are executed after the QML engine has been initialized,
|
|
|
|
// and after the QSystemTrayIcon has been created and shown.
|
2023-11-14 17:53:00 -05:00
|
|
|
QObject::connect(settingsManager_,
|
2022-02-01 17:07:16 -05:00
|
|
|
&AppSettingsManager::retranslate,
|
|
|
|
engine_.get(),
|
2023-11-22 15:42:20 -05:00
|
|
|
&QQmlApplicationEngine::retranslate,
|
|
|
|
Qt::QueuedConnection);
|
|
|
|
QObject::connect(settingsManager_,
|
|
|
|
&AppSettingsManager::retranslate,
|
|
|
|
this,
|
|
|
|
&MainApplication::initSystray,
|
|
|
|
Qt::QueuedConnection);
|
2022-02-01 17:07:16 -05:00
|
|
|
|
2021-07-19 23:52:58 -04:00
|
|
|
setWindowIcon(QIcon(":/images/jami.ico"));
|
2020-09-17 14:17:56 -04:00
|
|
|
|
2020-09-01 14:31:31 -04:00
|
|
|
Utils::removeOldVersions();
|
2023-02-14 14:01:40 -03:00
|
|
|
qputenv("JAMI_LANG", settingsManager_->getLanguage().toUtf8());
|
2022-01-28 12:11:04 -05:00
|
|
|
settingsManager_->loadTranslations();
|
2020-09-01 14:31:31 -04:00
|
|
|
setApplicationFont();
|
|
|
|
|
2022-01-21 14:42:35 -05:00
|
|
|
initLrc(runOptions_[Option::UpdateUrl].toString(),
|
2023-11-14 17:53:00 -05:00
|
|
|
connectivityMonitor_,
|
2023-06-27 07:58:48 -04:00
|
|
|
runOptions_[Option::Debug].toBool(),
|
|
|
|
runOptions_[Option::MuteDaemon].toBool());
|
2021-01-12 17:22:13 +01:00
|
|
|
|
2021-10-18 12:09:08 -04:00
|
|
|
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
|
2021-08-23 12:43:31 -04:00
|
|
|
using namespace Interfaces;
|
|
|
|
GlobalInstances::setDBusErrorHandler(std::make_unique<DBusErrorHandler>());
|
2020-11-27 11:49:34 -05:00
|
|
|
auto dBusErrorHandlerQObject = dynamic_cast<QObject*>(&GlobalInstances::dBusErrorHandler());
|
2021-08-23 12:43:31 -04:00
|
|
|
QML_REGISTERSINGLETONTYPE_CUSTOM(NS_MODELS, DBusErrorHandler, dBusErrorHandlerQObject);
|
2020-11-27 11:49:34 -05:00
|
|
|
if ((!lrc::api::Lrc::isConnected()) || (!lrc::api::Lrc::dbusIsValid())) {
|
2022-09-19 11:19:49 -04:00
|
|
|
engine_->load(QUrl(QStringLiteral("qrc:/DaemonReconnectWindow.qml")));
|
2020-11-27 11:49:34 -05:00
|
|
|
exec();
|
|
|
|
|
2022-01-21 14:42:35 -05:00
|
|
|
if ((!lrc::api::Lrc::isConnected()) || (!lrc::api::Lrc::dbusIsValid())) {
|
|
|
|
qWarning() << "Can't connect to the daemon via D-Bus.";
|
2020-11-27 11:49:34 -05:00
|
|
|
return false;
|
2022-01-21 14:42:35 -05:00
|
|
|
} else {
|
2020-11-27 11:49:34 -05:00
|
|
|
engine_.reset(new QQmlApplicationEngine());
|
2022-01-21 14:42:35 -05:00
|
|
|
}
|
2020-11-27 11:49:34 -05:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2023-11-14 17:53:00 -05:00
|
|
|
connect(connectivityMonitor_, &ConnectivityMonitor::connectivityChanged, this, [this] {
|
2022-08-10 10:36:39 -04:00
|
|
|
QTimer::singleShot(500, this, [&]() { lrcInstance_->connectivityChanged(); });
|
2020-09-14 13:04:57 -04:00
|
|
|
});
|
|
|
|
|
2021-02-23 16:22:00 -05:00
|
|
|
connect(this, &QGuiApplication::focusWindowChanged, [this] {
|
|
|
|
screenInfo_.setCurrentFocusWindow(this->focusWindow());
|
|
|
|
});
|
|
|
|
|
2021-03-30 15:15:36 -04:00
|
|
|
auto downloadPath = settingsManager_->getValue(Settings::Key::DownloadPath);
|
2023-01-10 16:47:18 -05:00
|
|
|
auto screenshotPath = settingsManager_->getValue(Settings::Key::ScreenshotPath);
|
2021-07-09 16:05:36 -04:00
|
|
|
auto allowTransferFromTrusted = settingsManager_->getValue(Settings::Key::AutoAcceptFiles)
|
|
|
|
.toBool();
|
|
|
|
auto acceptTransferBelow = settingsManager_->getValue(Settings::Key::AcceptTransferBelow).toInt();
|
2021-05-12 16:55:28 -04:00
|
|
|
lrcInstance_->accountModel().downloadDirectory = downloadPath.toString() + "/";
|
2023-01-10 16:47:18 -05:00
|
|
|
lrcInstance_->accountModel().screenshotDirectory = screenshotPath.toString();
|
2021-07-09 16:05:36 -04:00
|
|
|
lrcInstance_->accountModel().autoTransferFromTrusted = allowTransferFromTrusted;
|
|
|
|
lrcInstance_->accountModel().autoTransferSizeThreshold = acceptTransferBelow;
|
2021-03-30 15:15:36 -04:00
|
|
|
|
2022-01-25 13:10:12 -05:00
|
|
|
auto startMinimizedSetting = settingsManager_->getValue(Settings::Key::StartMinimized).toBool();
|
|
|
|
// The presence of start URI should override the startMinimized setting for this instance.
|
|
|
|
set_startMinimized(startMinimizedSetting && runOptions_[Option::StartUri].isNull());
|
2023-12-01 16:34:51 -05:00
|
|
|
|
2021-03-30 15:15:36 -04:00
|
|
|
initQmlLayer();
|
2021-12-23 14:22:08 -05:00
|
|
|
|
2022-01-11 13:38:57 -05:00
|
|
|
settingsManager_->setValue(Settings::Key::StartMinimized,
|
2022-01-21 14:42:35 -05:00
|
|
|
runOptions_[Option::StartMinimized].toBool());
|
2021-12-23 14:22:08 -05:00
|
|
|
|
2020-09-01 14:31:31 -04:00
|
|
|
initSystray();
|
2020-11-27 11:49:34 -05:00
|
|
|
|
|
|
|
return true;
|
2020-08-03 13:27:42 -04:00
|
|
|
}
|
|
|
|
|
2021-03-11 13:30:45 -05:00
|
|
|
void
|
|
|
|
MainApplication::restoreApp()
|
|
|
|
{
|
2021-03-29 16:51:53 -04:00
|
|
|
Q_EMIT lrcInstance_->restoreAppRequested();
|
2021-03-11 13:30:45 -05:00
|
|
|
}
|
|
|
|
|
2022-01-25 13:10:12 -05:00
|
|
|
void
|
|
|
|
MainApplication::handleUriAction(const QString& arg)
|
|
|
|
{
|
|
|
|
QString uri {};
|
|
|
|
if (arg.isEmpty() && !runOptions_[Option::StartUri].isNull()) {
|
|
|
|
uri = runOptions_[Option::StartUri].toString();
|
2024-02-01 16:43:55 -05:00
|
|
|
C_DBG << "URI action invoked by run option" << uri;
|
2022-03-28 09:54:32 -04:00
|
|
|
} else if (!arg.isEmpty()) {
|
2022-01-25 13:10:12 -05:00
|
|
|
uri = arg;
|
2024-02-01 16:43:55 -05:00
|
|
|
C_DBG << "URI action invoked by secondary instance" << uri;
|
2022-09-01 15:21:58 -04:00
|
|
|
Q_EMIT searchAndSelect(uri.replace("jami:", ""));
|
2022-01-25 13:10:12 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-03 13:27:42 -04:00
|
|
|
void
|
2023-06-27 07:58:48 -04:00
|
|
|
MainApplication::initLrc(const QString& downloadUrl,
|
|
|
|
ConnectivityMonitor* cm,
|
|
|
|
bool debugMode,
|
|
|
|
bool muteDaemon)
|
2020-08-03 13:27:42 -04:00
|
|
|
{
|
2024-02-15 12:05:14 -05:00
|
|
|
lrcInstance_.reset(new LRCInstance(downloadUrl, cm, debugMode, muteDaemon));
|
2021-03-11 13:30:45 -05:00
|
|
|
lrcInstance_->subscribeToDebugReceived();
|
2020-08-03 13:27:42 -04:00
|
|
|
}
|
|
|
|
|
2022-01-21 14:42:35 -05:00
|
|
|
void
|
2020-09-17 16:08:52 -04:00
|
|
|
MainApplication::parseArguments()
|
2020-09-11 15:19:19 -04:00
|
|
|
{
|
2022-01-25 13:10:12 -05:00
|
|
|
// See if the app is being started with a URI.
|
|
|
|
for (const auto& arg : QApplication::arguments()) {
|
|
|
|
if (arg.startsWith("jami:")) {
|
|
|
|
runOptions_[Option::StartUri] = arg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-01 19:06:01 -05:00
|
|
|
parser_.addHelpOption();
|
|
|
|
parser_.addVersionOption();
|
2020-09-17 16:08:52 -04:00
|
|
|
|
2020-09-29 11:41:38 -04:00
|
|
|
QCommandLineOption webDebugOption(QStringList() << "remote-debugging-port",
|
|
|
|
"Web debugging port.",
|
|
|
|
"port");
|
2024-02-01 19:06:01 -05:00
|
|
|
parser_.addOption(webDebugOption);
|
2020-09-29 11:41:38 -04:00
|
|
|
|
2021-06-21 13:15:58 -04:00
|
|
|
QCommandLineOption minimizedOption({"m", "minimized"}, "Start minimized.");
|
2024-02-01 19:06:01 -05:00
|
|
|
parser_.addOption(minimizedOption);
|
2020-09-17 16:08:52 -04:00
|
|
|
|
2021-06-21 13:15:58 -04:00
|
|
|
QCommandLineOption debugOption({"d", "debug"}, "Debug out.");
|
2024-02-01 19:06:01 -05:00
|
|
|
parser_.addOption(debugOption);
|
2020-09-11 15:19:19 -04:00
|
|
|
|
2022-03-11 18:07:50 -05:00
|
|
|
QCommandLineOption logFileOption({"f", "file"}, "Debug to <file>.", "file");
|
2024-02-01 19:06:01 -05:00
|
|
|
parser_.addOption(logFileOption);
|
2022-01-21 14:42:35 -05:00
|
|
|
|
2020-09-01 14:31:31 -04:00
|
|
|
#ifdef Q_OS_WINDOWS
|
2021-06-21 13:15:58 -04:00
|
|
|
QCommandLineOption updateUrlOption({"u", "url"}, "<url> for debugging version queries.", "url");
|
2024-02-01 19:06:01 -05:00
|
|
|
parser_.addOption(updateUrlOption);
|
2022-01-21 14:42:35 -05:00
|
|
|
|
2020-09-01 14:31:31 -04:00
|
|
|
#endif
|
2022-01-21 14:42:35 -05:00
|
|
|
QCommandLineOption terminateOption({"t", "term"}, "Terminate all instances.");
|
2024-02-01 19:06:01 -05:00
|
|
|
parser_.addOption(terminateOption);
|
2020-09-17 16:08:52 -04:00
|
|
|
|
2021-12-21 12:56:21 -05:00
|
|
|
QCommandLineOption muteDaemonOption({"q", "quiet"}, "Mute daemon logging. (only if debug)");
|
2024-02-01 19:06:01 -05:00
|
|
|
parser_.addOption(muteDaemonOption);
|
2021-06-21 13:15:58 -04:00
|
|
|
|
2024-02-01 19:06:01 -05:00
|
|
|
#ifdef QT_DEBUG
|
|
|
|
// In debug mode, add an option to test a specific QML component via its name.
|
|
|
|
// e.g. ./jami --test AccountComboBox
|
|
|
|
parser_.addOption(QCommandLineOption("test", "Test a QML component via its name.", "uri"));
|
|
|
|
// We may need to force the test window dimensions in the case that the component to test
|
|
|
|
// does not specify its own dimensions and is dependent on parent/sibling dimensions.
|
|
|
|
// e.g. ./jami --test AccountComboBox -w 200
|
|
|
|
parser_.addOption(QCommandLineOption("width", "Width for the test window.", "width"));
|
|
|
|
parser_.addOption(QCommandLineOption("height", "Height for the test window.", "height"));
|
|
|
|
#endif
|
2020-09-17 16:08:52 -04:00
|
|
|
|
2024-02-01 19:06:01 -05:00
|
|
|
parser_.process(*this);
|
|
|
|
|
|
|
|
runOptions_[Option::StartMinimized] = parser_.isSet(minimizedOption);
|
|
|
|
runOptions_[Option::Debug] = parser_.isSet(debugOption);
|
|
|
|
if (parser_.isSet(logFileOption)) {
|
|
|
|
auto logFileValue = parser_.value(logFileOption);
|
2022-03-11 18:07:50 -05:00
|
|
|
auto logFile = logFileValue.isEmpty() ? Utils::getDebugFilePath() : logFileValue;
|
|
|
|
qputenv("JAMI_LOG_FILE", logFile.toStdString().c_str());
|
|
|
|
}
|
2020-09-17 16:08:52 -04:00
|
|
|
#ifdef Q_OS_WINDOWS
|
2024-02-01 19:06:01 -05:00
|
|
|
runOptions_[Option::UpdateUrl] = parser_.value(updateUrlOption);
|
2020-09-17 16:08:52 -04:00
|
|
|
#endif
|
2024-02-01 19:06:01 -05:00
|
|
|
runOptions_[Option::TerminationRequested] = parser_.isSet(terminateOption);
|
|
|
|
runOptions_[Option::MuteDaemon] = parser_.isSet(muteDaemonOption);
|
2020-08-03 13:27:42 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MainApplication::setApplicationFont()
|
|
|
|
{
|
2022-11-25 16:09:44 -05:00
|
|
|
QStringList fontFamilies {"Ubuntu"};
|
|
|
|
#ifdef Q_OS_LINUX
|
|
|
|
QFontDatabase::addApplicationFont(":/fonts/NotoColorEmoji.ttf");
|
|
|
|
fontFamilies += "NotoColorEmoji";
|
|
|
|
#endif
|
2020-08-03 13:27:42 -04:00
|
|
|
QFont font;
|
2022-11-25 16:09:44 -05:00
|
|
|
font.setFamilies(fontFamilies);
|
2020-08-03 13:27:42 -04:00
|
|
|
setFont(font);
|
|
|
|
}
|
|
|
|
|
2024-02-01 19:06:01 -05:00
|
|
|
QString
|
|
|
|
findResource(const QString& targetBasename, const QString& basePath = ":/")
|
|
|
|
{
|
|
|
|
QDir dir(basePath);
|
|
|
|
// List all entries in the directory excluding special entries '.' and '..'
|
|
|
|
QStringList entries = dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot,
|
|
|
|
QDir::DirsFirst);
|
|
|
|
|
|
|
|
Q_FOREACH (const QString& entry, entries) {
|
|
|
|
QString fullPath = basePath + "/" + entry;
|
|
|
|
QFileInfo fileInfo(fullPath);
|
|
|
|
|
|
|
|
if (fileInfo.isDir()) {
|
|
|
|
// Recursively search in subdirectories
|
|
|
|
QString found = findResource(targetBasename, fullPath);
|
|
|
|
if (!found.isEmpty()) {
|
|
|
|
return found; // Return the first match found in any subdirectory
|
|
|
|
}
|
|
|
|
} else if (fileInfo.isFile()
|
|
|
|
&& fileInfo.fileName().contains(targetBasename, Qt::CaseInsensitive)) {
|
|
|
|
// Match found, return the full path but remove the leading ":/".
|
|
|
|
return fileInfo.absoluteFilePath().mid(2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// No match found in this directory or its subdirectories
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
2020-08-03 13:27:42 -04:00
|
|
|
void
|
2021-03-30 15:15:36 -04:00
|
|
|
MainApplication::initQmlLayer()
|
2020-08-03 13:27:42 -04:00
|
|
|
{
|
2021-07-13 17:19:43 -04:00
|
|
|
// Expose custom types to the QML engine.
|
|
|
|
Utils::registerTypes(engine_.get(),
|
|
|
|
lrcInstance_.get(),
|
2023-11-14 17:53:00 -05:00
|
|
|
systemTray_,
|
|
|
|
settingsManager_,
|
2024-04-15 13:58:17 -04:00
|
|
|
spellCheckDictionaryManager_,
|
2023-11-14 17:53:00 -05:00
|
|
|
connectivityMonitor_,
|
2023-11-16 15:27:07 -05:00
|
|
|
previewEngine_,
|
2021-07-13 17:19:43 -04:00
|
|
|
&screenInfo_,
|
|
|
|
this);
|
2020-11-27 11:49:34 -05:00
|
|
|
|
2023-11-23 13:22:37 -05:00
|
|
|
// Register the crash reporter as a context property in the QML engine.
|
|
|
|
engine_->rootContext()->setContextProperty("crashReporter", crashReporter_);
|
|
|
|
|
2025-03-30 18:15:57 -04:00
|
|
|
QUrl url = QStringLiteral("qrc:/MainApplicationWindow.qml");
|
2024-04-08 18:14:43 -04:00
|
|
|
#ifdef QT_DEBUG
|
2024-02-01 19:06:01 -05:00
|
|
|
if (parser_.isSet("test")) {
|
|
|
|
// List the QML files in the project source tree.
|
|
|
|
const auto targetTestComponent = findResource(parser_.value("test"));
|
|
|
|
if (targetTestComponent.isEmpty()) {
|
|
|
|
C_FATAL << "Failed to find QML component:" << parser_.value("test");
|
|
|
|
}
|
|
|
|
engine_->rootContext()->setContextProperty("testComponentURI", targetTestComponent);
|
|
|
|
// Log the width and height values for the test window.
|
|
|
|
const auto testWidth = parser_.isSet("width") ? parser_.value("width").toInt() : 0;
|
|
|
|
const auto testHeight = parser_.isSet("height") ? parser_.value("height").toInt() : 0;
|
|
|
|
engine_->rootContext()->setContextProperty("testWidth", testWidth);
|
|
|
|
engine_->rootContext()->setContextProperty("testHeight", testHeight);
|
2025-03-30 18:15:57 -04:00
|
|
|
url = QStringLiteral("qrc:/ComponentTestWindow.qml");
|
2024-02-01 19:06:01 -05:00
|
|
|
}
|
2024-04-08 18:14:43 -04:00
|
|
|
#endif
|
2024-02-01 19:06:01 -05:00
|
|
|
QObject::connect(
|
|
|
|
engine_.get(),
|
|
|
|
&QQmlApplicationEngine::objectCreationFailed,
|
|
|
|
this,
|
|
|
|
[url]() { C_FATAL << "Failed to load QML component:" << url; },
|
|
|
|
Qt::QueuedConnection);
|
|
|
|
engine_->load(url);
|
2024-01-31 13:04:48 -05:00
|
|
|
|
|
|
|
// Report the render interface used.
|
2024-02-23 17:25:18 -05:00
|
|
|
C_INFO << "Main window loaded using" << getRenderInterfaceString();
|
2020-08-03 13:27:42 -04:00
|
|
|
}
|
|
|
|
|
2020-09-01 14:31:31 -04:00
|
|
|
void
|
|
|
|
MainApplication::initSystray()
|
|
|
|
{
|
2021-07-19 23:52:58 -04:00
|
|
|
systemTray_->setIcon(QIcon(":/images/jami.svg"));
|
2020-08-31 15:57:10 -04:00
|
|
|
|
2023-11-24 12:01:19 -05:00
|
|
|
QMenu* menu {nullptr};
|
|
|
|
// If there was a previous menu, reuse it, otherwise create a new one.
|
|
|
|
if ((menu = systemTray_->contextMenu())) {
|
|
|
|
menu->clear();
|
|
|
|
} else {
|
|
|
|
menu = new QMenu;
|
|
|
|
}
|
2020-08-31 15:57:10 -04:00
|
|
|
|
2021-05-25 14:52:39 -04:00
|
|
|
QString quitString;
|
|
|
|
#ifdef Q_OS_WINDOWS
|
|
|
|
quitString = tr("E&xit");
|
|
|
|
#else
|
|
|
|
quitString = tr("&Quit");
|
|
|
|
#endif
|
|
|
|
|
2023-11-24 12:01:19 -05:00
|
|
|
QAction* quitAction = new QAction(quitString, this);
|
2022-01-11 13:38:57 -05:00
|
|
|
connect(quitAction, &QAction::triggered, this, &MainApplication::closeRequested);
|
2021-05-25 14:52:39 -04:00
|
|
|
|
2023-11-24 12:01:19 -05:00
|
|
|
QAction* restoreAction = new QAction(tr("&Show Jami"), this);
|
2021-06-02 11:11:36 -04:00
|
|
|
connect(restoreAction, &QAction::triggered, this, &MainApplication::restoreApp);
|
|
|
|
|
2023-11-14 17:53:00 -05:00
|
|
|
connect(systemTray_,
|
2021-03-30 15:15:36 -04:00
|
|
|
&QSystemTrayIcon::activated,
|
2022-01-11 13:38:57 -05:00
|
|
|
this,
|
2021-03-30 15:15:36 -04:00
|
|
|
[this](QSystemTrayIcon::ActivationReason reason) {
|
2021-05-31 15:28:30 -04:00
|
|
|
if (reason != QSystemTrayIcon::ActivationReason::Context) {
|
|
|
|
#ifdef Q_OS_WINDOWS
|
2021-03-30 15:15:36 -04:00
|
|
|
restoreApp();
|
2022-03-22 15:58:53 -04:00
|
|
|
#elif !defined(Q_OS_MACOS)
|
2023-11-24 12:01:19 -05:00
|
|
|
QWindow* window = focusWindow();
|
|
|
|
if (window)
|
|
|
|
window->close();
|
|
|
|
else
|
|
|
|
restoreApp();
|
2021-05-31 15:28:30 -04:00
|
|
|
#endif
|
|
|
|
}
|
2021-03-30 15:15:36 -04:00
|
|
|
});
|
2020-08-31 15:57:10 -04:00
|
|
|
|
2023-11-24 12:01:19 -05:00
|
|
|
menu->addAction(restoreAction);
|
|
|
|
menu->addAction(quitAction);
|
|
|
|
systemTray_->setContextMenu(menu);
|
2023-11-22 15:42:20 -05:00
|
|
|
|
2021-03-30 15:15:36 -04:00
|
|
|
systemTray_->show();
|
2020-09-01 14:31:31 -04:00
|
|
|
}
|
2020-08-31 15:57:10 -04:00
|
|
|
|
2022-02-03 17:16:47 -05:00
|
|
|
void
|
|
|
|
MainApplication::setEventFilter()
|
|
|
|
{
|
|
|
|
installEventFilter(this);
|
|
|
|
}
|