File indexing completed on 2024-09-08 12:53:28
0001 /** 0002 * SPDX-FileCopyrightText: 2018-2019 Black Hat <bhat@encom.eu.org> 0003 * 0004 * SPDX-License-Identifier: GPL-3.0-only 0005 */ 0006 #include <QCommandLineParser> 0007 #include <QFontDatabase> 0008 #include <QNetworkProxy> 0009 #include <QNetworkProxyFactory> 0010 #include <QQmlApplicationEngine> 0011 #include <QQmlContext> 0012 #include <QQuickStyle> 0013 #include <QQuickWindow> 0014 #include <clocale> 0015 0016 #ifdef Q_OS_ANDROID 0017 #include <QGuiApplication> 0018 #else 0019 #include <QApplication> 0020 #endif 0021 0022 #include <KAboutData> 0023 #ifdef HAVE_KDBUSADDONS 0024 #include <KDBusService> 0025 #include <KWindowSystem> 0026 #endif 0027 #include <KConfig> 0028 #include <KLocalizedContext> 0029 #include <KLocalizedString> 0030 #include <KWindowConfig> 0031 0032 #include "tokodon-version.h" 0033 0034 #include "account/account.h" 0035 #include "account/accountmanager.h" 0036 #include "account/profileeditor.h" 0037 #include "account/socialgraphmodel.h" 0038 #include "admin/accounttoolmodel.h" 0039 #include "admin/adminaccountinfo.h" 0040 #include "admin/federationtoolmodel.h" 0041 #include "config.h" 0042 #include "conversation/conversationmodel.h" 0043 #include "editor/attachmenteditormodel.h" 0044 #include "editor/languagemodel.h" 0045 #include "editor/polltimemodel.h" 0046 #include "editor/posteditorbackend.h" 0047 #include "network/networkaccessmanagerfactory.h" 0048 #include "network/networkcontroller.h" 0049 #include "network/networkrequestprogress.h" 0050 #include "search/searchmodel.h" 0051 #include "timeline/accountmodel.h" 0052 #include "timeline/maintimelinemodel.h" 0053 #include "timeline/notificationmodel.h" 0054 #include "timeline/poll.h" 0055 #include "timeline/post.h" 0056 #include "timeline/tagstimelinemodel.h" 0057 #include "timeline/threadmodel.h" 0058 #include "utils/blurhashimageprovider.h" 0059 #include "utils/clipboard.h" 0060 #include "utils/filehelper.h" 0061 #include "utils/mpvplayer.h" 0062 #include "timeline/tagsmodel.h" 0063 0064 #ifdef HAVE_COLORSCHEME 0065 #include "utils/colorschemer.h" 0066 #endif 0067 0068 #ifdef Q_OS_WINDOWS 0069 #include <Windows.h> 0070 #endif 0071 0072 #ifdef Q_OS_ANDROID 0073 Q_DECL_EXPORT 0074 #endif 0075 int main(int argc, char *argv[]) 0076 { 0077 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0078 QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 0079 #endif 0080 0081 QNetworkProxyFactory::setUseSystemConfiguration(true); 0082 0083 #ifdef Q_OS_ANDROID 0084 QGuiApplication app(argc, argv); 0085 QQuickStyle::setStyle(QStringLiteral("org.kde.breeze")); 0086 QIcon::setThemeName("tokodon"); 0087 #else 0088 QApplication app(argc, argv); 0089 // Default to org.kde.desktop style unless the user forces another style 0090 if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE")) { 0091 QQuickStyle::setStyle(QStringLiteral("org.kde.desktop")); 0092 } 0093 0094 // Breeze theme needs to be the "primary" theme or else icons do not get recolored 0095 // Non-Breeze themes (like Adwaita) do not load our icons properly unless tokodon is the main icon theme. 0096 if (QIcon::themeName() == "breeze") { 0097 QIcon::setFallbackThemeName("tokodon"); 0098 } else { 0099 QIcon::setThemeName("tokodon"); 0100 } 0101 #endif 0102 0103 #ifdef Q_OS_WINDOWS 0104 if (AttachConsole(ATTACH_PARENT_PROCESS)) { 0105 freopen("CONOUT$", "w", stdout); 0106 freopen("CONOUT$", "w", stderr); 0107 } 0108 0109 QApplication::setStyle(QStringLiteral("breeze")); 0110 auto font = app.font(); 0111 font.setPointSize(10); 0112 app.setFont(font); 0113 #endif 0114 KLocalizedString::setApplicationDomain("tokodon"); 0115 0116 QCoreApplication::setOrganizationName("KDE"); 0117 0118 KAboutData about(QStringLiteral("tokodon"), 0119 i18n("Tokodon"), 0120 QStringLiteral(TOKODON_VERSION_STRING), 0121 i18n("Mastodon client"), 0122 KAboutLicense::GPL_V3, 0123 i18n("© 2021-2023 Carl Schwan, 2021-2023 KDE Community")); 0124 about.addAuthor(i18n("Carl Schwan"), i18n("Maintainer"), QStringLiteral("carl@carlschwan.eu")); 0125 about.setTranslator(i18nc("NAME OF TRANSLATORS", "Your names"), i18nc("EMAIL OF TRANSLATORS", "Your emails")); 0126 about.setOrganizationDomain("kde.org"); 0127 about.setBugAddress("https://bugs.kde.org/describecomponents.cgi?product=tokodon"); 0128 0129 KAboutData::setApplicationData(about); 0130 QGuiApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("org.kde.tokodon"))); 0131 0132 QCommandLineParser parser; 0133 parser.setApplicationDescription(i18n("Client for the decentralized social network: mastodon")); 0134 parser.addPositionalArgument(QStringLiteral("urls"), i18n("Supports web+ap: url scheme")); 0135 0136 about.setupCommandLine(&parser); 0137 parser.process(app); 0138 about.processCommandLine(&parser); 0139 0140 #ifdef HAVE_KDBUSADDONS 0141 KDBusService service(KDBusService::Unique); 0142 #endif 0143 auto config = Config::self(); 0144 0145 #ifdef HAVE_COLORSCHEME 0146 ColorSchemer colorScheme; 0147 qmlRegisterSingletonInstance<ColorSchemer>("org.kde.kmasto", 1, 0, "ColorSchemer", &colorScheme); 0148 if (!config->colorScheme().isEmpty()) { 0149 colorScheme.apply(config->colorScheme()); 0150 } 0151 #endif 0152 0153 // Qt sets the locale in the QGuiApplication constructor, but libmpv 0154 // requires the LC_NUMERIC category to be set to "C", so change it back. 0155 setlocale(LC_NUMERIC, "C"); 0156 0157 qmlRegisterSingletonInstance("org.kde.kmasto", 1, 0, "Config", config); 0158 qmlRegisterSingletonInstance("org.kde.kmasto", 1, 0, "Controller", &NetworkController::instance()); 0159 qmlRegisterSingletonInstance("org.kde.kmasto", 1, 0, "AccountManager", &AccountManager::instance()); 0160 qmlRegisterType<MainTimelineModel>("org.kde.kmasto", 1, 0, "MainTimelineModel"); 0161 qmlRegisterType<SearchModel>("org.kde.kmasto", 1, 0, "SearchModel"); 0162 qmlRegisterType<SocialGraphModel>("org.kde.kmasto", 1, 0, "SocialGraphModel"); 0163 qmlRegisterType<AccountsToolModel>("org.kde.kmasto", 1, 0, "AccountsToolModel"); 0164 qmlRegisterType<FederationToolModel>("org.kde.kmasto", 1, 0, "FederationToolModel"); 0165 qmlRegisterType<TagsModel>("org.kde.kmasto", 1, 0, "TagsModel"); 0166 qmlRegisterType<ThreadModel>("org.kde.kmasto", 1, 0, "ThreadModel"); 0167 qmlRegisterType<ConversationModel>("org.kde.kmasto", 1, 0, "ConversationModel"); 0168 qmlRegisterType<TagsTimelineModel>("org.kde.kmasto", 1, 0, "TagsTimelineModel"); 0169 qmlRegisterType<AccountModel>("org.kde.kmasto", 1, 0, "AccountModel"); 0170 qmlRegisterType<ProfileEditorBackend>("org.kde.kmasto", 1, 0, "ProfileEditorBackend"); 0171 qmlRegisterType<NetworkRequestProgress>("org.kde.kmasto", 1, 0, "NetworkRequestProgress"); 0172 qmlRegisterType<PostEditorBackend>("org.kde.kmasto", 1, 0, "PostEditorBackend"); 0173 qmlRegisterType<NotificationModel>("org.kde.kmasto", 1, 0, "NotificationModel"); 0174 qmlRegisterType<PollTimeModel>("org.kde.kmasto", 1, 0, "PollTimeModel"); 0175 qmlRegisterSingletonInstance("org.kde.kmasto", 1, 0, "Clipboard", new Clipboard); 0176 qmlRegisterSingletonInstance("org.kde.kmasto", 1, 0, "FileHelper", new FileHelper); 0177 qmlRegisterSingletonType("org.kde.kmasto", 1, 0, "About", [](QQmlEngine *engine, QJSEngine *) -> QJSValue { 0178 return engine->toScriptValue(KAboutData::applicationData()); 0179 }); 0180 qRegisterMetaType<Account *>("Account*"); 0181 qRegisterMetaType<FederationInfo>("FederationInfo"); 0182 qRegisterMetaType<AbstractAccount *>("AbstractAccount*"); 0183 qRegisterMetaType<Identity *>("Identity*"); 0184 qRegisterMetaType<AdminAccountInfo *>("AdminAccountInfo*"); 0185 qRegisterMetaType<AttachmentEditorModel *>("AttachmentEditorModel*"); 0186 qRegisterMetaType<Post *>("Post*"); 0187 qRegisterMetaType<Tag *>("Tag*"); 0188 qRegisterMetaType<Poll *>("Poll*"); 0189 qRegisterMetaType<Card *>("Card*"); 0190 qRegisterMetaType<Application *>("Application*"); 0191 qRegisterMetaType<QNetworkReply *>("QNetworkReply*"); 0192 qRegisterMetaType<Relationship *>("Relationship*"); 0193 qmlRegisterUncreatableType<Tag>("org.kde.kmasto", 1, 0, "Tag", "ENUM"); 0194 qmlRegisterUncreatableType<Post>("org.kde.kmasto", 1, 0, "Post", "ENUM"); 0195 qmlRegisterUncreatableType<AdminAccountInfo>("org.kde.kmasto", 1, 0, "AdminAccountInfo", "ENUM"); 0196 qmlRegisterUncreatableType<Attachment>("org.kde.kmasto", 1, 0, "Attachment", "ENUM"); 0197 qmlRegisterUncreatableType<Notification>("org.kde.kmasto", 1, 0, "Notification", "ENUM"); 0198 qmlRegisterUncreatableType<Poll>("org.kde.kmasto", 1, 0, "Poll", "ENUM"); 0199 qmlRegisterSingletonType(QUrl("qrc:/content/ui/Navigation.qml"), "org.kde.kmasto", 1, 0, "Navigation"); 0200 qmlRegisterType<LanguageModel>("org.kde.kmasto", 1, 0, "LanguageModel"); 0201 qmlRegisterType<MpvPlayer>("org.kde.kmasto", 1, 0, "MpvPlayer"); 0202 0203 QQmlApplicationEngine engine; 0204 engine.rootContext()->setContextObject(new KLocalizedContext(&engine)); 0205 QObject::connect(&engine, &QQmlApplicationEngine::quit, &app, &QCoreApplication::quit); 0206 0207 NetworkAccessManagerFactory namFactory; 0208 engine.setNetworkAccessManagerFactory(&namFactory); 0209 0210 // Controller::instance().setAboutData(about); 0211 0212 engine.addImageProvider(QLatin1String("blurhash"), new BlurhashImageProvider); 0213 0214 engine.load(QUrl(QStringLiteral("qrc:/content/ui/main.qml"))); 0215 if (engine.rootObjects().isEmpty()) { 0216 return -1; 0217 } 0218 0219 if (parser.positionalArguments().length() > 0) { 0220 NetworkController::instance().openWebApLink(parser.positionalArguments()[0]); 0221 } 0222 0223 #ifdef HAVE_KDBUSADDONS 0224 QObject::connect(&service, &KDBusService::activateRequested, &engine, [&engine](const QStringList &arguments, const QString & /*workingDirectory*/) { 0225 const auto rootObjects = engine.rootObjects(); 0226 for (auto obj : rootObjects) { 0227 auto view = qobject_cast<QQuickWindow *>(obj); 0228 if (view) { 0229 KWindowSystem::updateStartupId(view); 0230 KWindowSystem::activateWindow(view); 0231 0232 if (arguments.isEmpty()) { 0233 return; 0234 } 0235 0236 auto args = arguments; 0237 args.removeFirst(); 0238 0239 if (arguments.length() >= 1) { 0240 NetworkController::instance().openWebApLink(args[0]); 0241 } 0242 0243 return; 0244 } 0245 } 0246 }); 0247 const auto rootObjects = engine.rootObjects(); 0248 for (auto obj : rootObjects) { 0249 auto view = qobject_cast<QQuickWindow *>(obj); 0250 if (view) { 0251 KConfig dataResource("data", KConfig::SimpleConfig, QStandardPaths::AppDataLocation); 0252 KConfigGroup windowGroup(&dataResource, "Window"); 0253 KWindowConfig::restoreWindowSize(view, windowGroup); 0254 KWindowConfig::restoreWindowPosition(view, windowGroup); 0255 break; 0256 } 0257 } 0258 #endif 0259 return QCoreApplication::exec(); 0260 }