summary refs log tree commit diff
path: root/third_party
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2021-06-16 22:30:45 +0200
committerNicolas Werner <nicolas.werner@hotmail.de>2021-06-25 11:34:17 +0200
commit6a7d28d1b5564db6c45460de680282e45751d11a (patch)
tree9c1f321075969f2e63f22d90957e2e6832b42f8c /third_party
parentShow some spaces in the community sidebar (diff)
downloadnheko-6a7d28d1b5564db6c45460de680282e45751d11a.tar.xz
update SingleApplication
Diffstat (limited to 'third_party')
-rw-r--r--third_party/SingleApplication-3.3.0/.github/FUNDING.yml1
-rw-r--r--third_party/SingleApplication-3.3.0/.github/workflows/build-cmake.yml56
-rw-r--r--third_party/SingleApplication-3.3.0/.gitignore (renamed from third_party/SingleApplication-3.2.0-dc8042b/.gitignore)0
-rw-r--r--third_party/SingleApplication-3.3.0/CHANGELOG.md (renamed from third_party/SingleApplication-3.2.0-dc8042b/CHANGELOG.md)6
-rw-r--r--third_party/SingleApplication-3.3.0/CMakeLists.txt (renamed from third_party/SingleApplication-3.2.0-dc8042b/CMakeLists.txt)0
-rw-r--r--third_party/SingleApplication-3.3.0/LICENSE (renamed from third_party/SingleApplication-3.2.0-dc8042b/LICENSE)0
-rw-r--r--third_party/SingleApplication-3.3.0/README.md (renamed from third_party/SingleApplication-3.2.0-dc8042b/README.md)0
-rw-r--r--third_party/SingleApplication-3.3.0/SingleApplication (renamed from third_party/SingleApplication-3.2.0-dc8042b/SingleApplication)0
-rw-r--r--third_party/SingleApplication-3.3.0/Windows.md (renamed from third_party/SingleApplication-3.2.0-dc8042b/Windows.md)0
-rw-r--r--third_party/SingleApplication-3.3.0/examples/basic/CMakeLists.txt12
-rwxr-xr-xthird_party/SingleApplication-3.3.0/examples/basic/basic.pro5
-rwxr-xr-xthird_party/SingleApplication-3.3.0/examples/basic/main.cpp10
-rw-r--r--third_party/SingleApplication-3.3.0/examples/calculator/CMakeLists.txt21
-rw-r--r--third_party/SingleApplication-3.3.0/examples/calculator/button.cpp73
-rw-r--r--third_party/SingleApplication-3.3.0/examples/calculator/button.h68
-rw-r--r--third_party/SingleApplication-3.3.0/examples/calculator/calculator.cpp406
-rw-r--r--third_party/SingleApplication-3.3.0/examples/calculator/calculator.h117
-rw-r--r--third_party/SingleApplication-3.3.0/examples/calculator/calculator.pro11
-rw-r--r--third_party/SingleApplication-3.3.0/examples/calculator/main.cpp71
-rw-r--r--third_party/SingleApplication-3.3.0/examples/sending_arguments/CMakeLists.txt20
-rwxr-xr-xthird_party/SingleApplication-3.3.0/examples/sending_arguments/main.cpp28
-rw-r--r--third_party/SingleApplication-3.3.0/examples/sending_arguments/messagereceiver.cpp12
-rw-r--r--third_party/SingleApplication-3.3.0/examples/sending_arguments/messagereceiver.h15
-rwxr-xr-xthird_party/SingleApplication-3.3.0/examples/sending_arguments/sending_arguments.pro9
-rw-r--r--third_party/SingleApplication-3.3.0/singleapplication.cpp (renamed from third_party/SingleApplication-3.2.0-dc8042b/singleapplication.cpp)33
-rw-r--r--third_party/SingleApplication-3.3.0/singleapplication.h (renamed from third_party/SingleApplication-3.2.0-dc8042b/singleapplication.h)16
-rw-r--r--third_party/SingleApplication-3.3.0/singleapplication.pri (renamed from third_party/SingleApplication-3.2.0-dc8042b/singleapplication.pri)0
-rw-r--r--third_party/SingleApplication-3.3.0/singleapplication_p.cpp (renamed from third_party/SingleApplication-3.2.0-dc8042b/singleapplication_p.cpp)110
-rw-r--r--third_party/SingleApplication-3.3.0/singleapplication_p.h (renamed from third_party/SingleApplication-3.2.0-dc8042b/singleapplication_p.h)13
29 files changed, 1050 insertions, 63 deletions
diff --git a/third_party/SingleApplication-3.3.0/.github/FUNDING.yml b/third_party/SingleApplication-3.3.0/.github/FUNDING.yml
new file mode 100644
index 00000000..3ca4d97a
--- /dev/null
+++ b/third_party/SingleApplication-3.3.0/.github/FUNDING.yml
@@ -0,0 +1 @@
+github: itay-grudev
diff --git a/third_party/SingleApplication-3.3.0/.github/workflows/build-cmake.yml b/third_party/SingleApplication-3.3.0/.github/workflows/build-cmake.yml
new file mode 100644
index 00000000..6344b504
--- /dev/null
+++ b/third_party/SingleApplication-3.3.0/.github/workflows/build-cmake.yml
@@ -0,0 +1,56 @@
+name: "CI: Build Test"
+
+on: [push, pull_request]
+
+jobs:
+  build:
+
+    strategy:
+      matrix:
+        qt_version: [5.12.6, 5.13.2, 5.14.0, 5.15.0, 6.0.0]
+        platform: [ubuntu-20.04, windows-latest, macos-latest]
+        include:
+          - qt_version: 6.0.0
+            additional_arguments: -D QT_DEFAULT_MAJOR_VERSION=6
+          - platform: ubuntu-20.04
+            CXXFLAGS: -Wall -Wextra -pedantic -Werror
+          - platform: macos-latest
+            CXXFLAGS: -Wall -Wextra -pedantic -Werror
+          - platform: windows-latest
+            CXXFLAGS: /W4 /WX
+
+    runs-on: ${{ matrix.platform }}
+    env:
+      CXXFLAGS: ${{ matrix.CXXFLAGS }}
+
+    steps:
+    - uses: actions/checkout@v2.3.4
+
+    - name: Install Qt
+      uses: jurplel/install-qt-action@v2.11.1
+      with:
+        version: ${{ matrix.qt_version }}
+
+    - name: cmake
+      run: cmake . ${{ matrix.additional_arguments }}
+
+    - name: cmake build
+      run: cmake --build .
+
+    - name: Build example - basic (cmake)
+      working-directory: examples/basic/
+      run: |
+        cmake . ${{ matrix.additional_arguments }}
+        cmake --build .
+
+    - name: Build example - calculator (cmake)
+      working-directory: examples/calculator/
+      run: |
+        cmake . ${{ matrix.additional_arguments }}
+        cmake --build .
+
+    - name: Build example - sending_arguments (cmake)
+      working-directory: examples/sending_arguments/
+      run: |
+        cmake . ${{ matrix.additional_arguments }}
+        cmake --build .
diff --git a/third_party/SingleApplication-3.2.0-dc8042b/.gitignore b/third_party/SingleApplication-3.3.0/.gitignore
index 35533fe8..35533fe8 100644
--- a/third_party/SingleApplication-3.2.0-dc8042b/.gitignore
+++ b/third_party/SingleApplication-3.3.0/.gitignore
diff --git a/third_party/SingleApplication-3.2.0-dc8042b/CHANGELOG.md b/third_party/SingleApplication-3.3.0/CHANGELOG.md
index e2ba290e..51669b90 100644
--- a/third_party/SingleApplication-3.2.0-dc8042b/CHANGELOG.md
+++ b/third_party/SingleApplication-3.3.0/CHANGELOG.md
@@ -3,6 +3,12 @@ Changelog
 
 If by accident I have forgotten to credit someone in the CHANGELOG, email me and I will fix it.
 
+
+__3.3.0__
+---------
+
+* Fixed message fragmentation issue causing crashes and incorrectly and inconsistently received messages. - _Nils Jeisecke_
+
 __3.2.0__
 ---------
 
diff --git a/third_party/SingleApplication-3.2.0-dc8042b/CMakeLists.txt b/third_party/SingleApplication-3.3.0/CMakeLists.txt
index ae1b1439..ae1b1439 100644
--- a/third_party/SingleApplication-3.2.0-dc8042b/CMakeLists.txt
+++ b/third_party/SingleApplication-3.3.0/CMakeLists.txt
diff --git a/third_party/SingleApplication-3.2.0-dc8042b/LICENSE b/third_party/SingleApplication-3.3.0/LICENSE
index a82e5a68..a82e5a68 100644
--- a/third_party/SingleApplication-3.2.0-dc8042b/LICENSE
+++ b/third_party/SingleApplication-3.3.0/LICENSE
diff --git a/third_party/SingleApplication-3.2.0-dc8042b/README.md b/third_party/SingleApplication-3.3.0/README.md
index 457ab339..457ab339 100644
--- a/third_party/SingleApplication-3.2.0-dc8042b/README.md
+++ b/third_party/SingleApplication-3.3.0/README.md
diff --git a/third_party/SingleApplication-3.2.0-dc8042b/SingleApplication b/third_party/SingleApplication-3.3.0/SingleApplication
index 8ead1a42..8ead1a42 100644
--- a/third_party/SingleApplication-3.2.0-dc8042b/SingleApplication
+++ b/third_party/SingleApplication-3.3.0/SingleApplication
diff --git a/third_party/SingleApplication-3.2.0-dc8042b/Windows.md b/third_party/SingleApplication-3.3.0/Windows.md
index 13c52da0..13c52da0 100644
--- a/third_party/SingleApplication-3.2.0-dc8042b/Windows.md
+++ b/third_party/SingleApplication-3.3.0/Windows.md
diff --git a/third_party/SingleApplication-3.3.0/examples/basic/CMakeLists.txt b/third_party/SingleApplication-3.3.0/examples/basic/CMakeLists.txt
new file mode 100644
index 00000000..c1429230
--- /dev/null
+++ b/third_party/SingleApplication-3.3.0/examples/basic/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.7.0)
+
+project(basic LANGUAGES CXX)
+
+# SingleApplication base class
+set(QAPPLICATION_CLASS QCoreApplication)
+add_subdirectory(../.. SingleApplication)
+
+add_executable(basic main.cpp)
+
+target_link_libraries(${PROJECT_NAME} SingleApplication::SingleApplication)
+
diff --git a/third_party/SingleApplication-3.3.0/examples/basic/basic.pro b/third_party/SingleApplication-3.3.0/examples/basic/basic.pro
new file mode 100755
index 00000000..b7af16cf
--- /dev/null
+++ b/third_party/SingleApplication-3.3.0/examples/basic/basic.pro
@@ -0,0 +1,5 @@
+# Single Application implementation
+include(../../singleapplication.pri)
+DEFINES += QAPPLICATION_CLASS=QCoreApplication
+
+SOURCES += main.cpp
diff --git a/third_party/SingleApplication-3.3.0/examples/basic/main.cpp b/third_party/SingleApplication-3.3.0/examples/basic/main.cpp
new file mode 100755
index 00000000..b2092c6d
--- /dev/null
+++ b/third_party/SingleApplication-3.3.0/examples/basic/main.cpp
@@ -0,0 +1,10 @@
+#include <singleapplication.h>
+
+int main(int argc, char *argv[])
+{
+    SingleApplication app( argc, argv );
+
+    qWarning() << "Started a new instance";
+
+    return app.exec();
+}
diff --git a/third_party/SingleApplication-3.3.0/examples/calculator/CMakeLists.txt b/third_party/SingleApplication-3.3.0/examples/calculator/CMakeLists.txt
new file mode 100644
index 00000000..82305f04
--- /dev/null
+++ b/third_party/SingleApplication-3.3.0/examples/calculator/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 3.7.0)
+
+project(calculator LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+
+# SingleApplication base class
+set(QAPPLICATION_CLASS QApplication)
+add_subdirectory(../.. SingleApplication)
+
+find_package(Qt${QT_DEFAULT_MAJOR_VERSION} COMPONENTS Core REQUIRED)
+
+add_executable(${PROJECT_NAME}
+    button.h
+    calculator.h
+    button.cpp
+    calculator.cpp
+    main.cpp
+)
+
+target_link_libraries(${PROJECT_NAME} SingleApplication::SingleApplication)
diff --git a/third_party/SingleApplication-3.3.0/examples/calculator/button.cpp b/third_party/SingleApplication-3.3.0/examples/calculator/button.cpp
new file mode 100644
index 00000000..d6cca0a0
--- /dev/null
+++ b/third_party/SingleApplication-3.3.0/examples/calculator/button.cpp
@@ -0,0 +1,73 @@
+/****************************************************************************

+**

+** Copyright (C) 2016 The Qt Company Ltd.

+** Contact: https://www.qt.io/licensing/

+**

+** This file is part of the examples of the Qt Toolkit.

+**

+** $QT_BEGIN_LICENSE:BSD$

+** Commercial License Usage

+** Licensees holding valid commercial Qt licenses may use this file in

+** accordance with the commercial license agreement provided with the

+** Software or, alternatively, in accordance with the terms contained in

+** a written agreement between you and The Qt Company. For licensing terms

+** and conditions see https://www.qt.io/terms-conditions. For further

+** information use the contact form at https://www.qt.io/contact-us.

+**

+** BSD License Usage

+** Alternatively, you may use this file under the terms of the BSD license

+** as follows:

+**

+** "Redistribution and use in source and binary forms, with or without

+** modification, are permitted provided that the following conditions are

+** met:

+**   * Redistributions of source code must retain the above copyright

+**     notice, this list of conditions and the following disclaimer.

+**   * Redistributions in binary form must reproduce the above copyright

+**     notice, this list of conditions and the following disclaimer in

+**     the documentation and/or other materials provided with the

+**     distribution.

+**   * Neither the name of The Qt Company Ltd nor the names of its

+**     contributors may be used to endorse or promote products derived

+**     from this software without specific prior written permission.

+**

+**

+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."

+**

+** $QT_END_LICENSE$

+**

+****************************************************************************/

+

+#include <QtWidgets>

+

+#include "button.h"

+

+//! [0]

+Button::Button(const QString &text, QWidget *parent)

+    : QToolButton(parent)

+{

+    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);

+    setText(text);

+}

+//! [0]

+

+//! [1]

+QSize Button::sizeHint() const

+//! [1] //! [2]

+{

+    QSize size = QToolButton::sizeHint();

+    size.rheight() += 20;

+    size.rwidth() = qMax(size.width(), size.height());

+    return size;

+}

+//! [2]

diff --git a/third_party/SingleApplication-3.3.0/examples/calculator/button.h b/third_party/SingleApplication-3.3.0/examples/calculator/button.h
new file mode 100644
index 00000000..2c014c7b
--- /dev/null
+++ b/third_party/SingleApplication-3.3.0/examples/calculator/button.h
@@ -0,0 +1,68 @@
+/****************************************************************************

+**

+** Copyright (C) 2016 The Qt Company Ltd.

+** Contact: https://www.qt.io/licensing/

+**

+** This file is part of the examples of the Qt Toolkit.

+**

+** $QT_BEGIN_LICENSE:BSD$

+** Commercial License Usage

+** Licensees holding valid commercial Qt licenses may use this file in

+** accordance with the commercial license agreement provided with the

+** Software or, alternatively, in accordance with the terms contained in

+** a written agreement between you and The Qt Company. For licensing terms

+** and conditions see https://www.qt.io/terms-conditions. For further

+** information use the contact form at https://www.qt.io/contact-us.

+**

+** BSD License Usage

+** Alternatively, you may use this file under the terms of the BSD license

+** as follows:

+**

+** "Redistribution and use in source and binary forms, with or without

+** modification, are permitted provided that the following conditions are

+** met:

+**   * Redistributions of source code must retain the above copyright

+**     notice, this list of conditions and the following disclaimer.

+**   * Redistributions in binary form must reproduce the above copyright

+**     notice, this list of conditions and the following disclaimer in

+**     the documentation and/or other materials provided with the

+**     distribution.

+**   * Neither the name of The Qt Company Ltd nor the names of its

+**     contributors may be used to endorse or promote products derived

+**     from this software without specific prior written permission.

+**

+**

+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."

+**

+** $QT_END_LICENSE$

+**

+****************************************************************************/

+

+#ifndef BUTTON_H

+#define BUTTON_H

+

+#include <QToolButton>

+

+//! [0]

+class Button : public QToolButton

+{

+    Q_OBJECT

+

+public:

+    explicit Button(const QString &text, QWidget *parent = 0);

+

+    QSize sizeHint() const Q_DECL_OVERRIDE;

+};

+//! [0]

+

+#endif

diff --git a/third_party/SingleApplication-3.3.0/examples/calculator/calculator.cpp b/third_party/SingleApplication-3.3.0/examples/calculator/calculator.cpp
new file mode 100644
index 00000000..3d34c2a7
--- /dev/null
+++ b/third_party/SingleApplication-3.3.0/examples/calculator/calculator.cpp
@@ -0,0 +1,406 @@
+/****************************************************************************

+**

+** Copyright (C) 2016 The Qt Company Ltd.

+** Contact: https://www.qt.io/licensing/

+**

+** This file is part of the examples of the Qt Toolkit.

+**

+** $QT_BEGIN_LICENSE:BSD$

+** Commercial License Usage

+** Licensees holding valid commercial Qt licenses may use this file in

+** accordance with the commercial license agreement provided with the

+** Software or, alternatively, in accordance with the terms contained in

+** a written agreement between you and The Qt Company. For licensing terms

+** and conditions see https://www.qt.io/terms-conditions. For further

+** information use the contact form at https://www.qt.io/contact-us.

+**

+** BSD License Usage

+** Alternatively, you may use this file under the terms of the BSD license

+** as follows:

+**

+** "Redistribution and use in source and binary forms, with or without

+** modification, are permitted provided that the following conditions are

+** met:

+**   * Redistributions of source code must retain the above copyright

+**     notice, this list of conditions and the following disclaimer.

+**   * Redistributions in binary form must reproduce the above copyright

+**     notice, this list of conditions and the following disclaimer in

+**     the documentation and/or other materials provided with the

+**     distribution.

+**   * Neither the name of The Qt Company Ltd nor the names of its

+**     contributors may be used to endorse or promote products derived

+**     from this software without specific prior written permission.

+**

+**

+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."

+**

+** $QT_END_LICENSE$

+**

+****************************************************************************/

+

+#include <QtWidgets>

+

+#include <cmath>

+

+#include "button.h"

+#include "calculator.h"

+

+//! [0]

+Calculator::Calculator(QWidget *parent)

+    : QWidget(parent)

+{

+    sumInMemory = 0.0;

+    sumSoFar = 0.0;

+    factorSoFar = 0.0;

+    waitingForOperand = true;

+//! [0]

+

+//! [1]

+    display = new QLineEdit("0");

+//! [1] //! [2]

+    display->setReadOnly(true);

+    display->setAlignment(Qt::AlignRight);

+    display->setMaxLength(15);

+

+    QFont font = display->font();

+    font.setPointSize(font.pointSize() + 8);

+    display->setFont(font);

+//! [2]

+

+//! [4]

+    for (int i = 0; i < NumDigitButtons; ++i) {

+        digitButtons[i] = createButton(QString::number(i), SLOT(digitClicked()));

+    }

+

+    Button *pointButton = createButton(".", SLOT(pointClicked()));

+    Button *changeSignButton = createButton("\302\261", SLOT(changeSignClicked()));

+

+    Button *backspaceButton = createButton("Backspace", SLOT(backspaceClicked()));

+    Button *clearButton = createButton("Clear", SLOT(clear()));

+    Button *clearAllButton = createButton("Clear All", SLOT(clearAll()));

+

+    Button *clearMemoryButton = createButton("MC", SLOT(clearMemory()));

+    Button *readMemoryButton = createButton("MR", SLOT(readMemory()));

+    Button *setMemoryButton = createButton("MS", SLOT(setMemory()));

+    Button *addToMemoryButton = createButton("M+", SLOT(addToMemory()));

+

+    Button *divisionButton = createButton("\303\267", SLOT(multiplicativeOperatorClicked()));

+    Button *timesButton = createButton("\303\227", SLOT(multiplicativeOperatorClicked()));

+    Button *minusButton = createButton("-", SLOT(additiveOperatorClicked()));

+    Button *plusButton = createButton("+", SLOT(additiveOperatorClicked()));

+

+    Button *squareRootButton = createButton("Sqrt", SLOT(unaryOperatorClicked()));

+    Button *powerButton = createButton("x\302\262", SLOT(unaryOperatorClicked()));

+    Button *reciprocalButton = createButton("1/x", SLOT(unaryOperatorClicked()));

+    Button *equalButton = createButton("=", SLOT(equalClicked()));

+//! [4]

+

+//! [5]

+    QGridLayout *mainLayout = new QGridLayout;

+//! [5] //! [6]

+    mainLayout->setSizeConstraint(QLayout::SetFixedSize);

+    mainLayout->addWidget(display, 0, 0, 1, 6);

+    mainLayout->addWidget(backspaceButton, 1, 0, 1, 2);

+    mainLayout->addWidget(clearButton, 1, 2, 1, 2);

+    mainLayout->addWidget(clearAllButton, 1, 4, 1, 2);

+

+    mainLayout->addWidget(clearMemoryButton, 2, 0);

+    mainLayout->addWidget(readMemoryButton, 3, 0);

+    mainLayout->addWidget(setMemoryButton, 4, 0);

+    mainLayout->addWidget(addToMemoryButton, 5, 0);

+

+    for (int i = 1; i < NumDigitButtons; ++i) {

+        int row = ((9 - i) / 3) + 2;

+        int column = ((i - 1) % 3) + 1;

+        mainLayout->addWidget(digitButtons[i], row, column);

+    }

+

+    mainLayout->addWidget(digitButtons[0], 5, 1);

+    mainLayout->addWidget(pointButton, 5, 2);

+    mainLayout->addWidget(changeSignButton, 5, 3);

+

+    mainLayout->addWidget(divisionButton, 2, 4);

+    mainLayout->addWidget(timesButton, 3, 4);

+    mainLayout->addWidget(minusButton, 4, 4);

+    mainLayout->addWidget(plusButton, 5, 4);

+

+    mainLayout->addWidget(squareRootButton, 2, 5);

+    mainLayout->addWidget(powerButton, 3, 5);

+    mainLayout->addWidget(reciprocalButton, 4, 5);

+    mainLayout->addWidget(equalButton, 5, 5);

+    setLayout(mainLayout);

+

+    setWindowTitle("Calculator");

+}

+//! [6]

+

+//! [7]

+void Calculator::digitClicked()

+{

+    Button *clickedButton = qobject_cast<Button *>(sender());

+    int digitValue = clickedButton->text().toInt();

+    if (display->text() == "0" && digitValue == 0.0)

+        return;

+

+    if (waitingForOperand) {

+        display->clear();

+        waitingForOperand = false;

+    }

+    display->setText(display->text() + QString::number(digitValue));

+}

+//! [7]

+

+//! [8]

+void Calculator::unaryOperatorClicked()

+//! [8] //! [9]

+{

+    Button *clickedButton = qobject_cast<Button *>(sender());

+    QString clickedOperator = clickedButton->text();

+    double operand = display->text().toDouble();

+    double result = 0.0;

+

+    if (clickedOperator == "Sqrt") {

+        if (operand < 0.0) {

+            abortOperation();

+            return;

+        }

+        result = std::sqrt(operand);

+    } else if (clickedOperator == "x\302\262") {

+        result = std::pow(operand, 2.0);

+    } else if (clickedOperator == "1/x") {

+        if (operand == 0.0) {

+            abortOperation();

+            return;

+        }

+        result = 1.0 / operand;

+    }

+    display->setText(QString::number(result));

+    waitingForOperand = true;

+}

+//! [9]

+

+//! [10]

+void Calculator::additiveOperatorClicked()

+//! [10] //! [11]

+{

+    Button *clickedButton = qobject_cast<Button *>(sender());

+    QString clickedOperator = clickedButton->text();

+    double operand = display->text().toDouble();

+

+//! [11] //! [12]

+    if (!pendingMultiplicativeOperator.isEmpty()) {

+//! [12] //! [13]

+        if (!calculate(operand, pendingMultiplicativeOperator)) {

+            abortOperation();

+            return;

+        }

+        display->setText(QString::number(factorSoFar));

+        operand = factorSoFar;

+        factorSoFar = 0.0;

+        pendingMultiplicativeOperator.clear();

+    }

+

+//! [13] //! [14]

+    if (!pendingAdditiveOperator.isEmpty()) {

+//! [14] //! [15]

+        if (!calculate(operand, pendingAdditiveOperator)) {

+            abortOperation();

+            return;

+        }

+        display->setText(QString::number(sumSoFar));

+    } else {

+        sumSoFar = operand;

+    }

+

+//! [15] //! [16]

+    pendingAdditiveOperator = clickedOperator;

+//! [16] //! [17]

+    waitingForOperand = true;

+}

+//! [17]

+

+//! [18]

+void Calculator::multiplicativeOperatorClicked()

+{

+    Button *clickedButton = qobject_cast<Button *>(sender());

+    QString clickedOperator = clickedButton->text();

+    double operand = display->text().toDouble();

+

+    if (!pendingMultiplicativeOperator.isEmpty()) {

+        if (!calculate(operand, pendingMultiplicativeOperator)) {

+            abortOperation();

+            return;

+        }

+        display->setText(QString::number(factorSoFar));

+    } else {

+        factorSoFar = operand;

+    }

+

+    pendingMultiplicativeOperator = clickedOperator;

+    waitingForOperand = true;

+}

+//! [18]

+

+//! [20]

+void Calculator::equalClicked()

+{

+    double operand = display->text().toDouble();

+

+    if (!pendingMultiplicativeOperator.isEmpty()) {

+        if (!calculate(operand, pendingMultiplicativeOperator)) {

+            abortOperation();

+            return;

+        }

+        operand = factorSoFar;

+        factorSoFar = 0.0;

+        pendingMultiplicativeOperator.clear();

+    }

+    if (!pendingAdditiveOperator.isEmpty()) {

+        if (!calculate(operand, pendingAdditiveOperator)) {

+            abortOperation();

+            return;

+        }

+        pendingAdditiveOperator.clear();

+    } else {

+        sumSoFar = operand;

+    }

+

+    display->setText(QString::number(sumSoFar));

+    sumSoFar = 0.0;

+    waitingForOperand = true;

+}

+//! [20]

+

+//! [22]

+void Calculator::pointClicked()

+{

+    if (waitingForOperand)

+        display->setText("0");

+    if (!display->text().contains('.'))

+        display->setText(display->text() + ".");

+    waitingForOperand = false;

+}

+//! [22]

+

+//! [24]

+void Calculator::changeSignClicked()

+{

+    QString text = display->text();

+    double value = text.toDouble();

+

+    if (value > 0.0) {

+        text.prepend("-");

+    } else if (value < 0.0) {

+        text.remove(0, 1);

+    }

+    display->setText(text);

+}

+//! [24]

+

+//! [26]

+void Calculator::backspaceClicked()

+{

+    if (waitingForOperand)

+        return;

+

+    QString text = display->text();

+    text.chop(1);

+    if (text.isEmpty()) {

+        text = "0";

+        waitingForOperand = true;

+    }

+    display->setText(text);

+}

+//! [26]

+

+//! [28]

+void Calculator::clear()

+{

+    if (waitingForOperand)

+        return;

+

+    display->setText("0");

+    waitingForOperand = true;

+}

+//! [28]

+

+//! [30]

+void Calculator::clearAll()

+{

+    sumSoFar = 0.0;

+    factorSoFar = 0.0;

+    pendingAdditiveOperator.clear();

+    pendingMultiplicativeOperator.clear();

+    display->setText("0");

+    waitingForOperand = true;

+}

+//! [30]

+

+//! [32]

+void Calculator::clearMemory()

+{

+    sumInMemory = 0.0;

+}

+

+void Calculator::readMemory()

+{

+    display->setText(QString::number(sumInMemory));

+    waitingForOperand = true;

+}

+

+void Calculator::setMemory()

+{

+    equalClicked();

+    sumInMemory = display->text().toDouble();

+}

+

+void Calculator::addToMemory()

+{

+    equalClicked();

+    sumInMemory += display->text().toDouble();

+}

+//! [32]

+//! [34]

+Button *Calculator::createButton(const QString &text, const char *member)

+{

+    Button *button = new Button(text);

+    connect(button, SIGNAL(clicked()), this, member);

+    return button;

+}

+//! [34]

+

+//! [36]

+void Calculator::abortOperation()

+{

+    clearAll();

+    display->setText("####");

+}

+//! [36]

+

+//! [38]

+bool Calculator::calculate(double rightOperand, const QString &pendingOperator)

+{

+    if (pendingOperator == "+") {

+        sumSoFar += rightOperand;

+    } else if (pendingOperator == "-") {

+        sumSoFar -= rightOperand;

+    } else if (pendingOperator == "\303\227") {

+        factorSoFar *= rightOperand;

+    } else if (pendingOperator == "\303\267") {

+        if (rightOperand == 0.0)

+            return false;

+        factorSoFar /= rightOperand;

+    }

+    return true;

+}

+//! [38]

diff --git a/third_party/SingleApplication-3.3.0/examples/calculator/calculator.h b/third_party/SingleApplication-3.3.0/examples/calculator/calculator.h
new file mode 100644
index 00000000..250a2f3e
--- /dev/null
+++ b/third_party/SingleApplication-3.3.0/examples/calculator/calculator.h
@@ -0,0 +1,117 @@
+/****************************************************************************

+**

+** Copyright (C) 2016 The Qt Company Ltd.

+** Contact: https://www.qt.io/licensing/

+**

+** This file is part of the examples of the Qt Toolkit.

+**

+** $QT_BEGIN_LICENSE:BSD$

+** Commercial License Usage

+** Licensees holding valid commercial Qt licenses may use this file in

+** accordance with the commercial license agreement provided with the

+** Software or, alternatively, in accordance with the terms contained in

+** a written agreement between you and The Qt Company. For licensing terms

+** and conditions see https://www.qt.io/terms-conditions. For further

+** information use the contact form at https://www.qt.io/contact-us.

+**

+** BSD License Usage

+** Alternatively, you may use this file under the terms of the BSD license

+** as follows:

+**

+** "Redistribution and use in source and binary forms, with or without

+** modification, are permitted provided that the following conditions are

+** met:

+**   * Redistributions of source code must retain the above copyright

+**     notice, this list of conditions and the following disclaimer.

+**   * Redistributions in binary form must reproduce the above copyright

+**     notice, this list of conditions and the following disclaimer in

+**     the documentation and/or other materials provided with the

+**     distribution.

+**   * Neither the name of The Qt Company Ltd nor the names of its

+**     contributors may be used to endorse or promote products derived

+**     from this software without specific prior written permission.

+**

+**

+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."

+**

+** $QT_END_LICENSE$

+**

+****************************************************************************/

+

+#ifndef CALCULATOR_H

+#define CALCULATOR_H

+

+#include <QWidget>

+

+QT_BEGIN_NAMESPACE

+class QLineEdit;

+QT_END_NAMESPACE

+class Button;

+

+//! [0]

+class Calculator : public QWidget

+{

+    Q_OBJECT

+

+public:

+    Calculator(QWidget *parent = 0);

+

+private slots:

+    void digitClicked();

+    void unaryOperatorClicked();

+    void additiveOperatorClicked();

+    void multiplicativeOperatorClicked();

+    void equalClicked();

+    void pointClicked();

+    void changeSignClicked();

+    void backspaceClicked();

+    void clear();

+    void clearAll();

+    void clearMemory();

+    void readMemory();

+    void setMemory();

+    void addToMemory();

+//! [0]

+

+//! [1]

+private:

+//! [1] //! [2]

+    Button *createButton(const QString &text, const char *member);

+    void abortOperation();

+    bool calculate(double rightOperand, const QString &pendingOperator);

+//! [2]

+

+//! [3]

+    double sumInMemory;

+//! [3] //! [4]

+    double sumSoFar;

+//! [4] //! [5]

+    double factorSoFar;

+//! [5] //! [6]

+    QString pendingAdditiveOperator;

+//! [6] //! [7]

+    QString pendingMultiplicativeOperator;

+//! [7] //! [8]

+    bool waitingForOperand;

+//! [8]

+

+//! [9]

+    QLineEdit *display;

+//! [9] //! [10]

+

+    enum { NumDigitButtons = 10 };

+    Button *digitButtons[NumDigitButtons];

+};

+//! [10]

+

+#endif

diff --git a/third_party/SingleApplication-3.3.0/examples/calculator/calculator.pro b/third_party/SingleApplication-3.3.0/examples/calculator/calculator.pro
new file mode 100644
index 00000000..8f132609
--- /dev/null
+++ b/third_party/SingleApplication-3.3.0/examples/calculator/calculator.pro
@@ -0,0 +1,11 @@
+QT += widgets

+

+HEADERS = button.h \

+    calculator.h

+SOURCES = button.cpp \

+    calculator.cpp \

+    main.cpp

+

+# Single Application implementation

+include(../../singleapplication.pri)

+DEFINES += QAPPLICATION_CLASS=QApplication

diff --git a/third_party/SingleApplication-3.3.0/examples/calculator/main.cpp b/third_party/SingleApplication-3.3.0/examples/calculator/main.cpp
new file mode 100644
index 00000000..d45438f4
--- /dev/null
+++ b/third_party/SingleApplication-3.3.0/examples/calculator/main.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************

+**

+** Copyright (C) 2016 The Qt Company Ltd.

+** Contact: https://www.qt.io/licensing/

+**

+** This file is part of the examples of the Qt Toolkit.

+**

+** $QT_BEGIN_LICENSE:BSD$

+** Commercial License Usage

+** Licensees holding valid commercial Qt licenses may use this file in

+** accordance with the commercial license agreement provided with the

+** Software or, alternatively, in accordance with the terms contained in

+** a written agreement between you and The Qt Company. For licensing terms

+** and conditions see https://www.qt.io/terms-conditions. For further

+** information use the contact form at https://www.qt.io/contact-us.

+**

+** BSD License Usage

+** Alternatively, you may use this file under the terms of the BSD license

+** as follows:

+**

+** "Redistribution and use in source and binary forms, with or without

+** modification, are permitted provided that the following conditions are

+** met:

+**   * Redistributions of source code must retain the above copyright

+**     notice, this list of conditions and the following disclaimer.

+**   * Redistributions in binary form must reproduce the above copyright

+**     notice, this list of conditions and the following disclaimer in

+**     the documentation and/or other materials provided with the

+**     distribution.

+**   * Neither the name of The Qt Company Ltd nor the names of its

+**     contributors may be used to endorse or promote products derived

+**     from this software without specific prior written permission.

+**

+**

+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."

+**

+** $QT_END_LICENSE$

+**

+****************************************************************************/

+

+#include <QApplication>

+

+#include <singleapplication.h>

+

+#include "calculator.h"

+

+int main(int argc, char *argv[])

+{

+    SingleApplication app(argc, argv);

+

+    Calculator calc;

+

+    QObject::connect( &app, &SingleApplication::instanceStarted, [ &calc ]() {

+        calc.raise();

+        calc.activateWindow();

+    });

+

+    calc.show();

+

+    return app.exec();

+}

diff --git a/third_party/SingleApplication-3.3.0/examples/sending_arguments/CMakeLists.txt b/third_party/SingleApplication-3.3.0/examples/sending_arguments/CMakeLists.txt
new file mode 100644
index 00000000..2cc55975
--- /dev/null
+++ b/third_party/SingleApplication-3.3.0/examples/sending_arguments/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.7.0)
+
+project(sending_arguments LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+
+# SingleApplication base class
+set(QAPPLICATION_CLASS QCoreApplication)
+add_subdirectory(../.. SingleApplication)
+
+find_package(Qt${QT_DEFAULT_MAJOR_VERSION} COMPONENTS Core REQUIRED)
+
+add_executable(${PROJECT_NAME}
+    main.cpp
+    messagereceiver.cpp
+    messagereceiver.h
+    main.cpp
+)
+
+target_link_libraries(${PROJECT_NAME} SingleApplication::SingleApplication)
diff --git a/third_party/SingleApplication-3.3.0/examples/sending_arguments/main.cpp b/third_party/SingleApplication-3.3.0/examples/sending_arguments/main.cpp
new file mode 100755
index 00000000..a9d34dd9
--- /dev/null
+++ b/third_party/SingleApplication-3.3.0/examples/sending_arguments/main.cpp
@@ -0,0 +1,28 @@
+#include <singleapplication.h>
+#include "messagereceiver.h"
+
+int main(int argc, char *argv[])
+{
+    // Allow secondary instances
+    SingleApplication app( argc, argv, true );
+
+    MessageReceiver msgReceiver;
+
+    // If this is a secondary instance
+    if( app.isSecondary() ) {
+        app.sendMessage( app.arguments().join(' ').toUtf8() );
+        qDebug() << "App already running.";
+        qDebug() << "Primary instance PID: " << app.primaryPid();
+        qDebug() << "Primary instance user: " << app.primaryUser();
+        return 0;
+    } else {
+        QObject::connect(
+            &app,
+            &SingleApplication::receivedMessage,
+            &msgReceiver,
+            &MessageReceiver::receivedMessage
+        );
+    }
+
+    return app.exec();
+}
diff --git a/third_party/SingleApplication-3.3.0/examples/sending_arguments/messagereceiver.cpp b/third_party/SingleApplication-3.3.0/examples/sending_arguments/messagereceiver.cpp
new file mode 100644
index 00000000..0560b072
--- /dev/null
+++ b/third_party/SingleApplication-3.3.0/examples/sending_arguments/messagereceiver.cpp
@@ -0,0 +1,12 @@
+#include <QDebug>
+#include "messagereceiver.h"
+
+MessageReceiver::MessageReceiver(QObject *parent) : QObject(parent)
+{
+}
+
+void MessageReceiver::receivedMessage(int instanceId, QByteArray message)
+{
+    qDebug() << "Received message from instance: " << instanceId;
+    qDebug() << "Message Text: " << message;
+}
diff --git a/third_party/SingleApplication-3.3.0/examples/sending_arguments/messagereceiver.h b/third_party/SingleApplication-3.3.0/examples/sending_arguments/messagereceiver.h
new file mode 100644
index 00000000..50a970c8
--- /dev/null
+++ b/third_party/SingleApplication-3.3.0/examples/sending_arguments/messagereceiver.h
@@ -0,0 +1,15 @@
+#ifndef MESSAGERECEIVER_H
+#define MESSAGERECEIVER_H
+
+#include <QObject>
+
+class MessageReceiver : public QObject
+{
+    Q_OBJECT
+public:
+    explicit MessageReceiver(QObject *parent = 0);
+public slots:
+    void receivedMessage( int instanceId, QByteArray message );
+};
+
+#endif // MESSAGERECEIVER_H
diff --git a/third_party/SingleApplication-3.3.0/examples/sending_arguments/sending_arguments.pro b/third_party/SingleApplication-3.3.0/examples/sending_arguments/sending_arguments.pro
new file mode 100755
index 00000000..897636a9
--- /dev/null
+++ b/third_party/SingleApplication-3.3.0/examples/sending_arguments/sending_arguments.pro
@@ -0,0 +1,9 @@
+# Single Application implementation
+include(../../singleapplication.pri)
+DEFINES += QAPPLICATION_CLASS=QCoreApplication
+
+SOURCES += main.cpp \
+    messagereceiver.cpp
+
+HEADERS += \
+    messagereceiver.h
diff --git a/third_party/SingleApplication-3.2.0-dc8042b/singleapplication.cpp b/third_party/SingleApplication-3.3.0/singleapplication.cpp
index 276ceee9..09e264ef 100644
--- a/third_party/SingleApplication-3.2.0-dc8042b/singleapplication.cpp
+++ b/third_party/SingleApplication-3.3.0/singleapplication.cpp
@@ -36,7 +36,7 @@
  * @param options Optional flags to toggle specific behaviour
  * @param timeout Maximum time blocking functions are allowed during app load
  */
-SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary, Options options, int timeout, QString userData )
+SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary, Options options, int timeout, const QString &userData )
     : app_t( argc, argv ), d_ptr( new SingleApplicationPrivate( this ) )
 {
     Q_D( SingleApplication );
@@ -172,9 +172,9 @@ SingleApplication::~SingleApplication()
  * Checks if the current application instance is primary.
  * @return Returns true if the instance is primary, false otherwise.
  */
-bool SingleApplication::isPrimary()
+bool SingleApplication::isPrimary() const
 {
-    Q_D( SingleApplication );
+    Q_D( const SingleApplication );
     return d->server != nullptr;
 }
 
@@ -182,9 +182,9 @@ bool SingleApplication::isPrimary()
  * Checks if the current application instance is secondary.
  * @return Returns true if the instance is secondary, false otherwise.
  */
-bool SingleApplication::isSecondary()
+bool SingleApplication::isSecondary() const
 {
-    Q_D( SingleApplication );
+    Q_D( const SingleApplication );
     return d->server == nullptr;
 }
 
@@ -194,9 +194,9 @@ bool SingleApplication::isSecondary()
  * only incremented afterwards.
  * @return Returns a unique instance id.
  */
-quint32 SingleApplication::instanceId()
+quint32 SingleApplication::instanceId() const
 {
-    Q_D( SingleApplication );
+    Q_D( const SingleApplication );
     return d->instanceNumber;
 }
 
@@ -206,9 +206,9 @@ quint32 SingleApplication::instanceId()
  * specific APIs.
  * @return Returns the primary instance PID.
  */
-qint64 SingleApplication::primaryPid()
+qint64 SingleApplication::primaryPid() const
 {
-    Q_D( SingleApplication );
+    Q_D( const SingleApplication );
     return d->primaryPid();
 }
 
@@ -216,9 +216,9 @@ qint64 SingleApplication::primaryPid()
  * Returns the username the primary instance is running as.
  * @return Returns the username the primary instance is running as.
  */
-QString SingleApplication::primaryUser()
+QString SingleApplication::primaryUser() const
 {
-    Q_D( SingleApplication );
+    Q_D( const SingleApplication );
     return d->primaryUser();
 }
 
@@ -226,7 +226,7 @@ QString SingleApplication::primaryUser()
  * Returns the username the current instance is running as.
  * @return Returns the username the current instance is running as.
  */
-QString SingleApplication::currentUser()
+QString SingleApplication::currentUser() const
 {
     return SingleApplicationPrivate::getUsername();
 }
@@ -248,10 +248,7 @@ bool SingleApplication::sendMessage( const QByteArray &message, int timeout )
     if( ! d->connectToPrimary( timeout,  SingleApplicationPrivate::Reconnect ) )
       return false;
 
-    d->socket->write( message );
-    bool dataWritten = d->socket->waitForBytesWritten( timeout );
-    d->socket->flush();
-    return dataWritten;
+    return d->writeConfirmedMessage( timeout, message );
 }
 
 /**
@@ -267,8 +264,8 @@ void SingleApplication::abortSafely()
     ::exit( EXIT_FAILURE );
 }
 
-QStringList SingleApplication::userData()
+QStringList SingleApplication::userData() const
 {
-    Q_D( SingleApplication );
+    Q_D( const SingleApplication );
     return d->appData();
 }
diff --git a/third_party/SingleApplication-3.2.0-dc8042b/singleapplication.h b/third_party/SingleApplication-3.3.0/singleapplication.h
index d39a6614..91cabf93 100644
--- a/third_party/SingleApplication-3.2.0-dc8042b/singleapplication.h
+++ b/third_party/SingleApplication-3.3.0/singleapplication.h
@@ -85,44 +85,44 @@ public:
      * Usually 4*timeout would be the worst case (fail) scenario.
      * @see See the corresponding QAPPLICATION_CLASS constructor for reference
      */
-    explicit SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 1000, QString userData = QString() );
+    explicit SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 1000, const QString &userData = {} );
     ~SingleApplication() override;
 
     /**
      * @brief Returns if the instance is the primary instance
      * @returns {bool}
      */
-    bool isPrimary();
+    bool isPrimary() const;
 
     /**
      * @brief Returns if the instance is a secondary instance
      * @returns {bool}
      */
-    bool isSecondary();
+    bool isSecondary() const;
 
     /**
      * @brief Returns a unique identifier for the current instance
      * @returns {qint32}
      */
-    quint32 instanceId();
+    quint32 instanceId() const;
 
     /**
      * @brief Returns the process ID (PID) of the primary instance
      * @returns {qint64}
      */
-    qint64 primaryPid();
+    qint64 primaryPid() const;
 
     /**
      * @brief Returns the username of the user running the primary instance
      * @returns {QString}
      */
-    QString primaryUser();
+    QString primaryUser() const;
 
     /**
      * @brief Returns the username of the current user
      * @returns {QString}
      */
-    QString currentUser();
+    QString currentUser() const;
 
     /**
      * @brief Sends a message to the primary instance. Returns true on success.
@@ -137,7 +137,7 @@ public:
      * @brief Get the set user data.
      * @returns {QStringList}
      */
-    QStringList userData();
+    QStringList userData() const;
 
 Q_SIGNALS:
     void instanceStarted();
diff --git a/third_party/SingleApplication-3.2.0-dc8042b/singleapplication.pri b/third_party/SingleApplication-3.3.0/singleapplication.pri
index ae81f599..ae81f599 100644
--- a/third_party/SingleApplication-3.2.0-dc8042b/singleapplication.pri
+++ b/third_party/SingleApplication-3.3.0/singleapplication.pri
diff --git a/third_party/SingleApplication-3.2.0-dc8042b/singleapplication_p.cpp b/third_party/SingleApplication-3.3.0/singleapplication_p.cpp
index 1ab58c23..13397282 100644
--- a/third_party/SingleApplication-3.2.0-dc8042b/singleapplication_p.cpp
+++ b/third_party/SingleApplication-3.3.0/singleapplication_p.cpp
@@ -263,20 +263,46 @@ bool SingleApplicationPrivate::connectToPrimary( int msecs, ConnectionType conne
 #endif
     writeStream << checksum;
 
-    // The header indicates the message length that follows
+    return writeConfirmedMessage( static_cast<int>(msecs - time.elapsed()), initMsg );
+}
+
+void SingleApplicationPrivate::writeAck( QLocalSocket *sock ) {
+    sock->putChar('\n');
+}
+
+bool SingleApplicationPrivate::writeConfirmedMessage (int msecs, const QByteArray &msg)
+{
+    QElapsedTimer time;
+    time.start();
+
+    // Frame 1: The header indicates the message length that follows
     QByteArray header;
     QDataStream headerStream(&header, QIODevice::WriteOnly);
 
 #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
     headerStream.setVersion(QDataStream::Qt_5_6);
 #endif
-    headerStream << static_cast <quint64>( initMsg.length() );
+    headerStream << static_cast <quint64>( msg.length() );
 
-    socket->write( header );
-    socket->write( initMsg );
-    bool result = socket->waitForBytesWritten( static_cast<int>(msecs - time.elapsed()) );
+    if( ! writeConfirmedFrame( static_cast<int>(msecs - time.elapsed()), header ))
+        return false;
+
+    // Frame 2: The message
+    return writeConfirmedFrame( static_cast<int>(msecs - time.elapsed()), msg );
+}
+
+bool SingleApplicationPrivate::writeConfirmedFrame( int msecs, const QByteArray &msg )
+{
+    socket->write( msg );
     socket->flush();
-    return result;
+
+    bool result = socket->waitForReadyRead( msecs ); // await ack byte
+    if (result) {
+        socket->read( 1 );
+        return true;
+    }
+
+    return false;
 }
 
 quint16 SingleApplicationPrivate::blockChecksum() const
@@ -321,32 +347,36 @@ void SingleApplicationPrivate::slotConnectionEstablished()
     QLocalSocket *nextConnSocket = server->nextPendingConnection();
     connectionMap.insert(nextConnSocket, ConnectionInfo());
 
-    QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose,
+    QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose, this,
         [nextConnSocket, this](){
             auto &info = connectionMap[nextConnSocket];
-            Q_EMIT this->slotClientConnectionClosed( nextConnSocket, info.instanceId );
+            this->slotClientConnectionClosed( nextConnSocket, info.instanceId );
         }
     );
 
-    QObject::connect(nextConnSocket, &QLocalSocket::disconnected,
+    QObject::connect(nextConnSocket, &QLocalSocket::disconnected, nextConnSocket, &QLocalSocket::deleteLater);
+
+    QObject::connect(nextConnSocket, &QLocalSocket::destroyed, this,
         [nextConnSocket, this](){
             connectionMap.remove(nextConnSocket);
-            nextConnSocket->deleteLater();
         }
     );
 
-    QObject::connect(nextConnSocket, &QLocalSocket::readyRead,
+    QObject::connect(nextConnSocket, &QLocalSocket::readyRead, this,
         [nextConnSocket, this](){
             auto &info = connectionMap[nextConnSocket];
             switch(info.stage){
-            case StageHeader:
-                readInitMessageHeader(nextConnSocket);
+            case StageInitHeader:
+                readMessageHeader( nextConnSocket, StageInitBody );
                 break;
-            case StageBody:
+            case StageInitBody:
                 readInitMessageBody(nextConnSocket);
                 break;
-            case StageConnected:
-                Q_EMIT this->slotDataAvailable( nextConnSocket, info.instanceId );
+            case StageConnectedHeader:
+                readMessageHeader( nextConnSocket, StageConnectedBody );
+                break;
+            case StageConnectedBody:
+                this->slotDataAvailable( nextConnSocket, info.instanceId );
                 break;
             default:
                 break;
@@ -355,7 +385,7 @@ void SingleApplicationPrivate::slotConnectionEstablished()
     );
 }
 
-void SingleApplicationPrivate::readInitMessageHeader( QLocalSocket *sock )
+void SingleApplicationPrivate::readMessageHeader( QLocalSocket *sock, SingleApplicationPrivate::ConnectionStage nextStage )
 {
     if (!connectionMap.contains( sock )){
         return;
@@ -375,29 +405,35 @@ void SingleApplicationPrivate::readInitMessageHeader( QLocalSocket *sock )
     quint64 msgLen = 0;
     headerStream >> msgLen;
     ConnectionInfo &info = connectionMap[sock];
-    info.stage = StageBody;
+    info.stage = nextStage;
     info.msgLen = msgLen;
 
-    if ( sock->bytesAvailable() >= (qint64) msgLen ){
-        readInitMessageBody( sock );
-    }
+    writeAck( sock );
 }
 
-void SingleApplicationPrivate::readInitMessageBody( QLocalSocket *sock )
+bool SingleApplicationPrivate::isFrameComplete( QLocalSocket *sock )
 {
-    Q_Q(SingleApplication);
-
     if (!connectionMap.contains( sock )){
-        return;
+        return false;
     }
 
     ConnectionInfo &info = connectionMap[sock];
     if( sock->bytesAvailable() < ( qint64 )info.msgLen ){
-        return;
+        return false;
     }
 
+    return true;
+}
+
+void SingleApplicationPrivate::readInitMessageBody( QLocalSocket *sock )
+{
+    Q_Q(SingleApplication);
+
+    if( !isFrameComplete( sock ) )
+        return;
+
     // Read the message body
-    QByteArray msgBytes = sock->read(info.msgLen);
+    QByteArray msgBytes = sock->readAll();
     QDataStream readStream(msgBytes);
 
 #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
@@ -437,8 +473,9 @@ void SingleApplicationPrivate::readInitMessageBody( QLocalSocket *sock )
         return;
     }
 
+    ConnectionInfo &info = connectionMap[sock];
     info.instanceId = instanceId;
-    info.stage = StageConnected;
+    info.stage = StageConnectedHeader;
 
     if( connectionType == NewInstance ||
         ( connectionType == SecondaryInstance &&
@@ -447,21 +484,28 @@ void SingleApplicationPrivate::readInitMessageBody( QLocalSocket *sock )
         Q_EMIT q->instanceStarted();
     }
 
-    if (sock->bytesAvailable() > 0){
-        Q_EMIT this->slotDataAvailable( sock, instanceId );
-    }
+    writeAck( sock );
 }
 
 void SingleApplicationPrivate::slotDataAvailable( QLocalSocket *dataSocket, quint32 instanceId )
 {
     Q_Q(SingleApplication);
+
+    if ( !isFrameComplete( dataSocket ) )
+        return;
+
     Q_EMIT q->receivedMessage( instanceId, dataSocket->readAll() );
+
+    writeAck( dataSocket );
+
+    ConnectionInfo &info = connectionMap[dataSocket];
+    info.stage = StageConnectedHeader;
 }
 
 void SingleApplicationPrivate::slotClientConnectionClosed( QLocalSocket *closedSocket, quint32 instanceId )
 {
     if( closedSocket->bytesAvailable() > 0 )
-        Q_EMIT slotDataAvailable( closedSocket, instanceId  );
+        slotDataAvailable( closedSocket, instanceId  );
 }
 
 void SingleApplicationPrivate::randomSleep()
@@ -470,7 +514,7 @@ void SingleApplicationPrivate::randomSleep()
     QThread::msleep( QRandomGenerator::global()->bounded( 8u, 18u ));
 #else
     qsrand( QDateTime::currentMSecsSinceEpoch() % std::numeric_limits<uint>::max() );
-    QThread::msleep( 8 + static_cast <unsigned long>( static_cast <float>( qrand() ) / RAND_MAX * 10 ));
+    QThread::msleep( qrand() % 11 + 8);
 #endif
 }
 
diff --git a/third_party/SingleApplication-3.2.0-dc8042b/singleapplication_p.h b/third_party/SingleApplication-3.3.0/singleapplication_p.h
index c49a46dd..58507cf3 100644
--- a/third_party/SingleApplication-3.2.0-dc8042b/singleapplication_p.h
+++ b/third_party/SingleApplication-3.3.0/singleapplication_p.h
@@ -61,9 +61,10 @@ public:
         Reconnect = 3
     };
     enum ConnectionStage : quint8 {
-        StageHeader = 0,
-        StageBody = 1,
-        StageConnected = 2,
+        StageInitHeader = 0,
+        StageInitBody = 1,
+        StageConnectedHeader = 2,
+        StageConnectedBody = 3,
     };
     Q_DECLARE_PUBLIC(SingleApplication)
 
@@ -79,8 +80,12 @@ public:
     quint16 blockChecksum() const;
     qint64 primaryPid() const;
     QString primaryUser() const;
-    void readInitMessageHeader(QLocalSocket *socket);
+    bool isFrameComplete(QLocalSocket *sock);
+    void readMessageHeader(QLocalSocket *socket, ConnectionStage nextStage);
     void readInitMessageBody(QLocalSocket *socket);
+    void writeAck(QLocalSocket *sock);
+    bool writeConfirmedFrame(int msecs, const QByteArray &msg);
+    bool writeConfirmedMessage(int msecs, const QByteArray &msg);
     static void randomSleep();
     void addAppData(const QString &data);
     QStringList appData() const;