Refactor macOS startup code

Moves all the stuff that is needed to start DBus on macOS (which for some reason it needs several steps, involving the use of `launchctl`) into a single `startDBusDaemon()` function. Before, it was spread into `kdeconnectconfig.cpp`, `indicatorhelper_mac.cpp` and `dbushelper.cpp`.

It also removes checking for an existing DBus daemon and always starts our own, since in most cases we couldn't connect to it anyway. This, together with removing the sleep in the retries when polling for the DBus daemon from 3s to 100ms, makes the startup much faster, so I removed the loading splash screen.
This commit is contained in:
Albert Vaca Cintora 2024-09-21 09:27:24 +00:00
parent d73cfa15b2
commit bbcbec7709
12 changed files with 149 additions and 336 deletions

View file

@ -1,11 +1,5 @@
add_definitions(-DTRANSLATION_DOMAIN=\"kdeconnect-core\") add_definitions(-DTRANSLATION_DOMAIN=\"kdeconnect-core\")
set(KDECONNECT_PRIVATE_DBUS_ADDR unix:tmpdir=/tmp)
if(WIN32)
set(KDECONNECT_PRIVATE_DBUS_ADDR tcp:host=localhost,port=0)
endif()
set(KDECONNECT_PRIVATE_DBUS_NAME DBusKDEConnectOnly)
configure_file(dbushelper.h.in ${CMAKE_CURRENT_BINARY_DIR}/dbushelper.h)
option(MDNS_ENABLED "Use MDNS for device discovery" ON) option(MDNS_ENABLED "Use MDNS for device discovery" ON)

View file

@ -18,28 +18,15 @@
#include "kdeconnectconfig.h" #include "kdeconnectconfig.h"
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
#include <KLocalizedString>
#include <QRegularExpression> #include <QRegularExpression>
#include <QRegularExpressionMatch> #include <QRegularExpressionMatch>
#include <QStandardPaths>
#include <QThread>
#endif #endif
namespace DBusHelper namespace DBusHelper
{ {
#ifdef Q_OS_MAC
class DBusInstancePrivate
{
public:
DBusInstancePrivate();
~DBusInstancePrivate();
void launchDBusDaemon();
void closeDBusDaemon();
private:
QProcess *m_dbusProcess;
};
static DBusInstancePrivate dbusInstance;
#endif
void filterNonExportableCharacters(QString &s) void filterNonExportableCharacters(QString &s)
{ {
@ -48,35 +35,56 @@ void filterNonExportableCharacters(QString &s)
} }
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
void launchDBusDaemon()
const QString PrivateDbusAddr = QStringLiteral("unix:tmpdir=/tmp");
const QString PrivateDBusAddressPath = QStringLiteral("/tmp/private_dbus_address");
const QString DBUS_LAUNCHD_SESSION_BUS_SOCKET = QStringLiteral("DBUS_LAUNCHD_SESSION_BUS_SOCKET");
QProcess *m_dbusProcess = nullptr;
void setLaunchctlEnv(const QString &env)
{ {
dbusInstance.launchDBusDaemon(); QProcess setLaunchdDBusEnv;
qAddPostRoutine(closeDBusDaemon); setLaunchdDBusEnv.setProgram(QStringLiteral("launchctl"));
setLaunchdDBusEnv.setArguments({QStringLiteral("setenv"), DBUS_LAUNCHD_SESSION_BUS_SOCKET, env});
setLaunchdDBusEnv.start();
setLaunchdDBusEnv.waitForFinished();
} }
void closeDBusDaemon() void unsetLaunchctlEnv()
{ {
dbusInstance.closeDBusDaemon();
}
void macosUnsetLaunchctlEnv()
{
// Unset Launchd env
QProcess unsetLaunchdDBusEnv; QProcess unsetLaunchdDBusEnv;
unsetLaunchdDBusEnv.setProgram(QStringLiteral("launchctl")); unsetLaunchdDBusEnv.setProgram(QStringLiteral("launchctl"));
unsetLaunchdDBusEnv.setArguments({QStringLiteral("unsetenv"), QStringLiteral(KDECONNECT_SESSION_DBUS_LAUNCHD_ENV)}); unsetLaunchdDBusEnv.setArguments({QStringLiteral("unsetenv"), DBUS_LAUNCHD_SESSION_BUS_SOCKET});
unsetLaunchdDBusEnv.start(); unsetLaunchdDBusEnv.start();
unsetLaunchdDBusEnv.waitForFinished(); unsetLaunchdDBusEnv.waitForFinished();
} }
void DBusInstancePrivate::launchDBusDaemon() void stopDBusDaemon()
{ {
// Kill old dbus daemon if (m_dbusProcess != nullptr) {
if (m_dbusProcess != nullptr) m_dbusProcess->terminate();
closeDBusDaemon(); m_dbusProcess->waitForFinished();
delete m_dbusProcess;
m_dbusProcess = nullptr;
unsetLaunchctlEnv();
}
}
// Start dbus daemon int startDBusDaemon()
m_dbusProcess = new QProcess(); {
if (m_dbusProcess) {
return 0;
}
qAddPostRoutine(stopDBusDaemon);
// Unset launchctl env and private dbus addr file, avoid block
unsetLaunchctlEnv();
QFile privateDBusAddressFile(PrivateDBusAddressPath);
if (privateDBusAddressFile.exists()) {
privateDBusAddressFile.resize(0);
}
QString kdeconnectDBusConfiguration; QString kdeconnectDBusConfiguration;
QString dbusDaemonExecutable = QStandardPaths::findExecutable(QStringLiteral("dbus-daemon"), {QCoreApplication::applicationDirPath()}); QString dbusDaemonExecutable = QStandardPaths::findExecutable(QStringLiteral("dbus-daemon"), {QCoreApplication::applicationDirPath()});
@ -87,60 +95,70 @@ void DBusInstancePrivate::launchDBusDaemon()
dbusDaemonExecutable = QLatin1String(qgetenv("craftRoot")) + QLatin1String("/../bin/dbus-daemon"); dbusDaemonExecutable = QLatin1String(qgetenv("craftRoot")) + QLatin1String("/../bin/dbus-daemon");
kdeconnectDBusConfiguration = QLatin1String(qgetenv("craftRoot")) + QLatin1String("/../share/dbus-1/session.conf"); kdeconnectDBusConfiguration = QLatin1String(qgetenv("craftRoot")) + QLatin1String("/../share/dbus-1/session.conf");
} }
m_dbusProcess = new QProcess();
m_dbusProcess->setProgram(dbusDaemonExecutable); m_dbusProcess->setProgram(dbusDaemonExecutable);
m_dbusProcess->setArguments({QStringLiteral("--print-address"), m_dbusProcess->setArguments({QStringLiteral("--print-address"),
QStringLiteral("--nofork"), QStringLiteral("--nofork"),
QStringLiteral("--config-file=") + kdeconnectDBusConfiguration, QStringLiteral("--config-file"),
QStringLiteral("--address=") + QStringLiteral(KDECONNECT_PRIVATE_DBUS_ADDR)}); kdeconnectDBusConfiguration,
QStringLiteral("--address"),
PrivateDbusAddr});
m_dbusProcess->setWorkingDirectory(QCoreApplication::applicationDirPath()); m_dbusProcess->setWorkingDirectory(QCoreApplication::applicationDirPath());
m_dbusProcess->setStandardOutputFile(KdeConnectConfig::instance().privateDBusAddressPath()); m_dbusProcess->setStandardOutputFile(PrivateDBusAddressPath);
m_dbusProcess->setStandardErrorFile(QProcess::nullDevice());
m_dbusProcess->start(); m_dbusProcess->start();
m_dbusProcess->waitForStarted(); // Avoid potential racing condition m_dbusProcess->waitForStarted();
QFile dbusAddressFile(PrivateDBusAddressPath);
if (!dbusAddressFile.open(QFile::ReadOnly | QFile::Text)) {
qCCritical(KDECONNECT_CORE) << "Private DBus enabled but error read private dbus address conf";
return -1;
}
QTextStream in(&dbusAddressFile);
qCDebug(KDECONNECT_CORE) << "Waiting for private dbus";
int retry = 0;
QString addr = in.readLine();
while (addr.length() == 0 && retry < 150) {
qCDebug(KDECONNECT_CORE) << "Retry reading private DBus address";
QThread::msleep(100);
retry++;
addr = in.readLine(); // Read until first not empty line
}
if (addr.length() == 0) {
qCCritical(KDECONNECT_CORE) << "Private DBus enabled but read private dbus address failed";
return -2;
}
qCDebug(KDECONNECT_CORE) << "Private dbus address: " << addr;
#ifdef Q_OS_MAC
// Set launchctl env
QString privateDBusAddress = KdeConnectConfig::instance().privateDBusAddress();
QRegularExpressionMatch path; QRegularExpressionMatch path;
if (privateDBusAddress.contains(QRegularExpression(QStringLiteral("path=(?<path>/tmp/dbus-[A-Za-z0-9]+)")), &path)) { if (!addr.contains(QRegularExpression(QStringLiteral("path=(?<path>/tmp/dbus-[A-Za-z0-9]+)")), &path)) {
qCDebug(KDECONNECT_CORE) << "DBus address: " << path.captured(QStringLiteral("path")); qCCritical(KDECONNECT_CORE) << "Fail to parse dbus address";
QProcess setLaunchdDBusEnv; return -3;
setLaunchdDBusEnv.setProgram(QStringLiteral("launchctl"));
setLaunchdDBusEnv.setArguments({QStringLiteral("setenv"), QStringLiteral(KDECONNECT_SESSION_DBUS_LAUNCHD_ENV), path.captured(QStringLiteral("path"))});
setLaunchdDBusEnv.start();
setLaunchdDBusEnv.waitForFinished();
} else {
qCDebug(KDECONNECT_CORE) << "Cannot get dbus address";
} }
#endif
}
void DBusInstancePrivate::closeDBusDaemon() QString dbusAddress = path.captured(QStringLiteral("path"));
{ qCDebug(KDECONNECT_CORE) << "DBus address: " << dbusAddress;
if (m_dbusProcess != nullptr) { if (dbusAddress.isEmpty()) {
m_dbusProcess->terminate(); qCCritical(KDECONNECT_CORE) << "Fail to extract dbus address";
m_dbusProcess->waitForFinished(); return -4;
delete m_dbusProcess;
m_dbusProcess = nullptr;
QFile privateDBusAddressFile(KdeConnectConfig::instance().privateDBusAddressPath());
if (privateDBusAddressFile.exists())
privateDBusAddressFile.resize(0);
macosUnsetLaunchctlEnv();
} }
setLaunchctlEnv(dbusAddress);
if (!QDBusConnection::sessionBus().isConnected()) {
qCCritical(KDECONNECT_CORE) << "Invalid env:" << dbusAddress;
return -5;
}
qCDebug(KDECONNECT_CORE) << "Private D-Bus daemon launched and connected.";
return 0;
} }
DBusInstancePrivate::DBusInstancePrivate() #endif // Q_OS_MAC
: m_dbusProcess(nullptr)
{
}
DBusInstancePrivate::~DBusInstancePrivate() } // namespace DBusHelper
{
closeDBusDaemon();
}
#endif
}

20
core/dbushelper.h Normal file
View file

@ -0,0 +1,20 @@
/**
* SPDX-FileCopyrightText: 2024 Albert Vaca <albertvaka@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#pragma once
#include <QDBusConnection>
#include <QString>
#include "kdeconnectcore_export.h"
namespace DBusHelper
{
void KDECONNECTCORE_EXPORT filterNonExportableCharacters(QString &s);
#ifdef Q_OS_MAC
int KDECONNECTCORE_EXPORT startDBusDaemon();
#endif
}

View file

@ -1,29 +0,0 @@
/**
* SPDX-FileCopyrightText: 2014 Albert Vaca <albertvaka@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#ifndef KDECONNECT_DBUSHELPER_H
#define KDECONNECT_DBUSHELPER_H
#include <QString>
#include <QDBusConnection>
#include "kdeconnectcore_export.h"
#define KDECONNECT_PRIVATE_DBUS_ADDR "${KDECONNECT_PRIVATE_DBUS_ADDR}"
#define KDECONNECT_PRIVATE_DBUS_NAME "${KDECONNECT_PRIVATE_DBUS_NAME}"
#define KDECONNECT_SESSION_DBUS_LAUNCHD_ENV "DBUS_LAUNCHD_SESSION_BUS_SOCKET"
namespace DBusHelper {
void KDECONNECTCORE_EXPORT filterNonExportableCharacters(QString& s);
#ifdef Q_OS_MAC
void KDECONNECTCORE_EXPORT launchDBusDaemon();
void KDECONNECTCORE_EXPORT closeDBusDaemon();
void KDECONNECTCORE_EXPORT macosUnsetLaunchctlEnv();
#endif
}
#endif

View file

@ -35,10 +35,6 @@ struct KdeConnectConfigPrivate {
QSettings *m_config; QSettings *m_config;
QSettings *m_trustedDevices; QSettings *m_trustedDevices;
#ifdef Q_OS_MAC
QString m_privateDBusAddress; // Private DBus Address cache
#endif
}; };
static QString getDefaultDeviceName() static QString getDefaultDeviceName()
@ -381,48 +377,3 @@ void KdeConnectConfig::generateCertificate(const QString &certPath)
Daemon::instance()->reportError(QStringLiteral("KDE Connect"), i18n("Could not store certificate file: %1", certPath)); Daemon::instance()->reportError(QStringLiteral("KDE Connect"), i18n("Could not store certificate file: %1", certPath));
} }
} }
#ifdef Q_OS_MAC
QString KdeConnectConfig::privateDBusAddressPath()
{
return baseConfigDir().absoluteFilePath(QStringLiteral("private_dbus_address"));
}
QString KdeConnectConfig::privateDBusAddress()
{
if (d->m_privateDBusAddress.length() != 0)
return d->m_privateDBusAddress;
QString dbusAddressPath = privateDBusAddressPath();
QFile dbusAddressFile(dbusAddressPath);
if (!dbusAddressFile.open(QFile::ReadOnly | QFile::Text)) {
qCCritical(KDECONNECT_CORE) << "Private DBus enabled but error read private dbus address conf";
exit(1);
}
QTextStream in(&dbusAddressFile);
qCDebug(KDECONNECT_CORE) << "Waiting for private dbus";
int retry = 0;
QString addr = in.readLine();
while (addr.length() == 0 && retry < 5) {
qCDebug(KDECONNECT_CORE) << "Retry reading private DBus address after 3s";
QThread::sleep(3);
retry++;
addr = in.readLine(); // Read until first not empty line
}
if (addr.length() == 0) {
qCCritical(KDECONNECT_CORE) << "Private DBus enabled but read private dbus address failed";
exit(1);
}
qCDebug(KDECONNECT_CORE) << "Private dbus address: " << addr;
d->m_privateDBusAddress = addr;
return addr;
}
#endif

View file

@ -61,13 +61,6 @@ public:
QDir deviceConfigDir(const QString &deviceId); QDir deviceConfigDir(const QString &deviceId);
QDir pluginConfigDir(const QString &deviceId, const QString &pluginName); // Used by KdeConnectPluginConfig QDir pluginConfigDir(const QString &deviceId, const QString &pluginName); // Used by KdeConnectPluginConfig
#ifdef Q_OS_MAC
/*
* Get private DBus Address when use private DBus
*/
QString privateDBusAddressPath();
QString privateDBusAddress();
#endif
private: private:
KdeConnectConfig(); KdeConnectConfig();

View file

@ -86,19 +86,10 @@ int main(int argc, char *argv[])
QCommandLineParser parser; QCommandLineParser parser;
QCommandLineOption replaceOption({QStringLiteral("replace")}, i18n("Replace an existing instance")); QCommandLineOption replaceOption({QStringLiteral("replace")}, i18n("Replace an existing instance"));
parser.addOption(replaceOption); parser.addOption(replaceOption);
#ifdef Q_OS_MAC
QCommandLineOption macosPrivateDBusOption({QStringLiteral("use-private-dbus")},
i18n("Launch a private D-Bus daemon with kdeconnectd (macOS test-purpose only)"));
parser.addOption(macosPrivateDBusOption);
#endif
aboutData.setupCommandLine(&parser); aboutData.setupCommandLine(&parser);
parser.process(app); parser.process(app);
#ifdef Q_OS_MAC
if (parser.isSet(macosPrivateDBusOption)) {
DBusHelper::launchDBusDaemon();
}
#endif
aboutData.processCommandLine(&parser); aboutData.processCommandLine(&parser);
if (parser.isSet(replaceOption)) { if (parser.isSet(replaceOption)) {
auto message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kdeconnect"), auto message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kdeconnect"),

View file

@ -12,23 +12,16 @@
IndicatorHelper::IndicatorHelper() IndicatorHelper::IndicatorHelper()
{ {
} }
IndicatorHelper::~IndicatorHelper() IndicatorHelper::~IndicatorHelper()
{ {
} }
void IndicatorHelper::preInit()
{
}
void IndicatorHelper::postInit()
{
}
void IndicatorHelper::iconPathHook() void IndicatorHelper::iconPathHook()
{ {
} }
int IndicatorHelper::daemonHook(QProcess & /*kdeconnectd*/) int IndicatorHelper::startDaemon()
{ {
return 0; return 0;
} }

View file

@ -7,9 +7,6 @@
#ifndef INDICATORHELPER_H #ifndef INDICATORHELPER_H
#define INDICATORHELPER_H #define INDICATORHELPER_H
#include <QProcess>
#include <QSplashScreen>
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include <QSystemTrayIcon> #include <QSystemTrayIcon>
#else #else
@ -17,6 +14,7 @@
#endif #endif
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include <QProcess>
#include <QUrl> #include <QUrl>
namespace processes namespace processes
{ {
@ -32,19 +30,12 @@ const QString kdeconnect_sms = QStringLiteral("kdeconnect-sms.exe");
class IndicatorHelper class IndicatorHelper
{ {
public: public:
#ifdef Q_OS_WIN
IndicatorHelper(const QUrl &indicatorUrl);
#else
IndicatorHelper(); IndicatorHelper();
#endif
~IndicatorHelper(); ~IndicatorHelper();
void preInit();
void postInit();
void iconPathHook(); void iconPathHook();
int daemonHook(QProcess &kdeconnectd); int startDaemon();
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
void systrayIconHook(QSystemTrayIcon &systray); void systrayIconHook(QSystemTrayIcon &systray);
@ -53,11 +44,9 @@ public:
#endif #endif
private: private:
#ifdef Q_OS_MAC
QSplashScreen *m_splashScreen;
#endif
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
QProcess kdeconnectd;
/** /**
* Terminate processes of KDE Connect like kdeconnectd.exe and dbus-daemon.exe * Terminate processes of KDE Connect like kdeconnectd.exe and dbus-daemon.exe
* *

View file

@ -4,55 +4,29 @@
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/ */
#include "indicatorhelper.h"
#include <KLocalizedString>
#include <QApplication> #include <QApplication>
#include <QDebug> #include <QDebug>
#include <QFile> #include <QFile>
#include <QIcon> #include <QIcon>
#include <QMessageBox> #include <QMessageBox>
#include <QProcess>
#include <QStandardPaths> #include <QStandardPaths>
#include <QThread> #include <QThread>
#include <KLocalizedString>
#include <dbushelper.h>
#include "indicatorhelper.h"
#include "serviceregister_mac.h" #include "serviceregister_mac.h"
#include <dbushelper.h>
#include <kdeconnectconfig.h> #include <kdeconnectconfig.h>
IndicatorHelper::IndicatorHelper() IndicatorHelper::IndicatorHelper()
{ {
registerServices(); registerServices();
// Use a hardcoded QPixmap because QIcon::fromTheme will instantiate a QPlatformTheme theme
// which could try to use DBus before we have started it and cache an invalid DBus session
// in QDBusConnectionManager
const QString iconPath = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("kdeconnect-icons"), QStandardPaths::LocateDirectory);
QPixmap splashPixmap(iconPath + QStringLiteral("/hicolor/scalable/apps/kdeconnect.svg"));
m_splashScreen = new QSplashScreen(splashPixmap);
// Icon is white, set the text color to black
m_splashScreen->showMessage(i18n("Launching") + QStringLiteral("\n"), Qt::AlignHCenter | Qt::AlignBottom, Qt::black);
m_splashScreen->show();
} }
IndicatorHelper::~IndicatorHelper() IndicatorHelper::~IndicatorHelper()
{ {
if (m_splashScreen != nullptr) {
delete m_splashScreen;
m_splashScreen = nullptr;
}
}
void IndicatorHelper::preInit()
{
}
void IndicatorHelper::postInit()
{
m_splashScreen->finish(nullptr);
} }
void IndicatorHelper::iconPathHook() void IndicatorHelper::iconPathHook()
@ -65,86 +39,26 @@ void IndicatorHelper::iconPathHook()
} }
} }
int IndicatorHelper::daemonHook(QProcess &kdeconnectd) int IndicatorHelper::startDaemon()
{ {
// This flag marks whether a session DBus daemon is installed and run int dbusStatus = DBusHelper::startDBusDaemon();
bool hasUsableSessionBus = true; if (dbusStatus) {
// Use another bus instance for detecting, avoid session bus cache in Qt
if (!QDBusConnection::connectToBus(QDBusConnection::SessionBus, QStringLiteral("kdeconnect-test-client")).isConnected()) {
qDebug() << "Default session bus not detected, will use private D-Bus.";
// Unset launchctl env and private dbus addr file, avoid block
DBusHelper::macosUnsetLaunchctlEnv();
QFile privateDBusAddressFile(KdeConnectConfig::instance().privateDBusAddressPath());
if (privateDBusAddressFile.exists())
privateDBusAddressFile.resize(0);
// Update session bus usability state
hasUsableSessionBus = false;
}
// Start daemon
m_splashScreen->showMessage(i18n("Launching daemon") + QStringLiteral("\n"), Qt::AlignHCenter | Qt::AlignBottom, Qt::black);
// Here we will try to bring our private session D-Bus
if (!hasUsableSessionBus) {
qDebug() << "Launching private session D-Bus.";
DBusHelper::macosUnsetLaunchctlEnv();
DBusHelper::launchDBusDaemon();
// Wait for dbus daemon env
QProcess getLaunchdDBusEnv;
m_splashScreen->showMessage(i18n("Waiting D-Bus") + QStringLiteral("\n"), Qt::AlignHCenter | Qt::AlignBottom, Qt::black);
getLaunchdDBusEnv.setProgram(QStringLiteral("launchctl"));
getLaunchdDBusEnv.setArguments({QStringLiteral("getenv"), QStringLiteral(KDECONNECT_SESSION_DBUS_LAUNCHD_ENV)});
getLaunchdDBusEnv.start();
getLaunchdDBusEnv.waitForFinished();
QString launchdDBusEnv = QString::fromLocal8Bit(getLaunchdDBusEnv.readAllStandardOutput());
if (!launchdDBusEnv.isEmpty() && QDBusConnection::sessionBus().isConnected()) {
qDebug() << "Private D-Bus daemon launched and connected.";
hasUsableSessionBus = true;
} else if (!launchdDBusEnv.isEmpty()) {
// Show a warning and exit
qCritical() << "Invalid " << KDECONNECT_SESSION_DBUS_LAUNCHD_ENV << "env: \"" << launchdDBusEnv << "\"";
QMessageBox::critical(nullptr, QMessageBox::critical(nullptr,
i18n("KDE Connect"), i18n("KDE Connect"),
i18n("Cannot connect to DBus\n" i18n("Cannot connect to DBus\n"
"KDE Connect will quit"), "KDE Connect will quit"),
QMessageBox::Abort, QMessageBox::Abort,
QMessageBox::Abort); QMessageBox::Abort);
// End the program QApplication::exit(dbusStatus);
return -1;
} else {
// Show a warning and exit
qCritical() << "Fail to get launchctl" << KDECONNECT_SESSION_DBUS_LAUNCHD_ENV << "env";
QMessageBox::critical(nullptr,
i18n("KDE Connect"),
i18n("Cannot connect to DBus\n"
"KDE Connect will quit"),
QMessageBox::Abort,
QMessageBox::Abort);
return -2;
}
// After D-Bus setting up, everything should go fine
QIcon kdeconnectIcon = QIcon::fromTheme(QStringLiteral("kdeconnect"));
m_splashScreen->setPixmap(QPixmap(kdeconnectIcon.pixmap(256, 256)));
} }
// Start kdeconnectd, the daemon will not duplicate when there is already one // Start kdeconnectd, the daemon will not duplicate when there is already one
if (QString daemon = QCoreApplication::applicationDirPath() + QLatin1String("/kdeconnectd"); QFile::exists(daemon)) { QString daemonPath = QCoreApplication::applicationDirPath() + QLatin1String("/kdeconnectd");
kdeconnectd.setProgram(daemon); if (!QFile::exists(daemonPath)) {
} else {
QMessageBox::critical(nullptr, i18n("KDE Connect"), i18n("Cannot find kdeconnectd"), QMessageBox::Abort, QMessageBox::Abort); QMessageBox::critical(nullptr, i18n("KDE Connect"), i18n("Cannot find kdeconnectd"), QMessageBox::Abort, QMessageBox::Abort);
return -1; QApplication::exit(-10);
} }
kdeconnectd.startDetached(); QProcess::startDetached(daemonPath);
m_splashScreen->showMessage(i18n("Loading modules") + QStringLiteral("\n"), Qt::AlignHCenter | Qt::AlignBottom, Qt::white);
return 0; return 0;
} }

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/ */
#include <QApplication>
#include <QDebug> #include <QDebug>
#include <QFile> #include <QFile>
#include <QIcon> #include <QIcon>
@ -14,17 +15,15 @@
#include <Windows.h> #include <Windows.h>
#include <tlhelp32.h> #include <tlhelp32.h>
#include <winrt/Windows.Foundation.Collections.h> #include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.UI.ViewManagement.h> #include <winrt/Windows.UI.ViewManagement.h>
#include "indicator_debug.h" #include "indicator_debug.h"
#include "indicatorhelper.h" #include "indicatorhelper.h"
winrt::Windows::UI::ViewManagement::UISettings uiSettings; winrt::Windows::UI::ViewManagement::UISettings uiSettings;
IndicatorHelper::IndicatorHelper(const QUrl &indicatorUrl) IndicatorHelper::IndicatorHelper()
: m_indicatorUrl(indicatorUrl) : m_indicatorUrl(QUrl::fromLocalFile(QApplication::applicationDirPath()))
{ {
uiSettings = winrt::Windows::UI::ViewManagement::UISettings(); uiSettings = winrt::Windows::UI::ViewManagement::UISettings();
} }
@ -39,14 +38,6 @@ IndicatorHelper::~IndicatorHelper()
this->terminateProcess(processes::kdeconnect_daemon, m_indicatorUrl); this->terminateProcess(processes::kdeconnect_daemon, m_indicatorUrl);
} }
void IndicatorHelper::preInit()
{
}
void IndicatorHelper::postInit()
{
}
void IndicatorHelper::iconPathHook() void IndicatorHelper::iconPathHook()
{ {
// FIXME: This doesn't seem to be enough for QIcon::fromTheme to find the icons, so we still have to use the full path when setting the icon // FIXME: This doesn't seem to be enough for QIcon::fromTheme to find the icons, so we still have to use the full path when setting the icon
@ -58,7 +49,7 @@ void IndicatorHelper::iconPathHook()
} }
} }
int IndicatorHelper::daemonHook(QProcess &kdeconnectd) int IndicatorHelper::startDaemon()
{ {
kdeconnectd.start(processes::kdeconnect_daemon, QStringList()); kdeconnectd.start(processes::kdeconnect_daemon, QStringList());
return 0; return 0;

View file

@ -49,6 +49,10 @@ int main(int argc, char **argv)
QIcon::setFallbackThemeName(QStringLiteral("breeze")); QIcon::setFallbackThemeName(QStringLiteral("breeze"));
QApplication app(argc, argv); QApplication app(argc, argv);
IndicatorHelper helper;
helper.startDaemon();
KAboutData about(QStringLiteral("kdeconnect-indicator"), KAboutData about(QStringLiteral("kdeconnect-indicator"),
i18n("KDE Connect Indicator"), i18n("KDE Connect Indicator"),
QStringLiteral(KDECONNECT_VERSION_STRING), QStringLiteral(KDECONNECT_VERSION_STRING),
@ -62,20 +66,8 @@ int main(int argc, char **argv)
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
KColorSchemeManager manager; KColorSchemeManager manager;
QApplication::setStyle(QStringLiteral("breeze")); QApplication::setStyle(QStringLiteral("breeze"));
IndicatorHelper helper(QUrl::fromLocalFile(qApp->applicationDirPath()));
#else
IndicatorHelper helper;
#endif #endif
helper.preInit();
// Run Daemon initialization step
// When run from macOS app bundle, D-Bus call should be later than kdeconnectd and D-Bus daemon
QProcess kdeconnectd;
if (helper.daemonHook(kdeconnectd)) {
return -1;
}
KDBusService dbusService(KDBusService::Unique); KDBusService dbusService(KDBusService::Unique);
// Trigger loading the KIconLoader plugin // Trigger loading the KIconLoader plugin
@ -130,7 +122,6 @@ int main(int argc, char **argv)
} }
// Add quit menu // Add quit menu
#if defined Q_OS_MAC #if defined Q_OS_MAC
menu->addAction(i18n("Quit"), []() { menu->addAction(i18n("Quit"), []() {
auto message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kdeconnect.daemon"), auto message = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kdeconnect.daemon"),
QStringLiteral("/MainApplication"), QStringLiteral("/MainApplication"),
@ -194,8 +185,5 @@ int main(int argc, char **argv)
app.setQuitOnLastWindowClosed(false); app.setQuitOnLastWindowClosed(false);
// Finish init
helper.postInit();
return app.exec(); return app.exec();
} }