diff --git a/linphone-app/CMakeLists.txt b/linphone-app/CMakeLists.txt index 454a20d28..cf9e805c9 100644 --- a/linphone-app/CMakeLists.txt +++ b/linphone-app/CMakeLists.txt @@ -511,10 +511,16 @@ set( UIS) list(APPEND SOURCES include/LinphoneApp/PluginExample.json) ## Single Application -list(APPEND HEADERS src/app/single-application/singleapplication.h - src/app/single-application/singleapplication_p.h) -list(APPEND SOURCES src/app/single-application/singleapplication.cpp - src/app/single-application/singleapplication_p.cpp) +if(APPLE OR WIN32) + list(APPEND HEADERS src/app/single-application/singleapplication.h + src/app/single-application/singleapplication_p.h) + list(APPEND SOURCES src/app/single-application/singleapplication.cpp + src/app/single-application/singleapplication_p.cpp) +else() # Use QDBus for Linux + list(APPEND HEADERS src/app/single-application/singleapplication.h + src/app/single-application/SingleApplicationDBusPrivate.hpp) + list(APPEND SOURCES src/app/single-application/SingleApplicationDBus.cpp) +endif() set(MAIN_FILE src/app/main.cpp) if (APPLE) diff --git a/linphone-app/src/app/single-application/SingleApplicationDBus.cpp b/linphone-app/src/app/single-application/SingleApplicationDBus.cpp new file mode 100644 index 000000000..9bc82ff2f --- /dev/null +++ b/linphone-app/src/app/single-application/SingleApplicationDBus.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include + +#include "config.h" + +#include "singleapplication.h" +#include "SingleApplicationDBusPrivate.hpp" + +// ============================================================================= + +namespace { + constexpr char ServiceName[] = "org." EXECUTABLE_NAME ".SingleApplication"; +} + +SingleApplicationPrivate::SingleApplicationPrivate (SingleApplication *q_ptr) + : QDBusAbstractAdaptor(q_ptr), q_ptr(q_ptr) {} + +QDBusConnection SingleApplicationPrivate::getBus () const { + if (options & SingleApplication::Mode::User) + return QDBusConnection::sessionBus(); + + return QDBusConnection::systemBus(); +} + +void SingleApplicationPrivate::startPrimary () { + signal(SIGINT, SingleApplicationPrivate::terminate); + if (!getBus().registerObject("/", this, QDBusConnection::ExportAllSlots)) + qWarning() << QStringLiteral("Failed to register single application object on DBus."); + instanceNumber = 0; +} + +void SingleApplicationPrivate::startSecondary () { + signal(SIGINT, SingleApplicationPrivate::terminate); + instanceNumber = 1; +} + +void SingleApplicationPrivate::terminate (int signum) { + SingleApplication::instance()->exit(signum); +} + +SingleApplication::SingleApplication (int &argc, char *argv[], bool allowSecondary, Options options, int, const QString &userData) + : QApplication(argc, argv), d_ptr(new SingleApplicationPrivate(this)) { + Q_D(SingleApplication); + + // Store the current mode of the program. + d->options = options; + + if (!d->getBus().isConnected()) { + qWarning() << QStringLiteral("Cannot connect to the D-Bus session bus."); + delete d; + ::exit(EXIT_FAILURE); + } + + if (d->getBus().registerService(ServiceName)) { + d->startPrimary(); + return; + } + + if (allowSecondary) { + d->startSecondary(); + return; + } + + delete d; + ::exit(EXIT_SUCCESS); +} + +SingleApplication::~SingleApplication () { + Q_D(SingleApplication); + delete d; +} + +bool SingleApplication::isPrimary () const { + auto d = d_func(); + return d->instanceNumber == 0; +} + +bool SingleApplication::isSecondary () const { + auto d = d_func(); + return d->instanceNumber != 0; +} + +quint32 SingleApplication::instanceId () const { + auto d = d_func(); + return d->instanceNumber; +} + +bool SingleApplication::sendMessage (const QByteArray &message, int timeout, SendMode sendMode) { + auto d = d_func(); + + if (isPrimary()) return false; + + QDBusInterface iface(ServiceName, "/", "", d->getBus()); + if (iface.isValid()) { + iface.setTimeout(timeout); + iface.call(QDBus::Block, "handleMessageReceived", instanceId(), message); + return true; + } + + return false; +} + +void SingleApplicationPrivate::handleMessageReceived (quint32 instanceId, QByteArray message) { + Q_Q(SingleApplication); + emit q->receivedMessage(instanceId, message); +} diff --git a/linphone-app/src/app/single-application/SingleApplicationDBusPrivate.hpp b/linphone-app/src/app/single-application/SingleApplicationDBusPrivate.hpp new file mode 100644 index 000000000..14c199c9a --- /dev/null +++ b/linphone-app/src/app/single-application/SingleApplicationDBusPrivate.hpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2010-2020 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SINGLE_APPLICATION_DBUS_PRIVATE_H_ +#define SINGLE_APPLICATION_DBUS_PRIVATE_H_ + +#include +#include + +#include "singleapplication.h" + +// ============================================================================= + +struct InstancesInfo { + bool primary; + quint32 secondary; +}; + +class SingleApplicationPrivate : public QDBusAbstractAdaptor { + Q_OBJECT; + Q_CLASSINFO("D-Bus Interface", "org.linphone.DBus.SingleApplication"); + +public: + SingleApplicationPrivate (SingleApplication *q_ptr); + + QDBusConnection getBus () const; + + void startPrimary (); + void startSecondary (); + + static void terminate (int signum); + + SingleApplication *q_ptr; + SingleApplication::Options options; + quint32 instanceNumber; + +// Explicit public slot. Cannot be private, must be exported as a method via D-Bus. +public slots: + void handleMessageReceived (quint32 instanceId, QByteArray message); + +private: + Q_DECLARE_PUBLIC(SingleApplication); +}; + +#endif // SINGLE_APPLICATION_DBUS_PRIVATE_H_