[qet] qet/qet: [5481] Replace qetsingleapplication by singleApplication.

[ Thread Index | Date Index | More lists.tuxfamily.org/qet Archives ]


Revision: 5481
Author:   blacksun
Date:     2018-08-15 14:45:55 +0200 (Wed, 15 Aug 2018)
Log Message:
-----------
Replace qetsingleapplication by singleApplication.
See : https://github.com/itay-grudev/SingleApplication

Modified Paths:
--------------
    trunk/qelectrotech.pro
    trunk/sources/main.cpp
    trunk/sources/qetapp.cpp
    trunk/sources/qetapp.h

Added Paths:
-----------
    trunk/SingleApplication/
    trunk/SingleApplication/CHANGELOG.md
    trunk/SingleApplication/LICENSE
    trunk/SingleApplication/README.md
    trunk/SingleApplication/Windows.md
    trunk/SingleApplication/examples/
    trunk/SingleApplication/examples/basic/
    trunk/SingleApplication/examples/basic/basic.pro
    trunk/SingleApplication/examples/basic/main.cpp
    trunk/SingleApplication/examples/calculator/
    trunk/SingleApplication/examples/calculator/button.cpp
    trunk/SingleApplication/examples/calculator/button.h
    trunk/SingleApplication/examples/calculator/calculator.cpp
    trunk/SingleApplication/examples/calculator/calculator.h
    trunk/SingleApplication/examples/calculator/calculator.pro
    trunk/SingleApplication/examples/calculator/main.cpp
    trunk/SingleApplication/examples/sending_arguments/
    trunk/SingleApplication/examples/sending_arguments/main.cpp
    trunk/SingleApplication/examples/sending_arguments/messagereceiver.cpp
    trunk/SingleApplication/examples/sending_arguments/messagereceiver.h
    trunk/SingleApplication/examples/sending_arguments/sending_arguments.pro
    trunk/SingleApplication/singleapplication.cpp
    trunk/SingleApplication/singleapplication.h
    trunk/SingleApplication/singleapplication.pri
    trunk/SingleApplication/singleapplication_p.cpp
    trunk/SingleApplication/singleapplication_p.h

Removed Paths:
-------------
    trunk/sources/qetsingleapplication.cpp
    trunk/sources/qetsingleapplication.h

Added: trunk/SingleApplication/CHANGELOG.md
===================================================================
--- trunk/SingleApplication/CHANGELOG.md	                        (rev 0)
+++ trunk/SingleApplication/CHANGELOG.md	2018-08-15 12:45:55 UTC (rev 5481)
@@ -0,0 +1,180 @@
+Changelog
+=========
+
+__3.0.12a__
+----------
+
+* Removed signal handling.
+
+__3.0.11a__
+----------
+
+* Fixed bug where the message sent by the second process was not received
+  correctly when the message is sent immediately following a connection.
+
+   _Francis Giraldeau_
+
+* Refactored code and implemented shared memory block consistency checks
+  via `qChecksum()` (CRC-16).
+* Explicit `qWarning` and `qCritical` when the library is unable to initialise
+  correctly.
+
+__3.0.10__
+----------
+
+* Removed C style casts and eliminated all clang warnings. Fixed `instanceId`
+  reading from only one byte in the message deserialization. Cleaned up
+  serialization code using `QDataStream`. Changed connection type to use
+  `quint8 enum` rather than `char`.
+* Renamed `SingleAppConnectionType` to `ConnectionType`. Added initialization
+  values to all `ConnectionType` enum cases.
+
+    _Jedidiah Buck McCready_
+
+__3.0.9__
+---------
+
+*   Added SingleApplicationPrivate::primaryPid() as a solution to allow
+    bringing the primary window of an application to the foreground on
+    Windows.
+
+    _Eelco van Dam from Peacs BV_
+
+__3.0.8__
+---------
+
+*   Bug fix - changed QApplication::instance() to QCoreApplication::instance()
+
+    _Evgeniy Bazhenov_
+
+__3.0.7a__
+----------
+
+*   Fixed compilation error with Mingw32 in MXE thanks to Vitaly Tonkacheyev.
+*   Removed QMutex used for thread safe behaviour. The implementation now uses
+    QCoreApplication::instance() to get an instance to SingleApplication for
+    memory deallocation.
+
+__3.0.6a__
+----------
+
+*   Reverted GetUserName API usage on Windows. Fixed bug with missing library.
+*   Fixed bug in the Calculator example, preventing it's window to be raised
+    on Windows.
+
+    Special thanks to Charles Gunawan.
+
+__3.0.5a__
+----------
+
+*   Fixed a memory leak in the SingleApplicationPrivate destructor.
+
+    _Sergei Moiseev_
+
+__3.0.4a__
+----------
+
+*   Fixed shadow and uninitialised variable warnings.
+
+    _Paul Walmsley_
+
+__3.0.3a__
+----------
+
+*   Removed Microsoft Windows specific code for getting username due to
+    multiple problems and compiler differences on Windows platforms. On
+    Windows the shared memory block in User mode now includes the user's
+    home path (which contains the user's username).
+
+*   Explicitly getting absolute path of the user's home directory as on Unix
+    a relative path (`~`) may be returned.
+
+__3.0.2a__
+----------
+
+*   Fixed bug on Windows when username containing wide characters causes the
+    library to crash.
+
+    _Le Liu_
+
+__3.0.1a__
+----------
+
+*   Allows the application path and version to be excluded from the server name
+    hash. The following flags were added for this purpose:
+      * `SingleApplication::Mode::ExcludeAppVersion`
+      * `SingleApplication::Mode::ExcludeAppPath`
+*   Allow a non elevated process to connect to a local server created by an
+    elevated process run by the same user on Windows
+*   Fixes a problem with upper case letters in paths on Windows
+
+    _Le Liu_
+
+__v3.0a__
+---------
+
+*   Depricated secondary instances count.
+*   Added a sendMessage() method to send a message to the primary instance.
+*   Added a receivedMessage() signal, emitted when a message is received from a
+    secondary instance.
+*   The SingleApplication constructor's third parameter is now a bool
+    specifying if the current instance should be allowed to run as a secondary
+    instance if there is already a primary instance.
+*   The SingleApplication constructor accept a fourth parameter specifying if
+    the SingleApplication block should be User-wide or System-wide.
+*   SingleApplication no longer relies on `applicationName` and
+    `organizationName` to be set. It instead concatenates all of the following
+    data and computes a `SHA256` hash which is used as the key of the
+    `QSharedMemory` block and the `QLocalServer`. Since at least
+    `applicationFilePath` is always present there is no need to explicitly set
+    any of the following prior to initialising `SingleApplication`.
+      * `QCoreApplication::applicationName`
+      * `QCoreApplication::applicationVersion`
+      * `QCoreApplication::applicationFilePath`
+      * `QCoreApplication::organizationName`
+      * `QCoreApplication::organizationDomain`
+      * User name or home directory path if in User mode
+*   The primary instance is no longer notified when a secondary instance had
+    been started by default. A `Mode` flag for this feature exists.
+*   Added `instanceNumber()` which represents a unique identifier for each
+    secondary instance started. When called from the primary instance will
+    return `0`.
+
+__v2.4__
+--------
+
+*   Stability improvements
+*   Support for secondary instances.
+*   The library now recovers safely after the primary process has crashed
+and the shared memory had not been deleted.
+
+__v2.3__
+--------
+
+*   Improved pimpl design and inheritance safety.
+
+    _Vladislav Pyatnichenko_
+
+__v2.2__
+--------
+
+*   The `QAPPLICATION_CLASS` macro can now be defined in the file including the
+Single Application header or with a `DEFINES+=` statement in the project file.
+
+__v2.1__
+--------
+
+*   A race condition can no longer occur when starting two processes nearly
+    simultaneously.
+
+    Fix issue [#3](https://github.com/itay-grudev/SingleApplication/issues/3)
+
+__v2.0__
+--------
+
+*   SingleApplication is now being passed a reference to `argc` instead of a
+    copy.
+
+    Fix issue [#1](https://github.com/itay-grudev/SingleApplication/issues/1)
+
+*   Improved documentation.

Added: trunk/SingleApplication/LICENSE
===================================================================
--- trunk/SingleApplication/LICENSE	                        (rev 0)
+++ trunk/SingleApplication/LICENSE	2018-08-15 12:45:55 UTC (rev 5481)
@@ -0,0 +1,24 @@
+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.
+
+Note: Some of the examples include code not distributed under the terms of the
+MIT License.

Added: trunk/SingleApplication/README.md
===================================================================
--- trunk/SingleApplication/README.md	                        (rev 0)
+++ trunk/SingleApplication/README.md	2018-08-15 12:45:55 UTC (rev 5481)
@@ -0,0 +1,265 @@
+SingleApplication
+=================
+
+This is a replacement of the QtSingleApplication for `Qt5`.
+
+Keeps the Primary Instance of your Application and kills each subsequent
+instances. It can (if enabled) spawn secondary (non-related to the primary)
+instances and can send data to the primary instance from secondary instances.
+
+Usage
+-----
+
+The `SingleApplication` class inherits from whatever `Q[Core|Gui]Application`
+class you specify via the `QAPPLICATION_CLASS` macro (`QCoreApplication` is the
+default). Further usage is similar to the use of the `Q[Core|Gui]Application`
+classes.
+
+The library sets up a `QLocalServer` and a `QSharedMemory` block. The first
+instance of your Application is your Primary Instance. It would check if the
+shared memory block exists and if not it will start a `QLocalServer` and listen
+for connections. Each subsequent instance of your application would check if the
+shared memory block exists and if it does, it will connect to the QLocalServer
+to notify the primary instance that a new instance had been started, after which
+it would terminate with status code `0`. In the Primary Instance
+`SingleApplication` would emit the `instanceStarted()` signal upon detecting
+that a new instance had been started.
+
+The library uses `stdlib` to terminate the program with the `exit()` function.
+
+You can use the library as if you use any other `QCoreApplication` derived
+class:
+
+```cpp
+#include <QApplication>
+#include <SingleApplication.h>
+
+int main( int argc, char* argv[] )
+{
+    SingleApplication app( argc, argv );
+
+    return app.exec();
+}
+```
+
+To include the library files I would recommend that you add it as a git
+submodule to your project and include it's contents with a `.pri` file. Here is
+how:
+
+```bash
+git submodule add git@xxxxxxxxxx:itay-grudev/SingleApplication.git singleapplication
+```
+
+Then include the `singleapplication.pri` file in your `.pro` project file. Also
+don't forget to specify which `QCoreApplication` class your app is using if it
+is not `QCoreApplication`.
+
+```qmake
+include(singleapplication/singleapplication.pri)
+DEFINES += QAPPLICATION_CLASS=QApplication
+```
+
+The `Instance Started` signal
+------------------------
+
+The SingleApplication class implements a `instanceStarted()` signal. You can
+bind to that signal to raise your application's window when a new instance had
+been started, for example.
+
+```cpp
+// window is a QWindow instance
+QObject::connect(
+    &app,
+    &SingleApplication::instanceStarted,
+    &window,
+    &QWindow::raise
+);
+```
+
+Using `SingleApplication::instance()` is a neat way to get the
+`SingleApplication` instance for binding to it's signals anywhere in your
+program.
+
+__Note:__ On Windows the ability to bring the application windows to the
+foreground is restricted. See [Windows specific implementations](Windows.md)
+for a workaround and an example implementation.
+
+
+Secondary Instances
+-------------------
+
+If you want to be able to launch additional Secondary Instances (not related to
+your Primary Instance) you have to enable that with the third parameter of the
+`SingleApplication` constructor. The default is `false` meaning no Secondary
+Instances. Here is an example of how you would start a Secondary Instance send
+a message with the command line arguments to the primary instance and then shut
+down.
+
+```cpp
+int main(int argc, char *argv[])
+{
+    SingleApplication app( argc, argv, true );
+
+    if( app.isSecondary() ) {
+        app.sendMessage(  app.arguments().join(' ')).toUtf8() );
+        app.exit( 0 );
+    }
+
+    return app.exec();
+}
+```
+
+*__Note:__ A secondary instance won't cause the emission of the
+`instanceStarted()` signal by default. See `SingleApplication::Mode` for more
+details.*
+
+You can check whether your instance is a primary or secondary with the following
+methods:
+
+```cpp
+app.isPrimary();
+// or
+app.isSecondary();
+```
+
+*__Note:__ If your Primary Instance is terminated a newly launched instance
+will replace the Primary one even if the Secondary flag has been set.*
+
+API
+---
+
+### Members
+
+```cpp
+SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 100 )
+```
+
+Depending on whether `allowSecondary` is set, this constructor may terminate
+your app if there is already a primary instance running. Additional `Options`
+can be specified to set whether the SingleApplication block should work
+user-wide or system-wide. Additionally the `Mode::SecondaryNotification` may be
+used to notify the primary instance whenever a secondary instance had been
+started (disabled by default). `timeout` specifies the maximum time in
+milliseconds to wait for blocking operations.
+
+*__Note:__ `argc` and `argv` may be changed as Qt removes arguments that it
+recognizes.*
+
+*__Note:__ `Mode::SecondaryNotification` only works if set on both the primary
+and the secondary instance.*
+
+*__Note:__ Operating system can restrict the shared memory blocks to the same
+user, in which case the User/System modes will have no effect and the block will
+be user wide.*
+
+---
+
+```cpp
+bool SingleApplication::sendMessage( QByteArray message, int timeout = 100 )
+```
+
+Sends `message` to the Primary Instance. Uses `timeout` as a the maximum timeout
+in milliseconds for blocking functions
+
+---
+
+```cpp
+bool SingleApplication::isPrimary()
+```
+
+Returns if the instance is the primary instance.
+
+---
+
+```cpp
+bool SingleApplication::isSecondary()
+```
+Returns if the instance is a secondary instance.
+
+---
+
+```cpp
+quint32 SingleApplication::instanceId()
+```
+
+Returns a unique identifier for the current instance.
+
+---
+
+```cpp
+qint64 SingleApplication::primaryPid()
+```
+
+Returns the process ID (PID) of the primary instance.
+
+### Signals
+
+```cpp
+void SingleApplication::instanceStarted()
+```
+
+Triggered whenever a new instance had been started, except for secondary
+instances if the `Mode::SecondaryNotification` flag is not specified.
+
+---
+
+```cpp
+void SingleApplication::receivedMessage( quint32 instanceId, QByteArray message )
+```
+
+Triggered whenever there is a message received from a secondary instance.
+
+---
+
+### Flags
+
+```cpp
+enum SingleApplication::Mode
+```
+
+*   `Mode::User` - The SingleApplication block should apply user wide. This adds
+    user specific data to the key used for the shared memory and server name.
+    This is the default functionality.
+*   `Mode::System` – The SingleApplication block applies system-wide.
+*   `Mode::SecondaryNotification` – Whether to trigger `instanceStarted()` even
+    whenever secondary instances are started.
+*   `Mode::ExcludeAppPath` – Excludes the application path from the server name
+    (and memory block) hash.
+*   `Mode::ExcludeAppVersion` – Excludes the application version from the server
+    name (and memory block) hash.
+
+*__Note:__ `Mode::SecondaryNotification` only works if set on both the primary
+and the secondary instance.*
+
+*__Note:__ Operating system can restrict the shared memory blocks to the same
+user, in which case the User/System modes will have no effect and the block will
+be user wide.*
+
+---
+
+Versioning
+----------
+
+Each major version introduces either very significant changes or is not
+backwards compatible with the previous version. Minor versions only add
+additional features, bug fixes or performance improvements and are backwards
+compatible with the previous release. See [`CHANGELOG.md`](CHANGELOG.md) for
+more details.
+
+Implementation
+--------------
+
+The library is implemented with a QSharedMemory block which is thread safe and
+guarantees a race condition will not occur. It also uses a QLocalSocket to
+notify the main process that a new instance had been spawned and thus invoke the
+`instanceStarted()` signal and for messaging the primary instance.
+
+Additionally the library can recover from being forcefully killed on *nix
+systems and will reset the memory block given that there are no other
+instances running.
+
+License
+-------
+This library and it's supporting documentation are released under
+`The MIT License (MIT)` with the exception of the Qt calculator examples which
+is distributed under the BSD license.

Added: trunk/SingleApplication/Windows.md
===================================================================
--- trunk/SingleApplication/Windows.md	                        (rev 0)
+++ trunk/SingleApplication/Windows.md	2018-08-15 12:45:55 UTC (rev 5481)
@@ -0,0 +1,46 @@
+Windows Specific Implementations
+================================
+
+Setting the foreground window
+-----------------------------
+
+In the `instanceStarted()` example in the `README` we demonstrated how an
+application can bring it's primary instance window whenever a second copy
+of the application is started.
+
+On Windows the ability to bring the application windows to the foreground is
+restricted, see [`AllowSetForegroundWindow()`][AllowSetForegroundWindow] for more
+details.
+
+The background process (the primary instance) can bring its windows to the
+foreground if it is allowed by the current foreground process (the secondary
+instance). To bypass this `SingleApplication` must be initialized with the
+`allowSecondary` parameter set to `true` and the `options` parameter must
+include `Mode::SecondaryNotification`, See `SingleApplication::Mode` for more
+details.
+
+Here is an example:
+
+```cpp
+if( app.isSecondary() ) {
+    // This API requires LIBS += User32.lib to be added to the project
+    AllowSetForegroundWindow( DWORD( app.getPrimaryPid() ) );
+}
+
+if( app.isPrimary() ) {
+    QObject::connect(
+        &app,
+        &SingleApplication::instanceStarted,
+        this,
+        &App::instanceStarted
+    );
+}
+```
+
+```cpp
+void App::instanceStarted() {
+    QApplication::setActiveWindow( [window/widget to set to the foreground] );
+}
+```
+
+[AllowSetForegroundWindow]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms632668.aspx

Added: trunk/SingleApplication/examples/basic/basic.pro
===================================================================
--- trunk/SingleApplication/examples/basic/basic.pro	                        (rev 0)
+++ trunk/SingleApplication/examples/basic/basic.pro	2018-08-15 12:45:55 UTC (rev 5481)
@@ -0,0 +1,5 @@
+# Single Application implementation
+include(../../singleapplication.pri)
+DEFINES += QAPPLICATION_CLASS=QCoreApplication
+
+SOURCES += main.cpp


Property changes on: trunk/SingleApplication/examples/basic/basic.pro
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/SingleApplication/examples/basic/main.cpp
===================================================================
--- trunk/SingleApplication/examples/basic/main.cpp	                        (rev 0)
+++ trunk/SingleApplication/examples/basic/main.cpp	2018-08-15 12:45:55 UTC (rev 5481)
@@ -0,0 +1,9 @@
+#include <singleapplication.h>
+
+int main(int argc, char *argv[])
+{
+    // Allow secondary instances
+    SingleApplication app( argc, argv );
+
+    return app.exec();
+}


Property changes on: trunk/SingleApplication/examples/basic/main.cpp
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/SingleApplication/examples/calculator/button.cpp
===================================================================
--- trunk/SingleApplication/examples/calculator/button.cpp	                        (rev 0)
+++ trunk/SingleApplication/examples/calculator/button.cpp	2018-08-15 12:45:55 UTC (rev 5481)
@@ -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]

Added: trunk/SingleApplication/examples/calculator/button.h
===================================================================
--- trunk/SingleApplication/examples/calculator/button.h	                        (rev 0)
+++ trunk/SingleApplication/examples/calculator/button.h	2018-08-15 12:45:55 UTC (rev 5481)
@@ -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

Added: trunk/SingleApplication/examples/calculator/calculator.cpp
===================================================================
--- trunk/SingleApplication/examples/calculator/calculator.cpp	                        (rev 0)
+++ trunk/SingleApplication/examples/calculator/calculator.cpp	2018-08-15 12:45:55 UTC (rev 5481)
@@ -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(tr("."), SLOT(pointClicked()));
+    Button *changeSignButton = createButton(tr("\302\261"), SLOT(changeSignClicked()));
+
+    Button *backspaceButton = createButton(tr("Backspace"), SLOT(backspaceClicked()));
+    Button *clearButton = createButton(tr("Clear"), SLOT(clear()));
+    Button *clearAllButton = createButton(tr("Clear All"), SLOT(clearAll()));
+
+    Button *clearMemoryButton = createButton(tr("MC"), SLOT(clearMemory()));
+    Button *readMemoryButton = createButton(tr("MR"), SLOT(readMemory()));
+    Button *setMemoryButton = createButton(tr("MS"), SLOT(setMemory()));
+    Button *addToMemoryButton = createButton(tr("M+"), SLOT(addToMemory()));
+
+    Button *divisionButton = createButton(tr("\303\267"), SLOT(multiplicativeOperatorClicked()));
+    Button *timesButton = createButton(tr("\303\227"), SLOT(multiplicativeOperatorClicked()));
+    Button *minusButton = createButton(tr("-"), SLOT(additiveOperatorClicked()));
+    Button *plusButton = createButton(tr("+"), SLOT(additiveOperatorClicked()));
+
+    Button *squareRootButton = createButton(tr("Sqrt"), SLOT(unaryOperatorClicked()));
+    Button *powerButton = createButton(tr("x\302\262"), SLOT(unaryOperatorClicked()));
+    Button *reciprocalButton = createButton(tr("1/x"), SLOT(unaryOperatorClicked()));
+    Button *equalButton = createButton(tr("="), 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(tr("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 == tr("Sqrt")) {
+        if (operand < 0.0) {
+            abortOperation();
+            return;
+        }
+        result = std::sqrt(operand);
+    } else if (clickedOperator == tr("x\302\262")) {
+        result = std::pow(operand, 2.0);
+    } else if (clickedOperator == tr("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() + tr("."));
+    waitingForOperand = false;
+}
+//! [22]
+
+//! [24]
+void Calculator::changeSignClicked()
+{
+    QString text = display->text();
+    double value = text.toDouble();
+
+    if (value > 0.0) {
+        text.prepend(tr("-"));
+    } 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(tr("####"));
+}
+//! [36]
+
+//! [38]
+bool Calculator::calculate(double rightOperand, const QString &pendingOperator)
+{
+    if (pendingOperator == tr("+")) {
+        sumSoFar += rightOperand;
+    } else if (pendingOperator == tr("-")) {
+        sumSoFar -= rightOperand;
+    } else if (pendingOperator == tr("\303\227")) {
+        factorSoFar *= rightOperand;
+    } else if (pendingOperator == tr("\303\267")) {
+        if (rightOperand == 0.0)
+            return false;
+        factorSoFar /= rightOperand;
+    }
+    return true;
+}
+//! [38]

Added: trunk/SingleApplication/examples/calculator/calculator.h
===================================================================
--- trunk/SingleApplication/examples/calculator/calculator.h	                        (rev 0)
+++ trunk/SingleApplication/examples/calculator/calculator.h	2018-08-15 12:45:55 UTC (rev 5481)
@@ -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

Added: trunk/SingleApplication/examples/calculator/calculator.pro
===================================================================
--- trunk/SingleApplication/examples/calculator/calculator.pro	                        (rev 0)
+++ trunk/SingleApplication/examples/calculator/calculator.pro	2018-08-15 12:45:55 UTC (rev 5481)
@@ -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

Added: trunk/SingleApplication/examples/calculator/main.cpp
===================================================================
--- trunk/SingleApplication/examples/calculator/main.cpp	                        (rev 0)
+++ trunk/SingleApplication/examples/calculator/main.cpp	2018-08-15 12:45:55 UTC (rev 5481)
@@ -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();
+}

Added: trunk/SingleApplication/examples/sending_arguments/main.cpp
===================================================================
--- trunk/SingleApplication/examples/sending_arguments/main.cpp	                        (rev 0)
+++ trunk/SingleApplication/examples/sending_arguments/main.cpp	2018-08-15 12:45:55 UTC (rev 5481)
@@ -0,0 +1,25 @@
+#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() );
+        return 0;
+    } else {
+        QObject::connect(
+            &app,
+            &SingleApplication::receivedMessage,
+            &msgReceiver,
+            &MessageReceiver::receivedMessage
+        );
+    }
+
+    return app.exec();
+}


Property changes on: trunk/SingleApplication/examples/sending_arguments/main.cpp
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/SingleApplication/examples/sending_arguments/messagereceiver.cpp
===================================================================
--- trunk/SingleApplication/examples/sending_arguments/messagereceiver.cpp	                        (rev 0)
+++ trunk/SingleApplication/examples/sending_arguments/messagereceiver.cpp	2018-08-15 12:45:55 UTC (rev 5481)
@@ -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;
+}

Added: trunk/SingleApplication/examples/sending_arguments/messagereceiver.h
===================================================================
--- trunk/SingleApplication/examples/sending_arguments/messagereceiver.h	                        (rev 0)
+++ trunk/SingleApplication/examples/sending_arguments/messagereceiver.h	2018-08-15 12:45:55 UTC (rev 5481)
@@ -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

Added: trunk/SingleApplication/examples/sending_arguments/sending_arguments.pro
===================================================================
--- trunk/SingleApplication/examples/sending_arguments/sending_arguments.pro	                        (rev 0)
+++ trunk/SingleApplication/examples/sending_arguments/sending_arguments.pro	2018-08-15 12:45:55 UTC (rev 5481)
@@ -0,0 +1,9 @@
+# Single Application implementation
+include(../../singleapplication.pri)
+DEFINES += QAPPLICATION_CLASS=QCoreApplication
+
+SOURCES += main.cpp \
+    messagereceiver.cpp
+
+HEADERS += \
+    messagereceiver.h


Property changes on: trunk/SingleApplication/examples/sending_arguments/sending_arguments.pro
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/SingleApplication/singleapplication.cpp
===================================================================
--- trunk/SingleApplication/singleapplication.cpp	                        (rev 0)
+++ trunk/SingleApplication/singleapplication.cpp	2018-08-15 12:45:55 UTC (rev 5481)
@@ -0,0 +1,174 @@
+// The MIT License (MIT)
+//
+// Copyright (c) Itay Grudev 2015 - 2018
+//
+// 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 <QtCore/QTime>
+#include <QtCore/QThread>
+#include <QtCore/QDateTime>
+#include <QtCore/QByteArray>
+#include <QtCore/QSharedMemory>
+
+#include "singleapplication.h"
+#include "singleapplication_p.h"
+
+/**
+ * @brief Constructor. Checks and fires up LocalServer or closes the program
+ * if another instance already exists
+ * @param argc
+ * @param argv
+ * @param {bool} allowSecondaryInstances
+ */
+SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary, Options options, int timeout )
+    : app_t( argc, argv ), d_ptr( new SingleApplicationPrivate( this ) )
+{
+    Q_D(SingleApplication);
+
+    // Store the current mode of the program
+    d->options = options;
+
+    // Generating an application ID used for identifying the shared memory
+    // block and QLocalServer
+    d->genBlockServerName();
+
+#ifdef Q_OS_UNIX
+    // By explicitly attaching it and then deleting it we make sure that the
+    // memory is deleted even after the process has crashed on Unix.
+    d->memory = new QSharedMemory( d->blockServerName );
+    d->memory->attach();
+    delete d->memory;
+#endif
+    // Guarantee thread safe behaviour with a shared memory block.
+    d->memory = new QSharedMemory( d->blockServerName );
+
+    // Create a shared memory block
+    if( d->memory->create( sizeof( InstancesInfo ) ) ) {
+        // Initialize the shared memory block
+        d->memory->lock();
+        d->initializeMemoryBlock();
+        d->memory->unlock();
+    } else {
+        // Attempt to attach to the memory segment
+        if( ! d->memory->attach() ) {
+            qCritical() << "SingleApplication: Unable to attach to shared memory block.";
+            qCritical() << d->memory->errorString();
+            delete d;
+            ::exit( EXIT_FAILURE );
+        }
+    }
+
+    InstancesInfo* inst = static_cast<InstancesInfo*>( d->memory->data() );
+    QTime time;
+    time.start();
+
+    // Make sure the shared memory block is initialised and in consistent state
+    while( true ) {
+        d->memory->lock();
+
+        if( d->blockChecksum() == inst->checksum ) break;
+
+        if( time.elapsed() > 5000 ) {
+            qWarning() << "SingleApplication: Shared memory block has been in an inconsistent state from more than 5s. Assuming primary instance failure.";
+            d->initializeMemoryBlock();
+        }
+
+        d->memory->unlock();
+
+        // Random sleep here limits the probability of a colision between two racing apps
+        qsrand( QDateTime::currentMSecsSinceEpoch() % std::numeric_limits<uint>::max() );
+        QThread::sleep( 8 + static_cast <unsigned long>( static_cast <float>( qrand() ) / RAND_MAX * 10 ) );
+    }
+
+    if( inst->primary == false) {
+        d->startPrimary();
+        d->memory->unlock();
+        return;
+    }
+
+    // Check if another instance can be started
+    if( allowSecondary ) {
+        inst->secondary += 1;
+        inst->checksum = d->blockChecksum();
+        d->instanceNumber = inst->secondary;
+        d->startSecondary();
+        if( d->options & Mode::SecondaryNotification ) {
+            d->connectToPrimary( timeout, SingleApplicationPrivate::SecondaryInstance );
+        }
+        d->memory->unlock();
+        return;
+    }
+
+    d->memory->unlock();
+
+    d->connectToPrimary( timeout, SingleApplicationPrivate::NewInstance );
+
+    delete d;
+
+    ::exit( EXIT_SUCCESS );
+}
+
+/**
+ * @brief Destructor
+ */
+SingleApplication::~SingleApplication()
+{
+    Q_D(SingleApplication);
+    delete d;
+}
+
+bool SingleApplication::isPrimary()
+{
+    Q_D(SingleApplication);
+    return d->server != nullptr;
+}
+
+bool SingleApplication::isSecondary()
+{
+    Q_D(SingleApplication);
+    return d->server == nullptr;
+}
+
+quint32 SingleApplication::instanceId()
+{
+    Q_D(SingleApplication);
+    return d->instanceNumber;
+}
+
+qint64 SingleApplication::primaryPid()
+{
+    Q_D(SingleApplication);
+    return d->primaryPid();
+}
+
+bool SingleApplication::sendMessage( QByteArray message, int timeout )
+{
+    Q_D(SingleApplication);
+
+    // Nobody to connect to
+    if( isPrimary() ) return false;
+
+    // Make sure the socket is connected
+    d->connectToPrimary( timeout,  SingleApplicationPrivate::Reconnect );
+
+    d->socket->write( message );
+    bool dataWritten = d->socket->flush();
+    d->socket->waitForBytesWritten( timeout );
+    return dataWritten;
+}

Added: trunk/SingleApplication/singleapplication.h
===================================================================
--- trunk/SingleApplication/singleapplication.h	                        (rev 0)
+++ trunk/SingleApplication/singleapplication.h	2018-08-15 12:45:55 UTC (rev 5481)
@@ -0,0 +1,135 @@
+// The MIT License (MIT)
+//
+// Copyright (c) Itay Grudev 2015 - 2018
+//
+// 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.
+
+#ifndef SINGLE_APPLICATION_H
+#define SINGLE_APPLICATION_H
+
+#include <QtCore/QtGlobal>
+#include <QtNetwork/QLocalSocket>
+
+#ifndef QAPPLICATION_CLASS
+  #define QAPPLICATION_CLASS QCoreApplication
+#endif
+
+#include QT_STRINGIFY(QAPPLICATION_CLASS)
+
+class SingleApplicationPrivate;
+
+/**
+ * @brief The SingleApplication class handles multipe instances of the same
+ * Application
+ * @see QCoreApplication
+ */
+class SingleApplication : public QAPPLICATION_CLASS
+{
+    Q_OBJECT
+
+    typedef QAPPLICATION_CLASS app_t;
+
+public:
+    /**
+     * @brief Mode of operation of SingleApplication.
+     * Whether the block should be user-wide or system-wide and whether the
+     * primary instance should be notified when a secondary instance had been
+     * started.
+     * @note Operating system can restrict the shared memory blocks to the same
+     * user, in which case the User/System modes will have no effect and the
+     * block will be user wide.
+     * @enum
+     */
+    enum Mode {
+        User                    = 1 << 0,
+        System                  = 1 << 1,
+        SecondaryNotification   = 1 << 2,
+        ExcludeAppVersion       = 1 << 3,
+        ExcludeAppPath          = 1 << 4
+    };
+    Q_DECLARE_FLAGS(Options, Mode)
+
+    /**
+     * @brief Intitializes a SingleApplication instance with argc command line
+     * arguments in argv
+     * @arg {int &} argc - Number of arguments in argv
+     * @arg {const char *[]} argv - Supplied command line arguments
+     * @arg {bool} allowSecondary - Whether to start the instance as secondary
+     * if there is already a primary instance.
+     * @arg {Mode} mode - Whether for the SingleApplication block to be applied
+     * User wide or System wide.
+     * @arg {int} timeout - Timeout to wait in miliseconds.
+     * @note argc and argv may be changed as Qt removes arguments that it
+     * recognizes
+     * @note Mode::SecondaryNotification only works if set on both the primary
+     * instance and the secondary instance.
+     * @note The timeout is just a hint for the maximum time of blocking
+     * operations. It does not guarantee that the SingleApplication
+     * initialisation will be completed in given time, though is a good hint.
+     * 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 );
+    ~SingleApplication();
+
+    /**
+     * @brief Returns if the instance is the primary instance
+     * @returns {bool}
+     */
+    bool isPrimary();
+
+    /**
+     * @brief Returns if the instance is a secondary instance
+     * @returns {bool}
+     */
+    bool isSecondary();
+
+    /**
+     * @brief Returns a unique identifier for the current instance
+     * @returns {qint32}
+     */
+    quint32 instanceId();
+
+    /**
+     * @brief Returns the process ID (PID) of the primary instance
+     * @returns {qint64}
+     */
+    qint64 primaryPid();
+
+    /**
+     * @brief Sends a message to the primary instance. Returns true on success.
+     * @param {int} timeout - Timeout for connecting
+     * @returns {bool}
+     * @note sendMessage() will return false if invoked from the primary
+     * instance.
+     */
+    bool sendMessage( QByteArray message, int timeout = 100 );
+
+Q_SIGNALS:
+    void instanceStarted();
+    void receivedMessage( quint32 instanceId, QByteArray message );
+
+private:
+    SingleApplicationPrivate *d_ptr;
+    Q_DECLARE_PRIVATE(SingleApplication)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(SingleApplication::Options)
+
+#endif // SINGLE_APPLICATION_H

Added: trunk/SingleApplication/singleapplication.pri
===================================================================
--- trunk/SingleApplication/singleapplication.pri	                        (rev 0)
+++ trunk/SingleApplication/singleapplication.pri	2018-08-15 12:45:55 UTC (rev 5481)
@@ -0,0 +1,19 @@
+QT += core network
+CONFIG += c++11
+
+HEADERS += $$PWD/singleapplication.h \
+    $$PWD/singleapplication_p.h
+SOURCES += $$PWD/singleapplication.cpp \
+    $$PWD/singleapplication_p.cpp
+
+INCLUDEPATH += $$PWD
+
+win32 {
+    msvc:LIBS += Advapi32.lib
+    gcc:LIBS += -ladvapi32
+}
+
+DISTFILES += \
+    $$PWD/README.md \
+    $$PWD/CHANGELOG.md \
+    $$PWD/Windows.md

Added: trunk/SingleApplication/singleapplication_p.cpp
===================================================================
--- trunk/SingleApplication/singleapplication_p.cpp	                        (rev 0)
+++ trunk/SingleApplication/singleapplication_p.cpp	2018-08-15 12:45:55 UTC (rev 5481)
@@ -0,0 +1,349 @@
+// The MIT License (MIT)
+//
+// Copyright (c) Itay Grudev 2015 - 2018
+//
+// 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.
+
+//
+//  W A R N I N G !!!
+//  -----------------
+//
+// This file is not part of the SingleApplication API. It is used purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or may even be removed.
+//
+
+#include <cstdlib>
+#include <cstddef>
+
+#include <QtCore/QDir>
+#include <QtCore/QProcess>
+#include <QtCore/QByteArray>
+#include <QtCore/QSemaphore>
+#include <QtCore/QDataStream>
+#include <QtCore/QStandardPaths>
+#include <QtCore/QCryptographicHash>
+#include <QtNetwork/QLocalServer>
+#include <QtNetwork/QLocalSocket>
+
+#include "singleapplication.h"
+#include "singleapplication_p.h"
+
+#ifdef Q_OS_WIN
+    #include <windows.h>
+    #include <lmcons.h>
+#endif
+
+SingleApplicationPrivate::SingleApplicationPrivate( SingleApplication *q_ptr )
+    : q_ptr( q_ptr )
+{
+    server = nullptr;
+    socket = nullptr;
+}
+
+SingleApplicationPrivate::~SingleApplicationPrivate()
+{
+    if( socket != nullptr ) {
+        socket->close();
+        delete socket;
+    }
+
+    memory->lock();
+    InstancesInfo* inst = static_cast<InstancesInfo*>(memory->data());
+    if( server != nullptr ) {
+        server->close();
+        delete server;
+        inst->primary = false;
+        inst->primaryPid = -1;
+        inst->checksum = blockChecksum();
+    }
+    memory->unlock();
+
+    delete memory;
+}
+
+void SingleApplicationPrivate::genBlockServerName()
+{
+    QCryptographicHash appData( QCryptographicHash::Sha256 );
+    appData.addData( "SingleApplication", 17 );
+    appData.addData( SingleApplication::app_t::applicationName().toUtf8() );
+    appData.addData( SingleApplication::app_t::organizationName().toUtf8() );
+    appData.addData( SingleApplication::app_t::organizationDomain().toUtf8() );
+
+    if( ! (options & SingleApplication::Mode::ExcludeAppVersion) ) {
+        appData.addData( SingleApplication::app_t::applicationVersion().toUtf8() );
+    }
+
+    if( ! (options & SingleApplication::Mode::ExcludeAppPath) ) {
+#ifdef Q_OS_WIN
+        appData.addData( SingleApplication::app_t::applicationFilePath().toLower().toUtf8() );
+#else
+        appData.addData( SingleApplication::app_t::applicationFilePath().toUtf8() );
+#endif
+    }
+
+    // User level block requires a user specific data in the hash
+    if( options & SingleApplication::Mode::User ) {
+#ifdef Q_OS_WIN
+        Q_UNUSED(timeout);
+        wchar_t username [ UNLEN + 1 ];
+        // Specifies size of the buffer on input
+        DWORD usernameLength = UNLEN + 1;
+        if( GetUserNameW( username, &usernameLength ) ) {
+            appData.addData( QString::fromWCharArray(username).toUtf8() );
+        } else {
+            appData.addData( QStandardPaths::standardLocations( QStandardPaths::HomeLocation ).join("").toUtf8() );
+        }
+#endif
+#ifdef Q_OS_UNIX
+        QProcess process;
+        process.start( "whoami" );
+        if( process.waitForFinished( 100 ) &&
+            process.exitCode() == QProcess::NormalExit) {
+            appData.addData( process.readLine() );
+        } else {
+            appData.addData(
+                QDir(
+                    QStandardPaths::standardLocations( QStandardPaths::HomeLocation ).first()
+                ).absolutePath().toUtf8()
+            );
+        }
+#endif
+    }
+
+    // Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with
+    // server naming requirements.
+    blockServerName = appData.result().toBase64().replace("/", "_");
+}
+
+void SingleApplicationPrivate::initializeMemoryBlock()
+{
+    InstancesInfo* inst = static_cast<InstancesInfo*>( memory->data() );
+    inst->primary = false;
+    inst->secondary = 0;
+    inst->primaryPid = -1;
+    inst->checksum = blockChecksum();
+}
+
+void SingleApplicationPrivate::startPrimary()
+{
+    Q_Q(SingleApplication);
+
+    // Successful creation means that no main process exists
+    // So we start a QLocalServer to listen for connections
+    QLocalServer::removeServer( blockServerName );
+    server = new QLocalServer();
+
+    // Restrict access to the socket according to the
+    // SingleApplication::Mode::User flag on User level or no restrictions
+    if( options & SingleApplication::Mode::User ) {
+      server->setSocketOptions( QLocalServer::UserAccessOption );
+    } else {
+      server->setSocketOptions( QLocalServer::WorldAccessOption );
+    }
+
+    server->listen( blockServerName );
+    QObject::connect(
+        server,
+        &QLocalServer::newConnection,
+        this,
+        &SingleApplicationPrivate::slotConnectionEstablished
+    );
+
+    // Reset the number of connections
+    InstancesInfo* inst = static_cast <InstancesInfo*>( memory->data() );
+
+    inst->primary = true;
+    inst->primaryPid = q->applicationPid();
+    inst->checksum = blockChecksum();
+
+    instanceNumber = 0;
+}
+
+void SingleApplicationPrivate::startSecondary()
+{
+}
+
+void SingleApplicationPrivate::connectToPrimary( int msecs, ConnectionType connectionType )
+{
+    // Connect to the Local Server of the Primary Instance if not already
+    // connected.
+    if( socket == nullptr ) {
+        socket = new QLocalSocket();
+    }
+
+    // If already connected - we are done;
+    if( socket->state() == QLocalSocket::ConnectedState )
+        return;
+
+    // If not connect
+    if( socket->state() == QLocalSocket::UnconnectedState ||
+        socket->state() == QLocalSocket::ClosingState ) {
+        socket->connectToServer( blockServerName );
+    }
+
+    // Wait for being connected
+    if( socket->state() == QLocalSocket::ConnectingState ) {
+        socket->waitForConnected( msecs );
+    }
+
+    // Initialisation message according to the SingleApplication protocol
+    if( socket->state() == QLocalSocket::ConnectedState ) {
+        // Notify the parent that a new instance had been started;
+        QByteArray initMsg;
+        QDataStream writeStream(&initMsg, QIODevice::WriteOnly);
+        writeStream.setVersion(QDataStream::Qt_5_6);
+        writeStream << blockServerName.toLatin1();
+        writeStream << static_cast<quint8>(connectionType);
+        writeStream << instanceNumber;
+        quint16 checksum = qChecksum(initMsg.constData(), static_cast<quint32>(initMsg.length()));
+        writeStream << checksum;
+
+        // The header indicates the message length that follows
+        QByteArray header;
+        QDataStream headerStream(&header, QIODevice::WriteOnly);
+        headerStream.setVersion(QDataStream::Qt_5_6);
+        headerStream << static_cast <quint64>( initMsg.length() );
+
+        socket->write( header );
+        socket->write( initMsg );
+        socket->flush();
+        socket->waitForBytesWritten( msecs );
+    }
+}
+
+quint16 SingleApplicationPrivate::blockChecksum()
+{
+    return qChecksum(
+       static_cast <const char *>( memory->data() ),
+       offsetof( InstancesInfo, checksum )
+   );
+}
+
+qint64 SingleApplicationPrivate::primaryPid()
+{
+    qint64 pid;
+
+    memory->lock();
+    InstancesInfo* inst = static_cast<InstancesInfo*>( memory->data() );
+    pid = inst->primaryPid;
+    memory->unlock();
+
+    return pid;
+}
+
+/**
+ * @brief Executed when a connection has been made to the LocalServer
+ */
+void SingleApplicationPrivate::slotConnectionEstablished()
+{
+    Q_Q(SingleApplication);
+
+    QLocalSocket *nextConnSocket = server->nextPendingConnection();
+
+    quint32 instanceId = 0;
+    ConnectionType connectionType = InvalidConnection;
+    if( nextConnSocket->waitForReadyRead( 100 ) ) {
+        // read the fields in same order and format as written
+        QDataStream headerStream(nextConnSocket);
+        headerStream.setVersion( QDataStream::Qt_5_6 );
+
+        // Read the header to know the message length
+        quint64 msgLen = 0;
+        headerStream >> msgLen;
+
+        if( msgLen >= sizeof( quint16 ) ) {
+           // Read the message body
+           QByteArray msgBytes = nextConnSocket->read(msgLen);
+           QDataStream readStream(msgBytes);
+           readStream.setVersion( QDataStream::Qt_5_6 );
+
+           // server name
+           QByteArray latin1Name;
+           readStream >> latin1Name;
+
+           // connection type
+           quint8 connType = InvalidConnection;
+           readStream >> connType;
+           connectionType = static_cast <ConnectionType>( connType );
+
+           // instance id
+           readStream >> instanceId;
+
+           // checksum
+           quint16 msgChecksum = 0;
+           readStream >> msgChecksum;
+
+           const quint16 actualChecksum = qChecksum(msgBytes.constData(), static_cast<quint32>(msgBytes.length() - sizeof(quint16)));
+
+           if (readStream.status() != QDataStream::Ok || QLatin1String(latin1Name) != blockServerName || msgChecksum != actualChecksum) {
+             connectionType = InvalidConnection;
+           }
+        }
+    }
+
+    if( connectionType == InvalidConnection ) {
+        nextConnSocket->close();
+        delete nextConnSocket;
+        return;
+    }
+
+    QObject::connect(
+        nextConnSocket,
+        &QLocalSocket::aboutToClose,
+        this,
+        [nextConnSocket, instanceId, this]() {
+            Q_EMIT this->slotClientConnectionClosed( nextConnSocket, instanceId );
+        }
+    );
+
+    QObject::connect(
+        nextConnSocket,
+        &QLocalSocket::readyRead,
+        this,
+        [nextConnSocket, instanceId, this]() {
+            Q_EMIT this->slotDataAvailable( nextConnSocket, instanceId );
+        }
+    );
+
+    if( connectionType == NewInstance || (
+            connectionType == SecondaryInstance &&
+            options & SingleApplication::Mode::SecondaryNotification
+        )
+    ) {
+        Q_EMIT q->instanceStarted();
+    }
+
+    if( nextConnSocket->bytesAvailable() > 0 ) {
+        Q_EMIT this->slotDataAvailable( nextConnSocket, instanceId );
+    }
+}
+
+void SingleApplicationPrivate::slotDataAvailable( QLocalSocket *dataSocket, quint32 instanceId )
+{
+    Q_Q(SingleApplication);
+    Q_EMIT q->receivedMessage( instanceId, dataSocket->readAll() );
+}
+
+void SingleApplicationPrivate::slotClientConnectionClosed( QLocalSocket *closedSocket, quint32 instanceId )
+{
+    if( closedSocket->bytesAvailable() > 0 )
+        Q_EMIT slotDataAvailable( closedSocket, instanceId  );
+    closedSocket->deleteLater();
+}

Added: trunk/SingleApplication/singleapplication_p.h
===================================================================
--- trunk/SingleApplication/singleapplication_p.h	                        (rev 0)
+++ trunk/SingleApplication/singleapplication_p.h	2018-08-15 12:45:55 UTC (rev 5481)
@@ -0,0 +1,83 @@
+// 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.
+
+//
+//  W A R N I N G !!!
+//  -----------------
+//
+// This file is not part of the SingleApplication API. It is used purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or may even be removed.
+//
+
+#ifndef SINGLEAPPLICATION_P_H
+#define SINGLEAPPLICATION_P_H
+
+#include <QtCore/QSharedMemory>
+#include <QtNetwork/QLocalServer>
+#include <QtNetwork/QLocalSocket>
+#include "singleapplication.h"
+
+struct InstancesInfo {
+    bool primary;
+    quint32 secondary;
+    qint64 primaryPid;
+    quint16 checksum;
+};
+
+class SingleApplicationPrivate : public QObject {
+Q_OBJECT
+public:
+    enum ConnectionType : quint8 {
+        InvalidConnection = 0,
+        NewInstance = 1,
+        SecondaryInstance = 2,
+        Reconnect = 3
+    };
+    Q_DECLARE_PUBLIC(SingleApplication)
+
+    SingleApplicationPrivate( SingleApplication *q_ptr );
+     ~SingleApplicationPrivate();
+
+    void genBlockServerName();
+    void initializeMemoryBlock();
+    void startPrimary();
+    void startSecondary();
+    void connectToPrimary(int msecs, ConnectionType connectionType );
+    quint16 blockChecksum();
+    qint64 primaryPid();
+
+    SingleApplication *q_ptr;
+    QSharedMemory *memory;
+    QLocalSocket *socket;
+    QLocalServer *server;
+    quint32 instanceNumber;
+    QString blockServerName;
+    SingleApplication::Options options;
+
+public Q_SLOTS:
+    void slotConnectionEstablished();
+    void slotDataAvailable( QLocalSocket*, quint32 );
+    void slotClientConnectionClosed( QLocalSocket*, quint32 );
+};
+
+#endif // SINGLEAPPLICATION_P_H

Modified: trunk/qelectrotech.pro
===================================================================
--- trunk/qelectrotech.pro	2018-08-13 17:57:33 UTC (rev 5480)
+++ trunk/qelectrotech.pro	2018-08-15 12:45:55 UTC (rev 5481)
@@ -70,6 +70,8 @@
 include(sources/PropertiesEditor/PropertiesEditor.pri)
 include(sources/QetGraphicsItemModeler/QetGraphicsItemModeler.pri)
 include(sources/QPropertyUndoCommand/QPropertyUndoCommand.pri)
+include(SingleApplication/singleapplication.pri)
+DEFINES += QAPPLICATION_CLASS=QApplication
 
 TEMPLATE = app
 DEPENDPATH += .

Modified: trunk/sources/main.cpp
===================================================================
--- trunk/sources/main.cpp	2018-08-13 17:57:33 UTC (rev 5480)
+++ trunk/sources/main.cpp	2018-08-15 12:45:55 UTC (rev 5481)
@@ -16,6 +16,8 @@
 	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
 */
 #include "qetapp.h"
+#include "singleapplication.h"
+#include "qet.h"
 
 /**
  * @brief main
@@ -37,5 +39,21 @@
 #else
     qputenv("QT_DEVICE_PIXEL_RATIO", QByteArray("auto"));
 #endif
-	return(QETApp(argc, argv).exec());
+	
+	SingleApplication app(argc, argv);
+	
+	if (app.isSecondary())
+	{
+		QStringList strl = app.arguments();
+			//Remove the first argument, it's the binary file
+		strl.takeFirst();
+		QString message = "launched-with-args: " + QET::joinWithSpaces(strl);
+		app.sendMessage(message.toUtf8());
+		return 0;
+	}
+	
+	QETApp qetapp;
+	QObject::connect(&app, &SingleApplication::receivedMessage, &qetapp, &QETApp::receiveMessage);
+	
+	return app.exec();
 }

Modified: trunk/sources/qetapp.cpp
===================================================================
--- trunk/sources/qetapp.cpp	2018-08-13 17:57:33 UTC (rev 5480)
+++ trunk/sources/qetapp.cpp	2018-08-15 12:45:55 UTC (rev 5481)
@@ -60,51 +60,29 @@
 TitleBlockTemplate *QETApp::default_titleblock_template_ = nullptr;
 QString QETApp::m_user_common_elements_dir = QString();
 QString QETApp::m_user_custom_elements_dir = QString();
+QETApp *QETApp::m_qetapp = nullptr;
 
 
 /**
-	Constructeur
-	@param argc Nombre d'arguments passes a l'application
-	@param argv Arguments passes a l'application
-*/
-QETApp::QETApp(int &argc, char **argv) :
-	QETSingleApplication(argc, argv, QString("qelectrotech-" + QETApp::userName())),
+ * @brief QETApp::QETApp
+ */
+QETApp::QETApp() :
 	m_splash_screen(nullptr),
 	non_interactive_execution_(false)
 {
+	m_qetapp = this;
 	parseArguments();
 	initConfiguration();
 	initLanguage();
 	QET::Icons::initIcons();
 	initStyle();
-
-	if (!non_interactive_execution_ && isRunning()) {
-		// envoie les arguments a l'instance deja existante
-		non_interactive_execution_ = sendMessage(
-			"launched-with-args: " +
-			QET::joinWithSpaces(QStringList(qet_arguments_.arguments()))
-		);
-	}
-
-	if (non_interactive_execution_) {
-		std::exit(EXIT_SUCCESS);
-	}
-
 	initSplashScreen();
 	initSystemTray();
 
-	// prise en compte des messages des autres instances
-	connect(this, SIGNAL(messageAvailable(QString)), this, SLOT(messageReceived(const QString&)));
-
-	// nettoyage avant de quitter l'application
-	connect(this, SIGNAL(aboutToQuit()), this, SLOT(cleanup()));
-
-	// connexion pour le signalmapper
 	connect(&signal_map, SIGNAL(mapped(QWidget *)), this, SLOT(invertMainWindowVisibility(QWidget *)));
+	qApp->setQuitOnLastWindowClosed(false);
+	connect(qApp, &QApplication::lastWindowClosed, this, &QETApp::checkRemainingWindows);
 
-	setQuitOnLastWindowClosed(false);
-	connect(this, SIGNAL(lastWindowClosed()), this, SLOT(checkRemainingWindows()));
-
 	setSplashScreenStep(tr("Chargement... Initialisation du cache des collections d'éléments", "splash screen caption"));
 	if (!collections_cache_) {
 		QString cache_path = QETApp::configDir() + "/elements_cache.sqlite";
@@ -112,14 +90,16 @@
 		collections_cache_->setLocale(langFromSetting());
 	}
 
-	// on ouvre soit les fichiers passes en parametre soit un nouvel editeur de projet
-	if (qet_arguments_.files().isEmpty()) {
+	if (qet_arguments_.files().isEmpty())
+	{
 		setSplashScreenStep(tr("Chargement... Éditeur de schéma", "splash screen caption"));
 		new QETDiagramEditor();
-	} else {
+	} else
+	{
 		setSplashScreenStep(tr("Chargement... Ouverture des fichiers", "splash screen caption"));
 		openFiles(qet_arguments_);
 	}
+	
 	buildSystemTrayMenu();
 	m_splash_screen -> hide();
 	
@@ -160,8 +140,9 @@
 /**
 	@return l'instance de la QETApp
 */
-QETApp *QETApp::instance() {
-	return(static_cast<QETApp *>(qApp));
+QETApp *QETApp::instance()
+{
+	return m_qetapp;
 }
 
 /**
@@ -176,7 +157,7 @@
 	if (!qtTranslator.load("qt_" + desired_language, qt_l10n_path)) {
 		qtTranslator.load("qt_" + desired_language, languages_path);
 	}
-	installTranslator(&qtTranslator);
+	qApp->installTranslator(&qtTranslator);
 
 	// charge les traductions pour l'application QET
 	if (!qetTranslator.load("qet_" + desired_language, languages_path)) {
@@ -186,7 +167,7 @@
 			qetTranslator.load("qet_en", languages_path);
 		}
 	}
-	installTranslator(&qetTranslator);
+	qApp->installTranslator(&qetTranslator);
 
 	QString ltr_special_string = tr(
 		"LTR",
@@ -211,7 +192,7 @@
 	Switches the application to the provided layout.
 */
 void QETApp::switchLayout(Qt::LayoutDirection direction) {
-	setLayoutDirection(direction);
+	qApp->setLayoutDirection(direction);
 }
 
 /**
@@ -441,26 +422,6 @@
 }
 
 /**
-	@return le nom de l'utilisateur courant
-*/
-QString QETApp::userName() {
-	QProcess * process = new QProcess();
-	QString str;
-#ifndef Q_OS_WIN32
-	// return(QString(getenv("USER")));
-	str = (process->processEnvironment()).value("USER", "UNKNOWN");
-	delete process;
-	return(str);
-#else
-	// return(QString(getenv("USERNAME")));
-	str = (process->processEnvironment()).value("USERNAME", "UNKNOWN");
-	delete process;
-	return(str);
-#endif
-}
-
-
-/**
  * @brief QETApp::commonElementsDir
  * @return the dir path of the common elements collection.
  */
@@ -1015,11 +976,18 @@
 	return(editors);
 }
 
-/**
-	Nettoie certaines choses avant que l'application ne quitte
-*/
-void QETApp::cleanup() {
-	m_qsti -> hide();
+void QETApp::receiveMessage(int instanceId, QByteArray message)
+{
+	Q_UNUSED(instanceId);
+	
+	QString str(message);
+	
+	if (str.startsWith("launched-with-args: "))
+	{
+		QString my_message(str.mid(20));
+		QStringList args_list = QET::splitWithSpaces(my_message);
+		openFiles(QETArguments(args_list));
+	}
 }
 
 /**
@@ -1028,7 +996,7 @@
 */
 template <class T> QList<T *> QETApp::detectWindows() const {
 	QList<T *> windows;
-	foreach(QWidget *widget, topLevelWidgets()) {
+	foreach(QWidget *widget, qApp->topLevelWidgets()) {
 		if (!widget -> isWindow()) continue;
 		if (T *window = qobject_cast<T *>(widget)) {
 			windows << window;
@@ -1118,8 +1086,8 @@
 */
 void QETApp::useSystemPalette(bool use) {
 	if (use) {
-		setPalette(initial_palette_);
-		setStyleSheet(
+		qApp->setPalette(initial_palette_);
+		qApp->setStyleSheet(
 					"QTabBar::tab:!selected { background-color: transparent; }"
 					"QAbstractScrollArea#mdiarea {"
 					"background-color -> setPalette(initial_palette_);"
@@ -1129,7 +1097,7 @@
 		QFile file(configDir() + "style.css");
 		file.open(QFile::ReadOnly);
 		QString styleSheet = QLatin1String(file.readAll());
-		setStyleSheet(styleSheet);
+		qApp->setStyleSheet(styleSheet);
 		file.close();
 	}
 }
@@ -1140,7 +1108,7 @@
 */
 void QETApp::quitQET() {
 	if (closeEveryEditor()) {
-		quit();
+		qApp->quit();
 	}
 }
 
@@ -1158,7 +1126,7 @@
 		QTimer::singleShot(500, this, SLOT(checkRemainingWindows()));
 	} else {
 		if (!diagramEditors().count() && !elementEditors().count()) {
-			quit();
+			qApp->quit();
 		}
 	}
 	sleep = !sleep;
@@ -1165,19 +1133,6 @@
 }
 
 /**
-	Gere les messages recus
-	@param message Message recu
-*/
-void QETApp::messageReceived(const QString &message) {
-	if (message.startsWith("launched-with-args: ")) {
-		QString my_message(message.mid(20));
-		// les arguments sont separes par des espaces non echappes
-		QStringList args_list = QET::splitWithSpaces(my_message);
-		openFiles(QETArguments(args_list));
-	}
-}
-
-/**
 	Ouvre les fichiers passes en arguments
 	@param args Objet contenant des arguments ; les fichiers
 	@see openProjectFiles openElementFiles
@@ -1371,7 +1326,7 @@
 */
 void QETApp::configureQET() {
 	// determine le widget parent a utiliser pour le dialogue
-	QWidget *parent_widget = activeWindow();
+	QWidget *parent_widget = qApp->activeWindow();
 
 	// cree le dialogue
 	ConfigDialog cd;
@@ -1399,7 +1354,7 @@
  */
 void QETApp::aboutQET()
 {
-	AboutQET aq(activeWindow());
+	AboutQET aq(qApp->activeWindow());
 	
 #ifdef Q_OS_MACOS
 	aq.setWindowFlags(Qt::Sheet);
@@ -1413,7 +1368,7 @@
 */
 QList<QWidget *> QETApp::floatingToolbarsAndDocksForMainWindow(QMainWindow *window) const {
 	QList<QWidget *> widgets;
-	foreach(QWidget *qw, topLevelWidgets()) {
+	foreach(QWidget *qw, qApp->topLevelWidgets()) {
 		if (!qw -> isWindow()) continue;
 		if (qobject_cast<QToolBar *>(qw) || qobject_cast<QDockWidget *>(qw)) {
 			if (qw -> parent() == window) widgets << qw;
@@ -1436,7 +1391,7 @@
 */
 void QETApp::parseArguments() {
 	// recupere les arguments
-	QList<QString> arguments_list(arguments());
+	QList<QString> arguments_list(qApp->arguments());
 
 	// enleve le premier argument : il s'agit du fichier binaire
 	arguments_list.takeFirst();
@@ -1499,7 +1454,7 @@
 	if (!message.isEmpty()) {
 		m_splash_screen -> showMessage(message, Qt::AlignBottom | Qt::AlignLeft);
 	}
-	processEvents();
+	qApp->processEvents();
 }
 
 /**
@@ -1514,7 +1469,7 @@
  * Setup the gui style
  */
 void QETApp::initStyle() {
-	initial_palette_ = palette();
+	initial_palette_ = qApp->palette();
 
 	//Apply or not the system style
 	QSettings settings;
@@ -1823,7 +1778,7 @@
 */
 void QETApp::printHelp() {
 	QString help(
-		tr("Usage : ") + QFileInfo(applicationFilePath()).fileName() + tr(" [options] [fichier]...\n\n") +
+		tr("Usage : ") + QFileInfo(qApp->applicationFilePath()).fileName() + tr(" [options] [fichier]...\n\n") +
 		tr("QElectroTech, une application de réalisation de schémas électriques.\n\n"
 		"Options disponibles : \n"
 		"  --help                        Afficher l'aide sur les options\n"

Modified: trunk/sources/qetapp.h
===================================================================
--- trunk/sources/qetapp.h	2018-08-13 17:57:33 UTC (rev 5480)
+++ trunk/sources/qetapp.h	2018-08-15 12:45:55 UTC (rev 5481)
@@ -21,8 +21,8 @@
 #include <QTranslator>
 #include <QSystemTrayIcon>
 #include <QPalette>
+#include <QByteArray>
 
-#include "qetsingleapplication.h"
 #include "elementslocation.h"
 #include "templatelocation.h"
 #include "qetarguments.h"
@@ -50,12 +50,12 @@
 /**
 	This class represents the QElectroTech application.
 */
-class QETApp : public QETSingleApplication
+class QETApp : public QObject
 {
 	Q_OBJECT
 		// constructors, destructor
 	public:
-		QETApp(int &, char **);
+		QETApp();
 		~QETApp() override;
 	
 	private:
@@ -81,7 +81,6 @@
 		static QList<TitleBlockTemplatesCollection *> availableTitleBlockTemplatesCollections();
 		static TitleBlockTemplatesCollection *titleBlockTemplatesCollection(const QString &);
 		
-		static QString userName();
 		static QString commonElementsDir();
 		static QString customElementsDir();
 		static QString commonElementsDirN();
@@ -148,6 +147,7 @@
 	
 		// attributes
 	private:
+		static QETApp *m_qetapp;
 		QTranslator qtTranslator;
 		QTranslator qetTranslator;
 		QSystemTrayIcon *m_qsti;
@@ -207,7 +207,6 @@
 		void useSystemPalette(bool);
 		void quitQET();
 		void checkRemainingWindows();
-		void messageReceived(const QString &);
 		void openFiles(const QETArguments &);
 		void openProjectFiles(const QStringList &);
 		void openElementFiles(const QStringList &);
@@ -217,10 +216,8 @@
 		void openTitleBlockTemplateFiles(const QStringList &);
 		void configureQET();
 		void aboutQET();
+		void receiveMessage(int instanceId, QByteArray message);
 	
-	private slots:
-		void cleanup();
-	
 	private:
 		template <class T> QList<T *> detectWindows() const;
 		template <class T> void setMainWindowsVisible(bool);

Deleted: trunk/sources/qetsingleapplication.cpp
===================================================================
--- trunk/sources/qetsingleapplication.cpp	2018-08-13 17:57:33 UTC (rev 5480)
+++ trunk/sources/qetsingleapplication.cpp	2018-08-15 12:45:55 UTC (rev 5481)
@@ -1,120 +0,0 @@
-/*
-	Copyright 2006-2017 The QElectroTech Team
-	This file is part of QElectroTech.
-	
-	QElectroTech is free software: you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation, either version 2 of the License, or
-	(at your option) any later version.
-	
-	QElectroTech is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTAvBILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-	
-	You should have received a copy of the GNU General Public License
-	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
-*/
-#include "qetsingleapplication.h"
-#include <QLocalSocket>
-
-const int QETSingleApplication::timeout_ = 10000;
-
-/**
-	Constructeur
-	@param argc Nombre d'arguments passes au programme par le systeme
-	@param argv Tableau des arguments passes au programme par le systeme
-	@param unique_key Cle unique
-*/
-QETSingleApplication::QETSingleApplication(int &argc, char **argv, const QString& unique_key) :
-	QApplication(argc, argv),
-	unique_key_(unique_key)
-{
-	// verifie s'il y a un segment de memoire partage correspondant a la cle unique
-#if defined (Q_OS_OS2)
-#define QT_NO_SHAREDMEMORY
-	{
-#else
-	shared_memory_.setKey(unique_key_);
-	if (shared_memory_.attach()) {
-		// oui : l'application est deja en cours d'execution
-		is_running_ = true;
-	} else {
-		// non : il s'agit du premier demarrage de l'application pour cette cle unique
-		is_running_ = false;
-		
-		// initialisation du segment de memoire partage
-		if (!shared_memory_.create(1)) {
-			qDebug() << "QETSingleApplication::QETSingleApplication() : Impossible de créer l'instance unique" << qPrintable(unique_key_);
-			return;
-		}
-#endif
-		// initialisation d'un serveur local pour recevoir les messages des autres instances
-		local_server_ = new QLocalServer(this);
-		connect(local_server_, SIGNAL(newConnection()), this, SLOT(receiveMessage()));
-		// la cle unique est egalement utilise pour le serveur
-		local_server_ -> listen(unique_key_);
-	}
-}
-
-/**
-	Destructeur
-*/
-QETSingleApplication::~QETSingleApplication() {
-}
-
-/**
-	Slot gerant la reception des messages.
-	Lorsque l'application recoit un message, ce slot emet le signal
-	messageAvailable avec le message recu.
-*/
-void QETSingleApplication::receiveMessage() {
-	QLocalSocket *local_socket = local_server_ -> nextPendingConnection();
-	if (!local_socket -> waitForReadyRead(timeout_)) {
-		qDebug() << "QETSingleApplication::receiveMessage() :" << qPrintable(local_socket -> errorString()) << "(" << qPrintable(unique_key_) << ")";
-		return;
-	}
-	QByteArray byteArray = local_socket -> readAll();
-	QString message = QString::fromUtf8(byteArray.constData());
-	emit(messageAvailable(message));
-	local_socket -> disconnectFromServer();
-}
-
-/**
-	@return true si l'application est deja en cours d'execution
-*/
-bool QETSingleApplication::isRunning() {
-	return(is_running_);
-}
-
-/**
-	Envoie un message a l'application. Si celle-ci n'est pas en cours
-	d'execution, cette methode ne fait rien.
-	@param message Message a transmettre a l'application
-	@return true si le message a ete tranmis, false sinon
-*/
-bool QETSingleApplication::sendMessage(const QString &message) {
-	// l'application doit etre en cours d'execution
-	if (!is_running_) {
-		return(false);
-	}
-	
-	// se connecte a l'application, avec gestion du timeout
-	QLocalSocket local_socket(this);
-	local_socket.connectToServer(unique_key_, QIODevice::WriteOnly);
-	if (!local_socket.waitForConnected(timeout_)) {
-		qDebug() << "QETSingleApplication::sendMessage() :" << qPrintable(local_socket.errorString()) << "(" << qPrintable(unique_key_) << ")";
-		return(false);
-	}
-	
-	// envoi du message, avec gestion du timeout
-	local_socket.write(message.toUtf8());
-	if (!local_socket.waitForBytesWritten(timeout_)) {
-		qDebug() << "QETSingleApplication::sendMessage() :" << qPrintable(local_socket.errorString()) << "(" << qPrintable(unique_key_) << ")";
-		return(false);
-	}
-	
-	// deconnexion
-	local_socket.disconnectFromServer();
-	return(true);
-}

Deleted: trunk/sources/qetsingleapplication.h
===================================================================
--- trunk/sources/qetsingleapplication.h	2018-08-13 17:57:33 UTC (rev 5480)
+++ trunk/sources/qetsingleapplication.h	2018-08-15 12:45:55 UTC (rev 5481)
@@ -1,60 +0,0 @@
-/*
-	Copyright 2006-2017 The QElectroTech Team
-	This file is part of QElectroTech.
-	
-	QElectroTech is free software: you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation, either version 2 of the License, or
-	(at your option) any later version.
-	
-	QElectroTech is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-	
-	You should have received a copy of the GNU General Public License
-	along with QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
-*/
-#ifndef QET_SINGLE_APPLICATION_H
-#define QET_SINGLE_APPLICATION_H
-#include <QApplication>
-#include <QSharedMemory>
-#include <QLocalServer>
-/**
-	This class represents a Qt Application executing only a single instance
-	depending on a unique string key.
-*/
-class QETSingleApplication : public QApplication {
-	Q_OBJECT
-	// constructors, destructor
-	public:
-	QETSingleApplication(int &, char **, const QString&);
-	~QETSingleApplication() override;
-	
-	private:
-	QETSingleApplication(const QETSingleApplication &);
-	
-	// methods
-	public:
-	bool isRunning();
-	bool sendMessage(const QString &);
-	
-	public slots:
-	void receiveMessage();
-	
-	signals:
-	void messageAvailable(QString);
-	
-	// attributes
-	private:
-	bool is_running_;
-	QString unique_key_;
-	#if defined (Q_OS_OS2)
-	#define QT_NO_SHAREDMEMORY
-	#else
-	QSharedMemory shared_memory_;
-	#endif
-	QLocalServer *local_server_;
-	static const int timeout_;
-};
-#endif


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/