358 lines
12 KiB
C++
358 lines
12 KiB
C++
/****************************************************************************
|
||
**
|
||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies)
|
||
** 2020 KylinSoft Co., Ltd.
|
||
** Contact: http://www.qt-project.org/legal
|
||
**
|
||
**
|
||
** This file is part of the Qt Solutions component.
|
||
**
|
||
** $QT_BEGIN_LICENSE:BSD$
|
||
** 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 Digia Plc and its Subsidiary(-ies) 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 "qt-single-application.h"
|
||
#include "qt-local-peer.h"
|
||
#include <QWidget>
|
||
#include <QDesktopWidget>
|
||
#include <QDBusConnection>
|
||
#include <QDBusInterface>
|
||
#include <QDBusReply>
|
||
#include "mainwindow.h"
|
||
|
||
|
||
/*!
|
||
\class QtSingleApplication qtsingleapplication.h
|
||
\brief The QtSingleApplication class provides an API to detect and
|
||
communicate with running instances of an application.
|
||
|
||
This class allows you to create applications where only one
|
||
instance should be running at a time. I.e., if the user tries to
|
||
launch another instance, the already running instance will be
|
||
activated instead. Another usecase is a client-server system,
|
||
where the first started instance will assume the role of server,
|
||
and the later instances will act as clients of that server.
|
||
|
||
By default, the full path of the executable file is used to
|
||
determine whether two processes are instances of the same
|
||
application. You can also provide an explicit identifier string
|
||
that will be compared instead.
|
||
|
||
The application should create the QtSingleApplication object early
|
||
in the startup phase, and call isRunning() to find out if another
|
||
instance of this application is already running. If isRunning()
|
||
returns false, it means that no other instance is running, and
|
||
this instance has assumed the role as the running instance. In
|
||
this case, the application should continue with the initialization
|
||
of the application user interface before entering the event loop
|
||
with exec(), as normal.
|
||
|
||
The messageReceived() signal will be emitted when the running
|
||
application receives messages from another instance of the same
|
||
application. When a message is received it might be helpful to the
|
||
user to raise the application so that it becomes visible. To
|
||
facilitate this, QtSingleApplication provides the
|
||
setActivationWindow() function and the activateWindow() slot.
|
||
|
||
If isRunning() returns true, another instance is already
|
||
running. It may be alerted to the fact that another instance has
|
||
started by using the sendMessage() function. Also data such as
|
||
startup parameters (e.g. the name of the file the user wanted this
|
||
new instance to open) can be passed to the running instance with
|
||
this function. Then, the application should terminate (or enter
|
||
client mode).
|
||
|
||
If isRunning() returns true, but sendMessage() fails, that is an
|
||
indication that the running instance is frozen.
|
||
|
||
Here's an example that shows how to convert an existing
|
||
application to use QtSingleApplication. It is very simple and does
|
||
not make use of all QtSingleApplication's functionality (see the
|
||
examples for that).
|
||
|
||
\code
|
||
// Original
|
||
int main(int argc, char **argv)
|
||
{
|
||
QApplication app(argc, argv);
|
||
|
||
MyMainWidget mmw;
|
||
mmw.show();
|
||
return app.exec();
|
||
}
|
||
|
||
// Single instance
|
||
int main(int argc, char **argv)
|
||
{
|
||
QtSingleApplication app(argc, argv);
|
||
|
||
if (app.isRunning())
|
||
return !app.sendMessage(someDataString);
|
||
|
||
MyMainWidget mmw;
|
||
app.setActivationWindow(&mmw);
|
||
mmw.show();
|
||
return app.exec();
|
||
}
|
||
\endcode
|
||
|
||
Once this QtSingleApplication instance is destroyed (normally when
|
||
the process exits or crashes), when the user next attempts to run the
|
||
application this instance will not, of course, be encountered. The
|
||
next instance to call isRunning() or sendMessage() will assume the
|
||
role as the new running instance.
|
||
|
||
For console (non-GUI) applications, QtSingleCoreApplication may be
|
||
used instead of this class, to avoid the dependency on the QtGui
|
||
library.
|
||
|
||
\sa QtSingleCoreApplication
|
||
*/
|
||
|
||
|
||
void QtSingleApplication::sysInit(const QString &appId) {
|
||
actWin = 0;
|
||
peer = new QtLocalPeer(this, appId);
|
||
// connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
|
||
connect(peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::messageReceived);
|
||
}
|
||
|
||
|
||
/*!
|
||
Creates a QtSingleApplication object. The application identifier
|
||
will be QCoreApplication::applicationFilePath(). \a argc, \a
|
||
argv, and \a GUIenabled are passed on to the QAppliation constructor.
|
||
|
||
If you are creating a console application (i.e. setting \a
|
||
GUIenabled to false), you may consider using
|
||
QtSingleCoreApplication instead.
|
||
*/
|
||
|
||
QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled)
|
||
: QApplication(argc, argv, GUIenabled) {
|
||
sysInit();
|
||
}
|
||
|
||
|
||
/*!
|
||
Creates a QtSingleApplication object with the application
|
||
identifier \a appId. \a argc and \a argv are passed on to the
|
||
QAppliation constructor.
|
||
*/
|
||
|
||
QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv)
|
||
: QApplication(argc, argv) {
|
||
sysInit(appId);
|
||
}
|
||
|
||
#if QT_VERSION < 0x050000
|
||
|
||
/*!
|
||
Creates a QtSingleApplication object. The application identifier
|
||
will be QCoreApplication::applicationFilePath(). \a argc, \a
|
||
argv, and \a type are passed on to the QAppliation constructor.
|
||
*/
|
||
QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type)
|
||
: QApplication(argc, argv, type) {
|
||
sysInit();
|
||
}
|
||
|
||
|
||
# if defined(Q_WS_X11)
|
||
/*!
|
||
Special constructor for X11, ref. the documentation of
|
||
QApplication's corresponding constructor. The application identifier
|
||
will be QCoreApplication::applicationFilePath(). \a dpy, \a visual,
|
||
and \a cmap are passed on to the QApplication constructor.
|
||
*/
|
||
QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE cmap)
|
||
: QApplication(dpy, visual, cmap) {
|
||
sysInit();
|
||
}
|
||
|
||
/*!
|
||
Special constructor for X11, ref. the documentation of
|
||
QApplication's corresponding constructor. The application identifier
|
||
will be QCoreApplication::applicationFilePath(). \a dpy, \a argc, \a
|
||
argv, \a visual, and \a cmap are passed on to the QApplication
|
||
constructor.
|
||
*/
|
||
QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
|
||
: QApplication(dpy, argc, argv, visual, cmap) {
|
||
sysInit();
|
||
}
|
||
|
||
/*!
|
||
Special constructor for X11, ref. the documentation of
|
||
QApplication's corresponding constructor. The application identifier
|
||
will be \a appId. \a dpy, \a argc, \a
|
||
argv, \a visual, and \a cmap are passed on to the QApplication
|
||
constructor.
|
||
*/
|
||
QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
|
||
: QApplication(dpy, argc, argv, visual, cmap) {
|
||
sysInit(appId);
|
||
}
|
||
# endif // Q_WS_X11
|
||
#endif // QT_VERSION < 0x050000
|
||
|
||
|
||
/*!
|
||
Returns true if another instance of this application is running;
|
||
otherwise false.
|
||
|
||
This function does not find instances of this application that are
|
||
being run by a different user (on Windows: that are running in
|
||
another session).
|
||
|
||
\sa sendMessage()
|
||
*/
|
||
|
||
bool QtSingleApplication::isRunning() {
|
||
return peer->isClient();
|
||
}
|
||
|
||
|
||
/*!
|
||
Tries to send the text \a message to the currently running
|
||
instance. The QtSingleApplication object in the running instance
|
||
will emit the messageReceived() signal when it receives the
|
||
message.
|
||
|
||
This function returns true if the message has been sent to, and
|
||
processed by, the current instance. If there is no instance
|
||
currently running, or if the running instance fails to process the
|
||
message within \a timeout milliseconds, this function return false.
|
||
|
||
\sa isRunning(), messageReceived()
|
||
*/
|
||
bool QtSingleApplication::sendMessage(const QString &message, int timeout) {
|
||
return peer->sendMessage(message, timeout);
|
||
}
|
||
|
||
|
||
/*!
|
||
Returns the application identifier. Two processes with the same
|
||
identifier will be regarded as instances of the same application.
|
||
*/
|
||
QString QtSingleApplication::id() const {
|
||
return peer->applicationId();
|
||
}
|
||
|
||
|
||
/*!
|
||
Sets the activation window of this application to \a aw. The
|
||
activation window is the widget that will be activated by
|
||
activateWindow(). This is typically the application's main window.
|
||
|
||
If \a activateOnMessage is true (the default), the window will be
|
||
activated automatically every time a message is received, just prior
|
||
to the messageReceived() signal being emitted.
|
||
|
||
\sa activateWindow(), messageReceived()
|
||
*/
|
||
|
||
void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage) {
|
||
actWin = aw;
|
||
//目前不需要用到此处的置顶方法,故此信号槽暂时注释掉,若后续需要根据新起进程传递的信号执行部分操作时可以把这里放开
|
||
// if (activateOnMessage)
|
||
// connect(peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow);
|
||
// else
|
||
// disconnect(peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow);
|
||
}
|
||
|
||
|
||
/*!
|
||
Returns the applications activation window if one has been set by
|
||
calling setActivationWindow(), otherwise returns 0.
|
||
|
||
\sa setActivationWindow()
|
||
*/
|
||
QWidget* QtSingleApplication::activationWindow() const {
|
||
return actWin;
|
||
}
|
||
|
||
|
||
/*!
|
||
De-minimizes, raises, and activates this application's activation window.
|
||
This function does nothing if no activation window has been set.
|
||
|
||
This is a convenience function to show the user that this
|
||
application instance has been activated when he has tried to start
|
||
another instance.
|
||
|
||
This function should typically be called in response to the
|
||
messageReceived() signal. By default, that will happen
|
||
automatically, if an activation window has been set.
|
||
|
||
\sa setActivationWindow(), messageReceived(), initialize()
|
||
*/
|
||
void QtSingleApplication::activateWindow() {
|
||
//单例置顶策略,由于bootOptionsFilter in mainwindow自带置顶策略,故注掉此处
|
||
// if (actWin) {
|
||
// if(this->applicationState() & Qt::ApplicationInactive)
|
||
// {
|
||
// MainWindow* w=qobject_cast<MainWindow*>(actWin);
|
||
//// w->loadMainWindow();
|
||
// w->clearSearchResult();
|
||
// actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized);
|
||
// actWin->raise();
|
||
// actWin->showNormal();
|
||
// actWin->activateWindow();
|
||
// }
|
||
// else {
|
||
// actWin->setWindowState(actWin->windowState() & Qt::WindowMinimized);
|
||
// actWin->hide();
|
||
// }
|
||
|
||
// }
|
||
}
|
||
|
||
|
||
/*!
|
||
\fn void QtSingleApplication::messageReceived(const QString& message)
|
||
|
||
This signal is emitted when the current instance receives a \a
|
||
message from another instance of this application.
|
||
|
||
\sa sendMessage(), setActivationWindow(), activateWindow()
|
||
*/
|
||
|
||
|
||
/*!
|
||
\fn void QtSingleApplication::initialize(bool dummy = true)
|
||
|
||
\obsolete
|
||
*/
|