diff options
| -rw-r--r-- | CHANGELOG.md | 9 | ||||
| -rw-r--r-- | README.md | 15 | ||||
| -rw-r--r-- | Windows.md | 46 | ||||
| -rw-r--r-- | singleapplication.cpp | 32 | ||||
| -rw-r--r-- | singleapplication.h | 8 | ||||
| -rw-r--r-- | singleapplication.pri | 5 | ||||
| -rw-r--r-- | singleapplication_p.h | 2 | 
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__  --------- @@ -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(); | 
