aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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();