diff --git a/win-linux/defaults.pri b/win-linux/defaults.pri index 85fcddb49..aae9d4f8b 100644 --- a/win-linux/defaults.pri +++ b/win-linux/defaults.pri @@ -153,12 +153,8 @@ SOURCES += \ # src/components/casclabel.cpp updmodule:!build_xp { - INCLUDEPATH += $$PWD/extras/update-daemon/src/classes - HEADERS += $$PWD/src/cupdatemanager.h \ - $$PWD/extras/update-daemon/src/classes/csocket.h - - SOURCES += $$PWD/src/cupdatemanager.cpp \ - $$PWD/extras/update-daemon/src/classes/csocket.cpp + HEADERS += $$PWD/src/cupdatemanager.h + SOURCES += $$PWD/src/cupdatemanager.cpp } RESOURCES += $$PWD/resources.qrc @@ -199,6 +195,8 @@ core_linux { QMAKE_LFLAGS += "-Wl,-rpath,\'\$$ORIGIN/converter\'" QMAKE_LFLAGS += -static-libstdc++ -static-libgcc + INCLUDEPATH += $$PWD/extras/update-daemon/src/classes + HEADERS += $$PWD/src/windows/platform_linux/cx11decoration.h \ #$$PWD/src/windows/platform_linux/gtk_addon.h \ $$PWD/src/windows/platform_linux/cwindowplatform.h \ @@ -210,7 +208,8 @@ core_linux { $$PWD/src/platform_linux/gtkprintdialog.h \ $$PWD/src/platform_linux/gtkmessage.h \ $$PWD/src/platform_linux/gtkutils.h \ - $$PWD/src/platform_linux/xcbutils.h + $$PWD/src/platform_linux/xcbutils.h \ + $$PWD/extras/update-daemon/src/classes/csocket.h SOURCES += $$PWD/src/windows/platform_linux/cx11decoration.cpp \ #$$PWD/src/windows/platform_linux/gtk_addon.cpp \ @@ -224,7 +223,8 @@ core_linux { $$PWD/src/platform_linux/gtkprintdialog.cpp \ $$PWD/src/platform_linux/gtkmessage.cpp \ $$PWD/src/platform_linux/gtkutils.cpp \ - $$PWD/src/platform_linux/xcbutils.cpp + $$PWD/src/platform_linux/xcbutils.cpp \ + $$PWD/extras/update-daemon/src/classes/csocket.cpp updmodule { HEADERS += $$PWD/src/platform_linux/updatedialog.h @@ -272,8 +272,11 @@ core_windows { OTHER_FILES += $$PWD/res/manifest/DesktopEditors.exe.manifest updmodule:!build_xp { - HEADERS += $$PWD/src/platform_win/updatedialog.h - SOURCES += $$PWD/src/platform_win/updatedialog.cpp + INCLUDEPATH += $$PWD/extras/update-daemon/src/classes + HEADERS += $$PWD/src/platform_win/updatedialog.h \ + $$PWD/extras/update-daemon/src/classes/csocket.h + SOURCES += $$PWD/src/platform_win/updatedialog.cpp \ + $$PWD/extras/update-daemon/src/classes/csocket.cpp } LIBS += -lwininet \ diff --git a/win-linux/src/defines.h b/win-linux/src/defines.h index 467eb88cb..2d7159f1f 100644 --- a/win-linux/src/defines.h +++ b/win-linux/src/defines.h @@ -127,6 +127,7 @@ typedef unsigned char BYTE; #define APP_PORT 12010 #define SVC_PORT 12011 #define INSTANCE_SVC_PORT 12012 +#define INSTANCE_APP_PORT 13012 #define BTN_TEXT_CANCEL QObject::tr("Cancel") #define BTN_TEXT_YES QObject::tr("Yes") diff --git a/win-linux/src/platform_linux/singleapplication.cpp b/win-linux/src/platform_linux/singleapplication.cpp index 84b39d9ca..0cd4d291c 100644 --- a/win-linux/src/platform_linux/singleapplication.cpp +++ b/win-linux/src/platform_linux/singleapplication.cpp @@ -1,332 +1,77 @@ -// The MIT License (MIT) -// -// Copyright (c) Itay Grudev 2015 - 2016 -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include "utils.h" -#include -#include -#include -#include -#include -#include - -#ifdef Q_OS_UNIX - #include - #include -#endif +/* + * (c) Copyright Ascensio System SIA 2010-2019 + * + * This program is a free software product. You can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License (AGPL) + * version 3 as published by the Free Software Foundation. In accordance with + * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect + * that Ascensio System SIA expressly excludes the warranty of non-infringement + * of any third-party rights. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For + * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html + * + * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha + * street, Riga, Latvia, EU, LV-1050. + * + * The interactive user interfaces in modified source and object code versions + * of the Program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU AGPL version 3. + * + * Pursuant to Section 7(b) of the License you must retain the original Product + * logo when distributing the program. Pursuant to Section 7(e) we decline to + * grant you any rights under trademark law for use of our trademarks. + * + * All the Product's GUI elements, including illustrations and icon sets, as + * well as technical writing content are licensed under the terms of the + * Creative Commons Attribution-ShareAlike 4.0 International. See the License + * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + * + */ #include "singleapplication.h" +#include "defines.h" +#include -struct InstancesInfo { - bool primary; - uint8_t secondary; -}; +#define RETRIES_DELAY_MS 100 -class SingleApplicationPrivate { -public: - Q_DECLARE_PUBLIC(SingleApplication) - SingleApplicationPrivate( SingleApplication *q_ptr ) : q_ptr( q_ptr ) { - server = NULL; - } - - ~SingleApplicationPrivate() - { - cleanUp(); - } - - void startPrimary( bool resetMemory ) - { - Q_Q(SingleApplication); -#ifdef Q_OS_UNIX - // Handle any further termination signals to ensure the - // QSharedMemory block is deleted even if the process crashes - crashHandler(); -#endif - // Successful creation means that no main process exists - // So we start a QLocalServer to listen for connections - QLocalServer::removeServer( memory->key() ); - server = new QLocalServer(); - server->listen( memory->key() ); - QObject::connect(server, &QLocalServer::newConnection, q, &SingleApplication::slotConnectionEstablished); - - // Reset the number of connections - memory->lock(); - InstancesInfo* inst = (InstancesInfo*)memory->data(); - - if( resetMemory ){ - inst->primary = true; - inst->secondary = 0; - } else { - inst->primary = true; - } - - memory->unlock(); - } - - void startSecondary() - { -#ifdef Q_OS_UNIX - // Handle any further termination signals to ensure the - // QSharedMemory block is deleted even if the process crashes - crashHandler(); -#endif - - //notifyPrimary(); - } - - void notifyPrimary(const QByteArray &data, int timeout) - { - // Connect to the Local Server of the main process to notify it - // that a new process had been started - QLocalSocket socket; - socket.connectToServer( memory->key() ); - - // Notify the parent that a new instance had been started; - if (socket.waitForConnected( timeout )) { - // Send input arguments to the parent - socket.write(data); - socket.waitForBytesWritten(); - } - socket.close(); - } - -#ifdef Q_OS_UNIX - void crashHandler() - { - // This guarantees the program will work even with multiple - // instances of SingleApplication in different threads. - // Which in my opinion is idiotic, but lets handle that too. - { - sharedMemMutex.lock(); - sharedMem.append( this ); - sharedMemMutex.unlock(); - } - - // Handle any further termination signals to ensure the - // QSharedMemory block is deleted even if the process crashes - signal( SIGHUP, SingleApplicationPrivate::terminate ); // 1 - signal( SIGINT, SingleApplicationPrivate::terminate ); // 2 - signal( SIGQUIT, SingleApplicationPrivate::terminate ); // 3 - signal( SIGILL, SingleApplicationPrivate::terminate ); // 4 - signal( SIGABRT, SingleApplicationPrivate::terminate ); // 6 - signal( SIGFPE, SingleApplicationPrivate::terminate ); // 8 - signal( SIGBUS, SingleApplicationPrivate::terminate ); // 10 - signal( SIGSEGV, SingleApplicationPrivate::terminate ); // 11 - signal( SIGSYS, SingleApplicationPrivate::terminate ); // 12 - signal( SIGPIPE, SingleApplicationPrivate::terminate ); // 13 - signal( SIGALRM, SingleApplicationPrivate::terminate ); // 14 - signal( SIGTERM, SingleApplicationPrivate::terminate ); // 15 - signal( SIGXCPU, SingleApplicationPrivate::terminate ); // 24 - signal( SIGXFSZ, SingleApplicationPrivate::terminate ); // 25 - } - - static void terminate( int signum ) - { - while( ! sharedMem.empty() ) { - delete sharedMem.back(); - sharedMem.pop_back(); - } - ::exit( 128 + signum ); - } - - static QList sharedMem; - static QMutex sharedMemMutex; -#endif - - void cleanUp() { - memory->lock(); - InstancesInfo* inst = (InstancesInfo*)memory->data(); - if( server != NULL ) { - server->close(); - inst->primary = false; - } else if (inst) { - if( inst->secondary > 0 ) - inst->secondary -= 1; - } - memory->unlock(); - delete memory; - } - - QSharedMemory *memory; - SingleApplication *q_ptr; - QLocalServer *server; -}; - -#ifdef Q_OS_UNIX - QList SingleApplicationPrivate::sharedMem; - QMutex SingleApplicationPrivate::sharedMemMutex; -#endif - -/** - * @brief Constructor. Checks and fires up LocalServer or closes the program - * if another instance already exists - * @param argc - * @param argv - */ -SingleApplication::SingleApplication( int &argc, char *argv[], const QString& servername) - : SingleApplication(argc, argv, servername, 0) -{} - -SingleApplication::SingleApplication( int &argc, char *argv[], const QString& servername, uint8_t secondaryInstances ) - : app_t( argc, argv ), d_ptr( new SingleApplicationPrivate( this ) ) +SingleApplication::SingleApplication(int &argc, char *argv[], const QString&) : + QApplication(argc, argv), + m_socket(new CSocket(0, INSTANCE_APP_PORT)) { - Q_D(SingleApplication); - - // Check command line arguments for the force primary and secondary flags -#ifdef Q_OS_UNIX - bool forcePrimary = false; -#endif - bool secondary = false; - for( int i = 0; i < argc; ++i ) { - if( strcmp( argv[i], "--secondary" ) == 0 ) { - secondary = true; -#ifndef Q_OS_UNIX - break; -#endif - } -#ifdef Q_OS_UNIX - QString s = QString(argv[i]); - if( strcmp( argv[i], "--primary" ) == 0 ) { - secondary = false; - forcePrimary = true; - break; - } -#endif + if (m_socket->isPrimaryInstance()) { + m_isPrimary = true; + m_socket->onMessageReceived([=](void *buff, size_t size) { + QString data = QString::fromLocal8Bit((const char*)buff, size); + QMetaObject::invokeMethod(this, "invokeSignal", Qt::QueuedConnection, Q_ARG(QString, data)); + }); } - -// QString serverName = app_t::organizationName() + app_t::applicationName(); -// serverName.replace( QRegExp("[^\\w\\-. ]"), "" ); - QString serverName = servername + ":" + QString::fromStdWString(Utils::systemUserName()); - -// QSystemSemaphore _semaphore("asc:desktop:editors", 1); -// _semaphore.acquire(); - - // Guarantee thread safe behaviour with a shared memory block. Also by - // attaching to it and deleting it we make sure that the memory i deleted - // even if the process had crashed - d->memory = new QSharedMemory( serverName ); - d->memory->attach(); - delete d->memory; - d->memory = new QSharedMemory( serverName ); - - // Create a shared memory block with a minimum size of 1 byte -#ifdef Q_OS_UNIX - if( d->memory->create( sizeof(InstancesInfo) ) || forcePrimary ) { -#else - if( d->memory->create( sizeof(InstancesInfo) ) ) { -#endif - d->startPrimary( true ); - return; - } else { - // Attempt to attach to the memory segment - if( d->memory->attach() ) { - d->memory->lock(); - InstancesInfo* inst = (InstancesInfo*)d->memory->data(); - - if( ! inst->primary ) { - d->startPrimary( false ); - d->memory->unlock(); - return; - } - - // Check if another instance can be started - if( secondary && inst->secondary < secondaryInstances ) { - inst->secondary += 1; - d->startSecondary(); - d->memory->unlock(); - return; - } - - d->memory->unlock(); - } - } - -// _semaphore.release(); - - //d->notifyPrimary(); - //delete d; - - //qWarning() << "DesktopEditors had been run already"; - - //::exit(EXIT_SUCCESS); } -/** - * @brief Destructor - */ SingleApplication::~SingleApplication() { - Q_D(SingleApplication); - delete d; + if (m_socket) + delete m_socket, m_socket = nullptr; } bool SingleApplication::isPrimary() { - Q_D(SingleApplication); - return d->server != NULL; + return m_isPrimary; } -bool SingleApplication::isSecondary() +bool SingleApplication::sendMessage(const QByteArray &msg) { - Q_D(SingleApplication); - return d->server == NULL; -} - -bool SingleApplication::sendMessage(const QByteArray &data) -{ - Q_D(SingleApplication); - if (isPrimary()) + if (m_isPrimary) return false; - d->notifyPrimary(data, 3000); - return true; + QThread::msleep(RETRIES_DELAY_MS); + CSocket socket(INSTANCE_APP_PORT, 0); + return socket.sendMessage((void*)msg.data(), msg.size()); } -/** - * @brief Executed when a connection has been made to the LocalServer - */ -void SingleApplication::slotConnectionEstablished() +void SingleApplication::invokeSignal(const QString &data) { - Q_D(SingleApplication); - - QLocalSocket *socket = d->server->nextPendingConnection(); - -// while (socket->bytesAvailable() < (int)sizeof(quint32)) -// socket->waitForReadyRead(); - - if( !socket->waitForConnected() ) - return; - - if( !socket->waitForReadyRead() ) - return; - - QByteArray buffer; - QDataStream stream(&buffer, QIODevice::ReadOnly); - buffer.append(socket->readAll()); - - socket->close(); - delete socket; - - // Send input arguments the window - Q_EMIT receivedMessage(buffer); + emit receivedMessage(data.toUtf8()); } diff --git a/win-linux/src/platform_linux/singleapplication.h b/win-linux/src/platform_linux/singleapplication.h index f7d65ff12..03ea89f90 100644 --- a/win-linux/src/platform_linux/singleapplication.h +++ b/win-linux/src/platform_linux/singleapplication.h @@ -1,66 +1,62 @@ -// The MIT License (MIT) -// -// Copyright (c) Itay Grudev 2015 - 2016 -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +/* + * (c) Copyright Ascensio System SIA 2010-2019 + * + * This program is a free software product. You can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License (AGPL) + * version 3 as published by the Free Software Foundation. In accordance with + * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect + * that Ascensio System SIA expressly excludes the warranty of non-infringement + * of any third-party rights. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For + * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html + * + * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha + * street, Riga, Latvia, EU, LV-1050. + * + * The interactive user interfaces in modified source and object code versions + * of the Program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU AGPL version 3. + * + * Pursuant to Section 7(b) of the License you must retain the original Product + * logo when distributing the program. Pursuant to Section 7(e) we decline to + * grant you any rights under trademark law for use of our trademarks. + * + * All the Product's GUI elements, including illustrations and icon sets, as + * well as technical writing content are licensed under the terms of the + * Creative Commons Attribution-ShareAlike 4.0 International. See the License + * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + * + */ #ifndef SINGLE_APPLICATION_H #define SINGLE_APPLICATION_H -#include +#include +#include +#include "csocket.h" -#ifndef QAPPLICATION_CLASS - #define QAPPLICATION_CLASS QApplication -#endif -#include QT_STRINGIFY(QAPPLICATION_CLASS) - -class SingleApplicationPrivate; - -/** - * @brief The SingleApplication class handles multipe instances of the same Application - * @see QApplication - */ -class SingleApplication : public QAPPLICATION_CLASS +class SingleApplication : public QApplication { Q_OBJECT - Q_DECLARE_PRIVATE(SingleApplication) - - typedef QAPPLICATION_CLASS app_t; - public: - explicit SingleApplication( int &argc, char *argv[], const QString& servername); - explicit SingleApplication( int &argc, char *argv[], const QString& servername, uint8_t secondaryInstances); + explicit SingleApplication( int &argc, char *argv[], const QString& servername = QString()); ~SingleApplication(); bool isPrimary(); - bool isSecondary(); bool sendMessage(const QByteArray&); signals: void receivedMessage(QByteArray message); -private Q_SLOTS: - void slotConnectionEstablished(); +private slots: + void invokeSignal(const QString&); private: - SingleApplicationPrivate *d_ptr; + CSocket *m_socket = nullptr; + bool m_isPrimary = false; }; #endif // SINGLE_APPLICATION_H