From 102bd219b7520fc4bcb0b41bcf9ed692686836d6 Mon Sep 17 00:00:00 2001 From: David Rosca Date: Tue, 19 Feb 2019 11:10:57 +0100 Subject: [PATCH] QtSingleApplication: Add DBus backend for Linux It should be more reliable than lockfile. BUG: 404494 FIXED-IN: 3.1.0 --- .../qtsingleapplication/qtlocalpeer.cpp | 65 +++++++++++++++++++ .../qtsingleapplication/qtlocalpeer.h | 1 + src/lib/app/mainapplication.cpp | 8 +-- 3 files changed, 70 insertions(+), 4 deletions(-) diff --git a/src/lib/3rdparty/qtsingleapplication/qtlocalpeer.cpp b/src/lib/3rdparty/qtsingleapplication/qtlocalpeer.cpp index c1cb96aa2..9c6613eda 100644 --- a/src/lib/3rdparty/qtsingleapplication/qtlocalpeer.cpp +++ b/src/lib/3rdparty/qtsingleapplication/qtlocalpeer.cpp @@ -44,6 +44,11 @@ #include #include +#include "../config.h" +#if defined(Q_OS_LINUX) && !defined(DISABLE_DBUS) +#define USE_DBUS +#endif + #if defined(Q_OS_WIN) #include #include @@ -65,6 +70,33 @@ namespace QtLP_Private { #endif } +#ifdef USE_DBUS +#include +#include +#include + +class QtSingleAppDBusInterface : public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.QtSingleApplication") + +public: + explicit QtSingleAppDBusInterface(QObject *parent) + : QDBusAbstractAdaptor(parent) + { + } + +public Q_SLOTS: + void SendMessage(const QString &message) + { + Q_EMIT messageReceived(message); + } + +Q_SIGNALS: + void messageReceived(const QString &message); +}; +#endif + const char* QtLocalPeer::ack = "ack"; QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId) @@ -100,18 +132,36 @@ QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId) socketName += QLatin1Char('-') + QString::number(::getuid(), 16); #endif +#ifdef USE_DBUS + if (!QDBusConnection::sessionBus().isConnected()) { + qCritical("Failed to connect to session bus!"); + } + m_dbusRegistered = QDBusConnection::sessionBus().registerService(id); + if (m_dbusRegistered) { + QtSingleAppDBusInterface *iface = new QtSingleAppDBusInterface(this); + connect(iface, &QtSingleAppDBusInterface::messageReceived, this, &QtLocalPeer::messageReceived); + QDBusConnection::sessionBus().registerObject(QStringLiteral("/"), this); + } +#else server = new QLocalServer(this); QString lockName = QDir(QDir::tempPath()).absolutePath() + QLatin1Char('/') + socketName + QLatin1String("-lockfile"); lockFile.setFileName(lockName); lockFile.open(QIODevice::ReadWrite); +#endif } bool QtLocalPeer::isClient() { +#ifdef USE_DBUS + if (m_dbusRegistered) { + return false; + } + return QDBusConnection::sessionBus().interface()->isServiceRegistered(id).value(); +#else if (lockFile.isLocked()) return false; @@ -130,6 +180,7 @@ bool QtLocalPeer::isClient() qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString())); QObject::connect(server, &QLocalServer::newConnection, this, &QtLocalPeer::receiveConnection); return false; +#endif } @@ -138,6 +189,13 @@ bool QtLocalPeer::sendMessage(const QString &message, int timeout) if (!isClient()) return false; +#ifdef USE_DBUS + QDBusMessage msg = QDBusMessage::createMethodCall(id, QStringLiteral("/"), + QStringLiteral("org.kde.QtSingleApplication"), + QStringLiteral("SendMessage")); + msg << message; + return QDBusConnection::sessionBus().call(msg, QDBus::Block, timeout).type() == QDBusMessage::ReplyMessage; +#else QLocalSocket socket; bool connOk = false; for(int i = 0; i < 2; i++) { @@ -167,15 +225,19 @@ bool QtLocalPeer::sendMessage(const QString &message, int timeout) res &= (socket.read(qstrlen(ack)) == ack); } return res; +#endif } void QtLocalPeer::removeLockedFile() { +#ifndef USE_DBUS lockFile.remove(); +#endif } void QtLocalPeer::receiveConnection() { +#ifndef USE_DBUS QLocalSocket* socket = server->nextPendingConnection(); if (!socket) return; @@ -214,4 +276,7 @@ void QtLocalPeer::receiveConnection() socket->waitForDisconnected(1000); // make sure client reads ack delete socket; emit messageReceived(message); //### (might take a long time to return) +#endif } + +#include "qtlocalpeer.moc" diff --git a/src/lib/3rdparty/qtsingleapplication/qtlocalpeer.h b/src/lib/3rdparty/qtsingleapplication/qtlocalpeer.h index 776a46162..e7c2e2efb 100644 --- a/src/lib/3rdparty/qtsingleapplication/qtlocalpeer.h +++ b/src/lib/3rdparty/qtsingleapplication/qtlocalpeer.h @@ -73,6 +73,7 @@ protected: private: static const char* ack; + bool m_dbusRegistered = false; }; #endif // QTLOCALPEER_H diff --git a/src/lib/app/mainapplication.cpp b/src/lib/app/mainapplication.cpp index 4202af601..1e89d169f 100644 --- a/src/lib/app/mainapplication.cpp +++ b/src/lib/app/mainapplication.cpp @@ -223,14 +223,14 @@ MainApplication::MainApplication(int &argc, char** argv) // Don't start single application in private browsing if (!isPrivate()) { - QString appId = QStringLiteral("FalkonWebBrowser"); + QString appId = QStringLiteral("org.kde.Falkon"); if (isPortable()) { - appId.append(QLatin1String("Portable")); + appId.append(QLatin1String(".Portable")); } if (isTestModeEnabled()) { - appId.append(QSL("TestMode")); + appId.append(QSL(".TestMode")); } if (newInstance) { @@ -241,7 +241,7 @@ MainApplication::MainApplication(int &argc, char** argv) // Generate unique appId so it is possible to start more separate instances // of the same profile. It is dangerous to run more instances of the same profile, // but if the user wants it, we should allow it. - appId.append(startProfile + QString::number(QDateTime::currentMSecsSinceEpoch())); + appId.append(QLatin1Char('.') + startProfile + QString::number(QDateTime::currentMSecsSinceEpoch())); } }