aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorItay Grudev <itay-grudev@users.noreply.github.com>2017-10-02 12:17:41 +0100
committerGitHub <noreply@github.com>2017-10-02 12:17:41 +0100
commit4f0365107283ce321da713baeab4d2aad0456baf (patch)
tree09caa4a6b735885355b47d1312375fccdd168d3d
parentFixed typo in the CHANGELOG.md (diff)
downloadsingleapplication-4f0365107283ce321da713baeab4d2aad0456baf.tar.xz
Primary PID support (#36)v3.0.9
* Added the ability to bring the primary application window to the foreground on Windows systems by adding an option flag. THis option can only be used in Windows development and in applications derived from QApplication with a QMainWindow object. Because the primary application needs to be instructed to go to the foreground, the option SecondaryNotification must also be set to use this functionality * Changed the ability to bring the primary application window to the front as discussed in itay-grudev/SingleApplication#31. Now the process ID of the primary application get stored and is accessible for other instances of the application. It is to the developer to bring the applications windows to the front. For convenience the accompanying readme now contains a paragraph with example of how to do this on Windows systems. * v3.0.9 Added SingleApplicationPrivate::primaryPid()
-rw-r--r--CHANGELOG.md9
-rw-r--r--README.md15
-rw-r--r--Windows.md46
-rw-r--r--singleapplication.cpp32
-rw-r--r--singleapplication.h8
-rw-r--r--singleapplication.pri5
-rw-r--r--singleapplication_p.h2
7 files changed, 111 insertions, 6 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 90ef30b..7bde394 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,15 @@
Changelog
=========
+__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__
---------
diff --git a/README.md b/README.md
index e003ab4..82e7a5b 100644
--- a/README.md
+++ b/README.md
@@ -80,6 +80,11 @@ 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
-------------------
@@ -177,7 +182,15 @@ Returns if the instance is a secondary instance.
quint32 SingleApplication::instanceId()
```
-Returns a unique identifier for the current instance
+Returns a unique identifier for the current instance.
+
+---
+
+```cpp
+qint64 SingleApplication::primaryPid()
+```
+
+Returns the process ID (PID) of the primary instance.
### Signals
diff --git a/Windows.md b/Windows.md
new file mode 100644
index 0000000..48b0748
--- /dev/null
+++ b/Windows.md
@@ -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
diff --git a/singleapplication.cpp b/singleapplication.cpp
index 1ab69fa..8711cb1 100644
--- a/singleapplication.cpp
+++ b/singleapplication.cpp
@@ -45,6 +45,7 @@
#include "singleapplication.h"
#include "singleapplication_p.h"
+
static const char NewInstance = 'N';
static const char SecondaryInstance = 'S';
static const char Reconnect = 'R';
@@ -61,14 +62,17 @@ SingleApplicationPrivate::~SingleApplicationPrivate()
socket->close();
delete socket;
}
+
memory->lock();
InstancesInfo* inst = (InstancesInfo*)memory->data();
if( server != nullptr ) {
server->close();
delete server;
inst->primary = false;
+ inst->primaryPid = -1;
}
memory->unlock();
+
delete memory;
}
@@ -128,6 +132,8 @@ void SingleApplicationPrivate::genBlockServerName( int timeout )
void SingleApplicationPrivate::startPrimary( bool resetMemory )
{
+ Q_Q(SingleApplication);
+
#ifdef Q_OS_UNIX
// Handle any further termination signals to ensure the
// QSharedMemory block is deleted even if the process crashes
@@ -158,13 +164,13 @@ void SingleApplicationPrivate::startPrimary( bool resetMemory )
memory->lock();
InstancesInfo* inst = (InstancesInfo*)memory->data();
- if( resetMemory ){
- inst->primary = true;
+ if( resetMemory ) {
inst->secondary = 0;
- } else {
- inst->primary = true;
}
+ inst->primary = true;
+ inst->primaryPid = q->applicationPid();
+
memory->unlock();
instanceNumber = 0;
@@ -217,6 +223,18 @@ void SingleApplicationPrivate::connectToPrimary( int msecs, char connectionType
}
}
+qint64 SingleApplicationPrivate::primaryPid()
+{
+ qint64 pid;
+
+ memory->lock();
+ InstancesInfo* inst = (InstancesInfo*)memory->data();
+ pid = inst->primaryPid;
+ memory->unlock();
+
+ return pid;
+}
+
#ifdef Q_OS_UNIX
void SingleApplicationPrivate::crashHandler()
{
@@ -433,6 +451,12 @@ quint32 SingleApplication::instanceId()
return d->instanceNumber;
}
+qint64 SingleApplication::primaryPid()
+{
+ Q_D(SingleApplication);
+ return d->primaryPid();
+}
+
bool SingleApplication::sendMessage( QByteArray message, int timeout )
{
Q_D(SingleApplication);
diff --git a/singleapplication.h b/singleapplication.h
index 93447f4..33a9898 100644
--- a/singleapplication.h
+++ b/singleapplication.h
@@ -102,11 +102,17 @@ public:
/**
* @brief Returns a unique identifier for the current instance
- * @returns {int}
+ * @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}
diff --git a/singleapplication.pri b/singleapplication.pri
index cd3dd35..a82ff28 100644
--- a/singleapplication.pri
+++ b/singleapplication.pri
@@ -11,3 +11,8 @@ win32 {
msvc:LIBS += Advapi32.lib
gcc:LIBS += -lAdvapi32
}
+
+DISTFILES += \
+ $$PWD/README.md \
+ $$PWD/CHANGELOG.md \
+ $$PWD/Windows.md
diff --git a/singleapplication_p.h b/singleapplication_p.h
index 833e731..856b33d 100644
--- a/singleapplication_p.h
+++ b/singleapplication_p.h
@@ -40,6 +40,7 @@
struct InstancesInfo {
bool primary;
quint32 secondary;
+ qint64 primaryPid;
};
class SingleApplicationPrivate : public QObject {
@@ -54,6 +55,7 @@ public:
void startPrimary( bool resetMemory );
void startSecondary();
void connectToPrimary( int msecs, char connectionType );
+ qint64 primaryPid();
#ifdef Q_OS_UNIX
void crashHandler();