File indexing completed on 2023-05-30 09:17:23
0001 /* 0002 * SPDX-FileCopyrightText: 2016 Aleix Pol Gonzalez <aleixpol@kde.org> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include <QApplication> 0008 #include <QPointer> 0009 #include <QProcess> 0010 #include <QThread> 0011 0012 #ifdef QSYSTRAY 0013 #include <QSystemTrayIcon> 0014 #else 0015 #include <KStatusNotifierItem> 0016 #endif 0017 0018 #include <KAboutData> 0019 #include <KCMultiDialog> 0020 #include <KColorSchemeManager> 0021 #include <KDBusService> 0022 #include <KLocalizedString> 0023 0024 #include "deviceindicator.h" 0025 #include "interfaces/dbusinterfaces.h" 0026 #include "interfaces/devicesmodel.h" 0027 #include "kdeconnect-version.h" 0028 0029 #include <dbushelper.h> 0030 0031 #include "indicatorhelper.h" 0032 0033 int main(int argc, char **argv) 0034 { 0035 QIcon::setFallbackThemeName(QStringLiteral("breeze")); 0036 QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); 0037 QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 0038 0039 QApplication app(argc, argv); 0040 KAboutData about(QStringLiteral("kdeconnect-indicator"), 0041 i18n("KDE Connect Indicator"), 0042 QStringLiteral(KDECONNECT_VERSION_STRING), 0043 i18n("KDE Connect Indicator tool"), 0044 KAboutLicense::GPL, 0045 i18n("(C) 2016 Aleix Pol Gonzalez")); 0046 KAboutData::setApplicationData(about); 0047 0048 #ifdef Q_OS_WIN 0049 KColorSchemeManager manager; 0050 QApplication::setStyle(QStringLiteral("breeze")); 0051 IndicatorHelper helper(QUrl::fromLocalFile(qApp->applicationDirPath())); 0052 #else 0053 IndicatorHelper helper; 0054 #endif 0055 0056 helper.preInit(); 0057 0058 // Run Daemon initialization step 0059 // When run from macOS app bundle, D-Bus call should be later than kdeconnectd and D-Bus daemon 0060 QProcess kdeconnectd; 0061 if (helper.daemonHook(kdeconnectd)) { 0062 return -1; 0063 } 0064 0065 KDBusService dbusService(KDBusService::Unique); 0066 0067 // Trigger loading the KIconLoader plugin 0068 about.setProgramLogo(QIcon(QStringLiteral(":/icons/kdeconnect/kdeconnect.svg"))); 0069 0070 DevicesModel model; 0071 model.setDisplayFilter(DevicesModel::Reachable | DevicesModel::Paired); 0072 QMenu *menu = new QMenu; 0073 0074 QPointer<KCMultiDialog> dialog; 0075 0076 DaemonDbusInterface iface; 0077 0078 auto refreshMenu = [&iface, &model, &menu, &helper, &dialog]() { 0079 menu->clear(); 0080 auto configure = menu->addAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("Configure...")); 0081 QObject::connect(configure, &QAction::triggered, configure, [&dialog]() { 0082 if (dialog == nullptr) { 0083 dialog = new KCMultiDialog; 0084 dialog->addModule(KPluginMetaData(QStringLiteral("plasma/kcms/systemsettings_qwidgets/kcm_kdeconnect"))); 0085 dialog->setAttribute(Qt::WA_DeleteOnClose); 0086 dialog->show(); 0087 dialog->raise(); 0088 } else { 0089 dialog->raise(); 0090 dialog->activateWindow(); 0091 } 0092 }); 0093 for (int i = 0, count = model.rowCount(); i < count; ++i) { 0094 DeviceDbusInterface *device = model.getDevice(i); 0095 auto indicator = new DeviceIndicator(device); 0096 QObject::connect(device, &DeviceDbusInterface::destroyed, indicator, &QObject::deleteLater); 0097 0098 menu->addMenu(indicator); 0099 } 0100 const QStringList requests = iface.pairingRequests(); 0101 if (!requests.isEmpty()) { 0102 menu->addSection(i18n("Pairing requests")); 0103 0104 for (const auto &req : requests) { 0105 DeviceDbusInterface *dev = new DeviceDbusInterface(req, menu); 0106 auto pairMenu = menu->addMenu(dev->name()); 0107 pairMenu->addAction(i18n("Pair"), dev, &DeviceDbusInterface::acceptPairing); 0108 pairMenu->addAction(i18n("Reject"), dev, &DeviceDbusInterface::rejectPairing); 0109 } 0110 } 0111 // Add quit menu 0112 #if defined Q_OS_MAC 0113 0114 menu->addAction(i18n("Quit"), []() { 0115 auto message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kdeconnect.daemon"), 0116 QStringLiteral("/MainApplication"), 0117 QStringLiteral("org.qtproject.Qt.QCoreApplication"), 0118 QStringLiteral("quit")); 0119 QDBusConnection::sessionBus().call(message, QDBus::NoBlock); 0120 qApp->quit(); 0121 }); 0122 #elif defined Q_OS_WIN 0123 0124 menu->addAction(QIcon::fromTheme(QStringLiteral("application-exit")), i18n("Quit"), []() { 0125 qApp->quit(); 0126 }); 0127 #endif 0128 }; 0129 0130 QObject::connect(&iface, &DaemonDbusInterface::pairingRequestsChangedProxy, &model, refreshMenu); 0131 QObject::connect(&model, &DevicesModel::rowsInserted, &model, refreshMenu); 0132 QObject::connect(&model, &DevicesModel::rowsRemoved, &model, refreshMenu); 0133 0134 // Run icon to add icon path (if necessary) 0135 helper.iconPathHook(); 0136 0137 #ifdef QSYSTRAY 0138 QSystemTrayIcon systray; 0139 helper.systrayIconHook(systray); 0140 systray.setVisible(true); 0141 systray.setToolTip(QStringLiteral("KDE Connect")); 0142 QObject::connect(&model, &DevicesModel::rowsChanged, &model, [&systray, &model]() { 0143 systray.setToolTip(i18np("%1 device connected", "%1 devices connected", model.rowCount())); 0144 }); 0145 QObject::connect(&systray, &QSystemTrayIcon::activated, [](QSystemTrayIcon::ActivationReason reason) { 0146 if (reason == QSystemTrayIcon::Trigger) { 0147 const QString kdeconnectAppExecutable = QStandardPaths::findExecutable(QStringLiteral("kdeconnect-app"), {QCoreApplication::applicationDirPath()}); 0148 if (!kdeconnectAppExecutable.isEmpty()) { 0149 QProcess::startDetached(kdeconnectAppExecutable, {}); 0150 } 0151 } 0152 }); 0153 0154 systray.setContextMenu(menu); 0155 #else 0156 KStatusNotifierItem systray; 0157 helper.systrayIconHook(systray); 0158 systray.setToolTip(QStringLiteral("kdeconnect"), QStringLiteral("KDE Connect"), QStringLiteral("KDE Connect")); 0159 systray.setCategory(KStatusNotifierItem::Communications); 0160 systray.setStatus(KStatusNotifierItem::Passive); 0161 systray.setStandardActionsEnabled(false); 0162 QObject::connect(&model, &DevicesModel::rowsChanged, &model, [&systray, &model]() { 0163 const auto count = model.rowCount(); 0164 #ifndef Q_OS_MACOS // On MacOS, setting status to Active disables color theme syncing of the menu icon 0165 systray.setStatus(count == 0 ? KStatusNotifierItem::Passive : KStatusNotifierItem::Active); 0166 #endif 0167 systray.setToolTip(QStringLiteral("kdeconnect"), QStringLiteral("KDE Connect"), i18np("%1 device connected", "%1 devices connected", count)); 0168 }); 0169 0170 systray.setContextMenu(menu); 0171 #endif 0172 0173 refreshMenu(); 0174 0175 app.setQuitOnLastWindowClosed(false); 0176 0177 // Finish init 0178 helper.postInit(); 0179 0180 return app.exec(); 0181 }