File indexing completed on 2024-09-29 10:12:46
0001 // SPDX-FileCopyrightText: 2018-2019 Black Hat <bhat@encom.eu.org> 0002 // SPDX-License-Identifier: GPL-3.0-only 0003 0004 #include <QCommandLineParser> 0005 #include <QIcon> 0006 #include <QNetworkProxyFactory> 0007 #include <QQmlApplicationEngine> 0008 #include <QQmlContext> 0009 #include <QQmlNetworkAccessManagerFactory> 0010 #include <QQuickStyle> 0011 #include <QQuickWindow> 0012 0013 #ifdef Q_OS_ANDROID 0014 #include <QGuiApplication> 0015 #else 0016 #include <QApplication> 0017 #endif 0018 0019 #include <KAboutData> 0020 #ifdef HAVE_KDBUSADDONS 0021 #include <KDBusService> 0022 #endif 0023 #ifdef HAVE_WINDOWSYSTEM 0024 #include <KWindowSystem> 0025 #endif 0026 #include <KLocalizedContext> 0027 #include <KLocalizedString> 0028 0029 #include "neochat-version.h" 0030 0031 #include <Quotient/keyverificationsession.h> 0032 #include <Quotient/accountregistry.h> 0033 #include <Quotient/networkaccessmanager.h> 0034 #include <Quotient/room.h> 0035 #include <Quotient/util.h> 0036 0037 #include "actionshandler.h" 0038 #include "blurhashimageprovider.h" 0039 #include "chatdocumenthandler.h" 0040 #include "clipboard.h" 0041 #include "controller.h" 0042 #include "delegatesizehelper.h" 0043 #include "filetypesingleton.h" 0044 #include "linkpreviewer.h" 0045 #include "locationhelper.h" 0046 #include "logger.h" 0047 #include "login.h" 0048 #include "matriximageprovider.h" 0049 #include "models/accountemoticonmodel.h" 0050 #include "models/collapsestateproxymodel.h" 0051 #include "models/customemojimodel.h" 0052 #include "models/devicesmodel.h" 0053 #include "models/devicesproxymodel.h" 0054 #include "models/emojimodel.h" 0055 #include "models/emoticonfiltermodel.h" 0056 #include "models/imagepacksmodel.h" 0057 #include "models/livelocationsmodel.h" 0058 #include "models/locationsmodel.h" 0059 #include "models/mediamessagefiltermodel.h" 0060 #include "models/messageeventmodel.h" 0061 #include "models/messagefiltermodel.h" 0062 #include "models/publicroomlistmodel.h" 0063 #include "models/pushrulemodel.h" 0064 #include "models/reactionmodel.h" 0065 #include "models/roomlistmodel.h" 0066 #include "models/searchmodel.h" 0067 #include "models/serverlistmodel.h" 0068 #include "models/sortfilterroomlistmodel.h" 0069 #include "models/sortfilterspacelistmodel.h" 0070 #include "models/statefiltermodel.h" 0071 #include "models/stickermodel.h" 0072 #include "models/userdirectorylistmodel.h" 0073 #include "models/userfiltermodel.h" 0074 #include "models/userlistmodel.h" 0075 #include "models/webshortcutmodel.h" 0076 #include "neochatconfig.h" 0077 #include "neochatroom.h" 0078 #include "neochatuser.h" 0079 #include "notificationsmanager.h" 0080 #include "pollhandler.h" 0081 #include "roommanager.h" 0082 #include "spacehierarchycache.h" 0083 #include "urlhelper.h" 0084 #include "windowcontroller.h" 0085 0086 #ifdef HAVE_COLORSCHEME 0087 #include "colorschemer.h" 0088 #endif 0089 #include "models/completionmodel.h" 0090 #include "models/statemodel.h" 0091 #include "neochatuser.h" 0092 0093 #ifdef HAVE_RUNNER 0094 #include "runner.h" 0095 #include <QDBusConnection> 0096 #endif 0097 0098 #ifdef Q_OS_WINDOWS 0099 #include <Windows.h> 0100 #endif 0101 0102 using namespace Quotient; 0103 0104 class NetworkAccessManagerFactory : public QQmlNetworkAccessManagerFactory 0105 { 0106 QNetworkAccessManager *create(QObject *) override 0107 { 0108 return NetworkAccessManager::instance(); 0109 } 0110 }; 0111 0112 static QWindow *windowFromEngine(QQmlApplicationEngine *engine) 0113 { 0114 const auto rootObjects = engine->rootObjects(); 0115 auto *window = qobject_cast<QQuickWindow *>(rootObjects.first()); 0116 Q_ASSERT(window); 0117 return window; 0118 } 0119 0120 #ifdef Q_OS_ANDROID 0121 Q_DECL_EXPORT 0122 #endif 0123 int main(int argc, char *argv[]) 0124 { 0125 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0126 QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 0127 #endif 0128 0129 QNetworkProxyFactory::setUseSystemConfiguration(true); 0130 0131 #ifdef Q_OS_ANDROID 0132 QGuiApplication app(argc, argv); 0133 QQuickStyle::setStyle(QStringLiteral("org.kde.breeze")); 0134 #else 0135 QIcon::setFallbackThemeName("breeze"); 0136 QApplication app(argc, argv); 0137 // Default to org.kde.desktop style unless the user forces another style 0138 if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE")) { 0139 QQuickStyle::setStyle(QStringLiteral("org.kde.desktop")); 0140 } 0141 #endif 0142 0143 #ifdef Q_OS_WINDOWS 0144 if (AttachConsole(ATTACH_PARENT_PROCESS)) { 0145 freopen("CONOUT$", "w", stdout); 0146 freopen("CONOUT$", "w", stderr); 0147 } 0148 0149 QApplication::setStyle(QStringLiteral("breeze")); 0150 QFont font(QStringLiteral("Segoe UI Emoji")); 0151 font.setPointSize(10); 0152 font.setHintingPreference(QFont::PreferNoHinting); 0153 app.setFont(font); 0154 #endif 0155 KLocalizedString::setApplicationDomain("neochat"); 0156 0157 QGuiApplication::setOrganizationName("KDE"); 0158 0159 KAboutData about(QStringLiteral("neochat"), 0160 i18n("NeoChat"), 0161 QStringLiteral(NEOCHAT_VERSION_STRING), 0162 i18n("Matrix client"), 0163 KAboutLicense::GPL_V3, 0164 i18n("© 2018-2020 Black Hat, 2020-2023 KDE Community")); 0165 about.addAuthor(i18n("Carl Schwan"), i18n("Maintainer"), QStringLiteral("carl@carlschwan.eu"), QStringLiteral("https://carlschwan.eu")); 0166 about.addAuthor(i18n("Tobias Fella"), i18n("Maintainer"), QStringLiteral("tobias.fella@kde.org"), QStringLiteral("https://tobiasfella.de")); 0167 about.addAuthor(i18n("James Graham"), i18n("Maintainer"), QStringLiteral("james.h.graham@protonmail.com")); 0168 about.addCredit(i18n("Black Hat"), i18n("Original author of Spectral"), QStringLiteral("bhat@encom.eu.org")); 0169 about.addCredit(i18n("Alexey Rusakov"), i18n("Maintainer of Quotient"), QStringLiteral("Kitsune-Ral@users.sf.net")); 0170 about.setTranslator(i18nc("NAME OF TRANSLATORS", "Your names"), i18nc("EMAIL OF TRANSLATORS", "Your emails")); 0171 about.setOrganizationDomain("kde.org"); 0172 0173 about.addComponent(QStringLiteral("libQuotient"), 0174 i18n("A Qt5 library to write cross-platform clients for Matrix"), 0175 i18nc("<version number> (built against <possibly different version number>)", 0176 "%1 (built against %2)", 0177 Quotient::versionString(), 0178 QStringLiteral(Quotient_VERSION_STRING)), 0179 QStringLiteral("https://github.com/quotient-im/libquotient"), 0180 KAboutLicense::LGPL_V2_1); 0181 0182 KAboutData::setApplicationData(about); 0183 QGuiApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("org.kde.neochat"))); 0184 0185 initLogging(); 0186 0187 #if Quotient_VERSION_MINOR == 8 0188 #ifdef Quotient_E2EE_ENABLED 0189 Connection::setEncryptionDefault(true); 0190 #endif 0191 #endif 0192 0193 #ifdef NEOCHAT_FLATPAK 0194 // Copy over the included FontConfig configuration to the 0195 // app's config dir: 0196 QFile::copy("/app/etc/fonts/conf.d/99-noto-mono-color-emoji.conf", "/var/config/fontconfig/conf.d/99-noto-mono-color-emoji.conf"); 0197 #endif 0198 0199 Clipboard clipboard; 0200 auto config = NeoChatConfig::self(); 0201 FileTypeSingleton fileTypeSingleton; 0202 0203 Login *login = new Login(); 0204 UrlHelper urlHelper; 0205 0206 #ifdef HAVE_COLORSCHEME 0207 ColorSchemer colorScheme; 0208 qmlRegisterSingletonInstance<ColorSchemer>("org.kde.neochat", 1, 0, "ColorSchemer", &colorScheme); 0209 if (!config->colorScheme().isEmpty()) { 0210 colorScheme.apply(config->colorScheme()); 0211 } 0212 #endif 0213 0214 qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "Controller", &Controller::instance()); 0215 qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "NotificationsManager", &NotificationsManager::instance()); 0216 qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "Clipboard", &clipboard); 0217 qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "Config", config); 0218 qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "RoomManager", &RoomManager::instance()); 0219 qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "FileType", &fileTypeSingleton); 0220 qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "LoginHelper", login); 0221 qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "UrlHelper", &urlHelper); 0222 qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "EmojiModel", &EmojiModel::instance()); 0223 qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "AccountRegistry", &Controller::instance().accounts()); 0224 qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "SpaceHierarchyCache", &SpaceHierarchyCache::instance()); 0225 qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "CustomEmojiModel", &CustomEmojiModel::instance()); 0226 qmlRegisterType<ActionsHandler>("org.kde.neochat", 1, 0, "ActionsHandler"); 0227 qmlRegisterType<ChatDocumentHandler>("org.kde.neochat", 1, 0, "ChatDocumentHandler"); 0228 qmlRegisterType<RoomListModel>("org.kde.neochat", 1, 0, "RoomListModel"); 0229 qmlRegisterType<KWebShortcutModel>("org.kde.neochat", 1, 0, "WebShortcutModel"); 0230 qmlRegisterType<UserListModel>("org.kde.neochat", 1, 0, "UserListModel"); 0231 qmlRegisterType<MessageEventModel>("org.kde.neochat", 1, 0, "MessageEventModel"); 0232 qmlRegisterType<ReactionModel>("org.kde.neochat", 1, 0, "ReactionModel"); 0233 qmlRegisterType<CollapseStateProxyModel>("org.kde.neochat", 1, 0, "CollapseStateProxyModel"); 0234 qmlRegisterType<MediaMessageFilterModel>("org.kde.neochat", 1, 0, "MediaMessageFilterModel"); 0235 qmlRegisterType<MessageFilterModel>("org.kde.neochat", 1, 0, "MessageFilterModel"); 0236 qmlRegisterType<UserFilterModel>("org.kde.neochat", 1, 0, "UserFilterModel"); 0237 qmlRegisterType<PublicRoomListModel>("org.kde.neochat", 1, 0, "PublicRoomListModel"); 0238 qmlRegisterType<UserDirectoryListModel>("org.kde.neochat", 1, 0, "UserDirectoryListModel"); 0239 qmlRegisterType<ServerListModel>("org.kde.neochat", 1, 0, "ServerListModel"); 0240 qmlRegisterType<SortFilterRoomListModel>("org.kde.neochat", 1, 0, "SortFilterRoomListModel"); 0241 qmlRegisterType<SortFilterSpaceListModel>("org.kde.neochat", 1, 0, "SortFilterSpaceListModel"); 0242 qmlRegisterType<DevicesModel>("org.kde.neochat", 1, 0, "DevicesModel"); 0243 qmlRegisterType<DevicesProxyModel>("org.kde.neochat", 1, 0, "DevicesProxyModel"); 0244 qmlRegisterType<LinkPreviewer>("org.kde.neochat", 1, 0, "LinkPreviewer"); 0245 qmlRegisterType<CompletionModel>("org.kde.neochat", 1, 0, "CompletionModel"); 0246 qmlRegisterType<StateModel>("org.kde.neochat", 1, 0, "StateModel"); 0247 qmlRegisterType<StateFilterModel>("org.kde.neochat", 1, 0, "StateFilterModel"); 0248 qmlRegisterType<SearchModel>("org.kde.neochat", 1, 0, "SearchModel"); 0249 qmlRegisterType<LiveLocationsModel>("org.kde.neochat", 1, 0, "LiveLocationsModel"); 0250 qmlRegisterType<LocationsModel>("org.kde.neochat", 1, 0, "LocationsModel"); 0251 qmlRegisterType<PollHandler>("org.kde.neochat", 1, 0, "PollHandler"); 0252 qmlRegisterType<PushRuleModel>("org.kde.neochat", 1, 0, "PushRuleModel"); 0253 qmlRegisterType<StickerModel>("org.kde.neochat", 1, 0, "StickerModel"); 0254 qmlRegisterType<ImagePacksModel>("org.kde.neochat", 1, 0, "ImagePacksModel"); 0255 qmlRegisterType<AccountEmoticonModel>("org.kde.neochat", 1, 0, "AccountEmoticonModel"); 0256 qmlRegisterType<EmoticonFilterModel>("org.kde.neochat", 1, 0, "EmoticonFilterModel"); 0257 qmlRegisterType<DelegateSizeHelper>("org.kde.neochat", 1, 0, "DelegateSizeHelper"); 0258 qmlRegisterUncreatableType<RoomMessageEvent>("org.kde.neochat", 1, 0, "RoomMessageEvent", "ENUM"); 0259 qmlRegisterUncreatableType<PushNotificationKind>("org.kde.neochat", 1, 0, "PushNotificationKind", "ENUM"); 0260 qmlRegisterUncreatableType<PushNotificationSection>("org.kde.neochat", 1, 0, "PushNotificationSection", "ENUM"); 0261 qmlRegisterUncreatableType<PushNotificationState>("org.kde.neochat", 1, 0, "PushNotificationState", "ENUM"); 0262 qmlRegisterUncreatableType<PushNotificationAction>("org.kde.neochat", 1, 0, "PushNotificationAction", "ENUM"); 0263 qmlRegisterUncreatableType<NeoChatRoomType>("org.kde.neochat", 1, 0, "NeoChatRoomType", "ENUM"); 0264 qmlRegisterUncreatableType<NeoChatUser>("org.kde.neochat", 1, 0, "NeoChatUser", {}); 0265 qmlRegisterUncreatableType<NeoChatRoom>("org.kde.neochat", 1, 0, "NeoChatRoom", {}); 0266 0267 qRegisterMetaType<User *>("User*"); 0268 qRegisterMetaType<User *>("const User*"); 0269 qRegisterMetaType<User *>("const Quotient::User*"); 0270 qRegisterMetaType<Room *>("Room*"); 0271 qRegisterMetaType<Connection *>("Connection*"); 0272 qRegisterMetaType<MessageEventType>("MessageEventType"); 0273 qRegisterMetaType<NeoChatRoom *>("NeoChatRoom*"); 0274 qRegisterMetaType<NeoChatUser *>("NeoChatUser*"); 0275 qRegisterMetaType<GetRoomEventsJob *>("GetRoomEventsJob*"); 0276 qRegisterMetaType<QMimeType>("QMimeType"); 0277 #ifdef Quotient_E2EE_ENABLED 0278 qRegisterMetaType<KeyVerificationSession *>("KeyVerificationSession*"); 0279 qmlRegisterUncreatableType<KeyVerificationSession>("org.kde.neochat", 1, 0, "KeyVerificationSession", {}); 0280 qRegisterMetaType<QVector<EmojiEntry>>("QVector<EmojiEntry>"); 0281 #endif 0282 qmlRegisterSingletonType("org.kde.neochat", 1, 0, "About", [](QQmlEngine *engine, QJSEngine *) -> QJSValue { 0283 return engine->toScriptValue(KAboutData::applicationData()); 0284 }); 0285 qmlRegisterSingletonType(QUrl("qrc:/OsmLocationPlugin.qml"), "org.kde.neochat", 1, 0, "OsmLocationPlugin"); 0286 qmlRegisterSingletonType("org.kde.neochat", 1, 0, "LocationHelper", [](QQmlEngine *engine, QJSEngine *) -> QJSValue { 0287 return engine->toScriptValue(LocationHelper()); 0288 }); 0289 0290 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0291 qRegisterMetaTypeStreamOperators<Emoji>(); 0292 #endif 0293 0294 QQmlApplicationEngine engine; 0295 0296 #ifdef HAVE_KDBUSADDONS 0297 KDBusService service(KDBusService::Unique); 0298 service.connect(&service, 0299 &KDBusService::activateRequested, 0300 &RoomManager::instance(), 0301 [&engine](const QStringList &arguments, const QString &workingDirectory) { 0302 Q_UNUSED(workingDirectory); 0303 0304 QWindow *window = windowFromEngine(&engine); 0305 KWindowSystem::updateStartupId(window); 0306 0307 WindowController::instance().showAndRaiseWindow(QString()); 0308 0309 // Open matrix uri 0310 if (arguments.isEmpty()) { 0311 return; 0312 } 0313 auto args = arguments; 0314 args.removeFirst(); 0315 for (const auto &arg : args) { 0316 RoomManager::instance().openResource(arg); 0317 } 0318 }); 0319 #endif 0320 0321 engine.rootContext()->setContextObject(new KLocalizedContext(&engine)); 0322 QObject::connect(&engine, &QQmlApplicationEngine::quit, &app, &QCoreApplication::quit); 0323 engine.setNetworkAccessManagerFactory(new NetworkAccessManagerFactory()); 0324 0325 QCommandLineParser parser; 0326 parser.setApplicationDescription(i18n("Client for the matrix communication protocol")); 0327 parser.addPositionalArgument(QStringLiteral("urls"), i18n("Supports matrix: url scheme")); 0328 0329 about.setupCommandLine(&parser); 0330 parser.process(app); 0331 about.processCommandLine(&parser); 0332 0333 engine.addImageProvider(QLatin1String("mxc"), new MatrixImageProvider); 0334 engine.addImageProvider(QLatin1String("blurhash"), new BlurhashImageProvider); 0335 0336 engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 0337 if (engine.rootObjects().isEmpty()) { 0338 return -1; 0339 } 0340 0341 if (parser.positionalArguments().length() > 0) { 0342 RoomManager::instance().setUrlArgument(parser.positionalArguments()[0]); 0343 } 0344 0345 #ifdef HAVE_RUNNER 0346 Runner runner; 0347 QDBusConnection::sessionBus().registerObject("/RoomRunner", &runner, QDBusConnection::ExportScriptableContents); 0348 #endif 0349 0350 QWindow *window = windowFromEngine(&engine); 0351 0352 WindowController::instance().setWindow(window); 0353 WindowController::instance().restoreGeometry(); 0354 0355 return app.exec(); 0356 }