mirror of
https://github.com/ONLYOFFICE/desktop-apps.git
synced 2026-04-07 14:09:22 +08:00
Merge pull request #931 from ONLYOFFICE/fix/multiple_instances_59389_r1
Fix bug 59389
This commit is contained in:
@ -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 \
|
||||
|
||||
@ -55,14 +55,16 @@ core_windows {
|
||||
$$PWD/src/platform_win/svccontrol.h \
|
||||
$$PWD/src/classes/platform_win/capplication.h \
|
||||
$$PWD/src/classes/platform_win/cunzip.h \
|
||||
$$PWD/src/classes/platform_win/cdownloader.h
|
||||
$$PWD/src/classes/platform_win/cdownloader.h \
|
||||
$$PWD/src/classes/platform_win/ctimer.h
|
||||
|
||||
SOURCES += $$PWD/src/platform_win/main.cpp \
|
||||
$$PWD/src/platform_win/utils.cpp \
|
||||
$$PWD/src/platform_win/svccontrol.cpp \
|
||||
$$PWD/src/classes/platform_win/capplication.cpp \
|
||||
$$PWD/src/classes/platform_win/cunzip.cpp \
|
||||
$$PWD/src/classes/platform_win/cdownloader.cpp
|
||||
$$PWD/src/classes/platform_win/cdownloader.cpp \
|
||||
$$PWD/src/classes/platform_win/ctimer.cpp
|
||||
|
||||
OTHER_FILES += $$PWD/res/version.rc \
|
||||
$$PWD/res/manifest/updatesvc.exe.manifest
|
||||
@ -94,13 +96,15 @@ core_linux {
|
||||
HEADERS += $$PWD/src/platform_linux/utils.h \
|
||||
$$PWD/src/classes/platform_linux/capplication.h \
|
||||
$$PWD/src/classes/platform_linux/cunzip.h \
|
||||
$$PWD/src/classes/platform_linux/cdownloader.h
|
||||
$$PWD/src/classes/platform_linux/cdownloader.h \
|
||||
$$PWD/src/classes/platform_linux/ctimer.h
|
||||
|
||||
SOURCES += $$PWD/src/platform_linux/main.cpp \
|
||||
$$PWD/src/platform_linux/utils.cpp \
|
||||
$$PWD/src/classes/platform_linux/capplication.cpp \
|
||||
$$PWD/src/classes/platform_linux/cunzip.cpp \
|
||||
$$PWD/src/classes/platform_linux/cdownloader.cpp
|
||||
$$PWD/src/classes/platform_linux/cdownloader.cpp \
|
||||
$$PWD/src/classes/platform_linux/ctimer.cpp
|
||||
|
||||
CONFIG += link_pkgconfig
|
||||
PKGCONFIG += gtk+-3.0
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
|
||||
CApplication::CApplication()
|
||||
{
|
||||
if (SDL_Init(SDL_INIT_VIDEO) != 0)
|
||||
if (SDL_Init(SDL_INIT_EVENTS | SDL_INIT_TIMER) != 0)
|
||||
NS_Logger::WriteLog(string("SDL_Init error: ") + SDL_GetError(), true);
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* (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 "ctimer.h"
|
||||
|
||||
|
||||
Uint32 timerCallback(Uint32 interval, void *param) {
|
||||
FnVoidVoid *callback = (FnVoidVoid*)param;
|
||||
if (callback && *callback)
|
||||
(*callback)();
|
||||
return interval;
|
||||
}
|
||||
|
||||
CTimer::CTimer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CTimer::~CTimer()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void CTimer::stop()
|
||||
{
|
||||
if (timerID != 0) {
|
||||
SDL_RemoveTimer(timerID);
|
||||
timerID = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CTimer::start(unsigned int timeout, FnVoidVoid callback)
|
||||
{
|
||||
stop();
|
||||
timerID = SDL_AddTimer(timeout, timerCallback, (void*)&callback);
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* (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 CTIMER_H
|
||||
#define CTIMER_H
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <functional>
|
||||
|
||||
typedef std::function<void(void)> FnVoidVoid;
|
||||
|
||||
|
||||
class CTimer
|
||||
{
|
||||
public:
|
||||
CTimer();
|
||||
~CTimer();
|
||||
|
||||
void stop();
|
||||
|
||||
/* callback */
|
||||
void start(unsigned int timeout, FnVoidVoid callback);
|
||||
|
||||
private:
|
||||
SDL_TimerID timerID = 0;
|
||||
};
|
||||
|
||||
#endif // CTIMER_H
|
||||
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* (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 "ctimer.h"
|
||||
|
||||
|
||||
FnVoidVoid _callback = nullptr;
|
||||
|
||||
|
||||
VOID CALLBACK Timerproc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
|
||||
{
|
||||
if (_callback)
|
||||
_callback();
|
||||
}
|
||||
|
||||
CTimer::CTimer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CTimer::~CTimer()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void CTimer::stop()
|
||||
{
|
||||
if (timerId != 0) {
|
||||
KillTimer(NULL, timerId);
|
||||
timerId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CTimer::start(unsigned int timeout, FnVoidVoid callback)
|
||||
{
|
||||
stop();
|
||||
_callback = callback;
|
||||
timerId = SetTimer(NULL, 0, timeout, Timerproc);
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* (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 CTIMER_H
|
||||
#define CTIMER_H
|
||||
|
||||
#include <Windows.h>
|
||||
#include <functional>
|
||||
|
||||
typedef std::function<void(void)> FnVoidVoid;
|
||||
|
||||
|
||||
class CTimer
|
||||
{
|
||||
public:
|
||||
CTimer();
|
||||
~CTimer();
|
||||
|
||||
void stop();
|
||||
|
||||
/* callback */
|
||||
void start(unsigned int timeout, FnVoidVoid callback);
|
||||
|
||||
private:
|
||||
UINT_PTR timerId = 0;
|
||||
};
|
||||
|
||||
#endif // CTIMER_H
|
||||
@ -32,9 +32,11 @@
|
||||
|
||||
#include "platform_linux/utils.h"
|
||||
#include "classes/platform_linux/capplication.h"
|
||||
#include "classes/platform_linux/ctimer.h"
|
||||
#include "classes/csvcmanager.h"
|
||||
#include "../../src/defines.h"
|
||||
#include "../../src/prop/defines_p.h"
|
||||
#include <csignal>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
@ -50,9 +52,25 @@ int main(int argc, char *argv[])
|
||||
|
||||
CApplication app;
|
||||
CSvcManager upd;
|
||||
socket.onMessageReceived([&app](void *buff, size_t) {
|
||||
int pid = -1;
|
||||
socket.onMessageReceived([&app, &pid](void *buff, size_t) {
|
||||
if (strcmp((const char*)buff, "stop") == 0)
|
||||
app.exit(0);
|
||||
else {
|
||||
char *err = NULL;
|
||||
int _pid = strtol((const char*)buff, &err, 10);
|
||||
if (!err || *err == '\0')
|
||||
pid = _pid;
|
||||
}
|
||||
});
|
||||
|
||||
// Checking for the completion of the main application:
|
||||
// updatevc needs to be terminated when the main application is using a socket
|
||||
// with the same address in the SingleApplication implementation and has been terminated incorrectly.
|
||||
CTimer tmr;
|
||||
tmr.start(5000, [&app, &pid]() {
|
||||
if (pid != -1 && kill(pid, 0) != 0)
|
||||
app.exit(0);
|
||||
});
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
#include "utils.h"
|
||||
#include "platform_win/svccontrol.h"
|
||||
#include "classes/platform_win/capplication.h"
|
||||
#include "classes/platform_win/ctimer.h"
|
||||
#include "classes/csvcmanager.h"
|
||||
#include "../../src/defines.h"
|
||||
#include "../../src/prop/defines_p.h"
|
||||
@ -95,9 +96,28 @@ int __cdecl _tmain (int argc, TCHAR *argv[])
|
||||
|
||||
CApplication app;
|
||||
CSvcManager upd;
|
||||
socket.onMessageReceived([&app](void *buff, size_t) {
|
||||
int pid = -1;
|
||||
socket.onMessageReceived([&app, &pid](void *buff, size_t) {
|
||||
if (strcmp((const char*)buff, "stop") == 0)
|
||||
app.exit(0);
|
||||
else {
|
||||
char *err = NULL;
|
||||
int _pid = strtol((const char*)buff, &err, 10);
|
||||
if (!err || *err == '\0')
|
||||
pid = _pid;
|
||||
}
|
||||
});
|
||||
|
||||
// Termination on crash of the main application
|
||||
CTimer tmr;
|
||||
tmr.start(30000, [&app, &pid]() {
|
||||
if (pid > 0) {
|
||||
HANDLE procHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
|
||||
if (procHandle)
|
||||
CloseHandle(procHandle);
|
||||
else
|
||||
app.exit(0);
|
||||
}
|
||||
});
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
@ -49,6 +49,7 @@
|
||||
# define DAEMON_NAME L"/updatesvc.exe"
|
||||
#else
|
||||
# include <QProcess>
|
||||
# include <unistd.h>
|
||||
# include "components/cmessage.h"
|
||||
# include "platform_linux/updatedialog.h"
|
||||
# define DAEMON_NAME "/updatesvc"
|
||||
@ -229,8 +230,19 @@ CUpdateManager::CUpdateManager(QObject *parent):
|
||||
// m_pTimer = new QTimer(this);
|
||||
// m_pTimer->setSingleShot(false);
|
||||
// connect(m_pTimer, SIGNAL(timeout()), this, SLOT(checkUpdates()));
|
||||
if (IsPackage(Portable))
|
||||
if (IsPackage(Portable)) {
|
||||
runProcess(QStrToTStr(qApp->applicationDirPath()) + DAEMON_NAME, TEXT("--run-as-app"));
|
||||
QTimer::singleShot(0, this, []() {
|
||||
std::string msg;
|
||||
#ifdef _WIN32
|
||||
msg = std::to_string(GetCurrentProcessId());
|
||||
#else
|
||||
msg = std::to_string(getpid());
|
||||
#endif
|
||||
CSocket sock(INSTANCE_SVC_PORT, 0);
|
||||
sock.sendMessage((void*)msg.c_str(), sizeof(msg));
|
||||
});
|
||||
}
|
||||
init();
|
||||
} else
|
||||
CLogger::log("Updates is off, URL is empty.");
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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 <cstdlib>
|
||||
#include "utils.h"
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtCore/QSemaphore>
|
||||
#include <QtCore/QSharedMemory>
|
||||
#include <QtNetwork/QLocalSocket>
|
||||
#include <QtNetwork/QLocalServer>
|
||||
#include <QDataStream>
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#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 <QThread>
|
||||
|
||||
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<SingleApplicationPrivate*> 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*> 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());
|
||||
}
|
||||
|
||||
@ -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 <QtCore/QtGlobal>
|
||||
#include <QApplication>
|
||||
#include <QByteArray>
|
||||
#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
|
||||
|
||||
Reference in New Issue
Block a user