mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-23 18:32:49 +00:00
kdeui: do not fork from KUniqueApplication
simplifies startup notification for example, external applications that pass the "nofork" argument may fail (not uncommon to be passed to konsole) Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
parent
0220b5bd85
commit
cd8ab8d93e
5 changed files with 214 additions and 430 deletions
|
@ -157,9 +157,6 @@ class KAboutData;
|
|||
* // Register the supported options
|
||||
* KCmdLineArgs::addCmdLineOptions( options );
|
||||
*
|
||||
* // Add options from other components
|
||||
* KUniqueApplication::addCmdLineOptions();
|
||||
*
|
||||
* ....
|
||||
*
|
||||
* // Create application object without passing 'argc' and 'argv' again.
|
||||
|
|
|
@ -17,321 +17,134 @@
|
|||
Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "kuniqueapplication.h"
|
||||
#include "kuniqueapplication_p.h"
|
||||
#include "kmainwindow.h"
|
||||
#include "kcmdlineargs.h"
|
||||
#include "kstandarddirs.h"
|
||||
#include "kaboutdata.h"
|
||||
#include "kconfiggroup.h"
|
||||
#include "kwindowsystem.h"
|
||||
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtDBus/QtDBus>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
#if defined Q_WS_X11
|
||||
#include <kstartupinfo.h>
|
||||
#endif
|
||||
|
||||
/* I don't know why, but I end up with complaints about
|
||||
a forward-declaration of QWidget in the activeWidow()->show
|
||||
call below on Qt/Mac if I don't include this here... */
|
||||
#include <QWidget>
|
||||
|
||||
#include <kconfig.h>
|
||||
#include "kconfig.h"
|
||||
#include "kstartupinfo.h"
|
||||
#include "kdebug.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QTimer>
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusConnectionInterface>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if defined Q_WS_X11
|
||||
#include <netwm.h>
|
||||
#include <X11/Xlib.h>
|
||||
#define DISPLAY "DISPLAY"
|
||||
#else
|
||||
# ifdef Q_WS_QWS
|
||||
# define DISPLAY "QWS_DISPLAY"
|
||||
# else
|
||||
# define DISPLAY "DISPLAY"
|
||||
# endif
|
||||
# include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
|
||||
bool KUniqueApplication::Private::s_nofork = false;
|
||||
bool KUniqueApplication::Private::s_multipleInstances = false;
|
||||
bool s_kuniqueapplication_startCalled = false;
|
||||
|
||||
void
|
||||
KUniqueApplication::addCmdLineOptions()
|
||||
bool KUniqueApplication::start(StartFlags flags)
|
||||
{
|
||||
KCmdLineOptions kunique_options;
|
||||
kunique_options.add("nofork", ki18n("Do not run in the background."));
|
||||
KCmdLineArgs::addCmdLineOptions(kunique_options, KLocalizedString(), "kuniqueapp", "kde");
|
||||
}
|
||||
if (s_kuniqueapplication_startCalled) {
|
||||
return true;
|
||||
}
|
||||
s_kuniqueapplication_startCalled = true;
|
||||
|
||||
QString appName = KCmdLineArgs::aboutData()->appName();
|
||||
const QStringList parts = KCmdLineArgs::aboutData()->organizationDomain().split(QLatin1Char('.'), QString::SkipEmptyParts);
|
||||
if (parts.isEmpty()) {
|
||||
appName.prepend(QLatin1String("local."));
|
||||
} else {
|
||||
foreach (const QString &s, parts) {
|
||||
appName.prepend(QLatin1Char('.'));
|
||||
appName.prepend(s);
|
||||
}
|
||||
}
|
||||
|
||||
static QDBusConnectionInterface *tryToInitDBusConnection()
|
||||
{
|
||||
// Check the D-Bus connection health
|
||||
QDBusConnectionInterface* dbusService = 0;
|
||||
QDBusConnectionInterface* dbusService = nullptr;
|
||||
QDBusConnection sessionBus = QDBusConnection::sessionBus();
|
||||
if (!sessionBus.isConnected() || !(dbusService = sessionBus.interface()))
|
||||
{
|
||||
if (!sessionBus.isConnected() || !(dbusService = sessionBus.interface())) {
|
||||
kError() << "KUniqueApplication: Cannot find the D-Bus session server: " << sessionBus.lastError().message();
|
||||
::exit(255);
|
||||
}
|
||||
return dbusService;
|
||||
}
|
||||
|
||||
bool
|
||||
KUniqueApplication::start(StartFlags flags)
|
||||
{
|
||||
if( s_kuniqueapplication_startCalled )
|
||||
return true;
|
||||
s_kuniqueapplication_startCalled = true;
|
||||
if (Private::s_multipleInstances || flags & KUniqueApplication::NonUniqueInstance) {
|
||||
appName = appName + '-' + QString::number(::getpid());
|
||||
}
|
||||
|
||||
addCmdLineOptions(); // Make sure to add cmd line options
|
||||
KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kuniqueapp");
|
||||
Private::s_nofork = !args->isSet("fork");
|
||||
|
||||
QString appName = KCmdLineArgs::aboutData()->appName();
|
||||
const QStringList parts = KCmdLineArgs::aboutData()->organizationDomain().split(QLatin1Char('.'), QString::SkipEmptyParts);
|
||||
if (parts.isEmpty())
|
||||
appName.prepend(QLatin1String("local."));
|
||||
else
|
||||
foreach (const QString& s, parts)
|
||||
{
|
||||
appName.prepend(QLatin1Char('.'));
|
||||
appName.prepend(s);
|
||||
}
|
||||
|
||||
bool forceNewProcess = Private::s_multipleInstances || flags & NonUniqueInstance;
|
||||
|
||||
if (Private::s_nofork)
|
||||
{
|
||||
|
||||
|
||||
QDBusConnectionInterface* dbusService = tryToInitDBusConnection();
|
||||
|
||||
QString pid = QString::number(getpid());
|
||||
if (forceNewProcess)
|
||||
appName = appName + '-' + pid;
|
||||
|
||||
// Check to make sure that we're actually able to register with the D-Bus session
|
||||
// server.
|
||||
bool registered = dbusService->registerService(appName) == QDBusConnectionInterface::ServiceRegistered;
|
||||
if (!registered)
|
||||
{
|
||||
// Check to make sure that we're actually able to register with the D-Bus session
|
||||
// server.
|
||||
bool registered = dbusService->registerService(appName) == QDBusConnectionInterface::ServiceRegistered;
|
||||
if (!registered) {
|
||||
kError() << "KUniqueApplication: Can't setup D-Bus service. Probably already running.";
|
||||
::exit(255);
|
||||
}
|
||||
}
|
||||
|
||||
// We'll call newInstance in the constructor. Do nothing here.
|
||||
return true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
int fd[2];
|
||||
signed char result;
|
||||
if (0 > pipe(fd))
|
||||
{
|
||||
kError() << "KUniqueApplication: pipe() failed!";
|
||||
::exit(255);
|
||||
}
|
||||
int fork_result = fork();
|
||||
switch(fork_result) {
|
||||
case -1:
|
||||
kError() << "KUniqueApplication: fork() failed!";
|
||||
::exit(255);
|
||||
break;
|
||||
case 0:
|
||||
{
|
||||
// Child
|
||||
|
||||
QDBusConnectionInterface* dbusService = tryToInitDBusConnection();
|
||||
::close(fd[0]);
|
||||
if (forceNewProcess)
|
||||
appName.append("-").append(QString::number(getpid()));
|
||||
|
||||
QDBusReply<QDBusConnectionInterface::RegisterServiceReply> reply =
|
||||
dbusService->registerService(appName);
|
||||
if (!reply.isValid())
|
||||
{
|
||||
kError() << "KUniqueApplication: Can't setup D-Bus service.";
|
||||
result = -1;
|
||||
::write(fd[1], &result, 1);
|
||||
::exit(255);
|
||||
}
|
||||
if (reply == QDBusConnectionInterface::ServiceNotRegistered)
|
||||
{
|
||||
// Already running. Ok.
|
||||
result = 0;
|
||||
::write(fd[1], &result, 1);
|
||||
::close(fd[1]);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
KStartupInfoId id;
|
||||
if( kapp != NULL ) // KApplication constructor unsets the env. variable
|
||||
id.initId( kapp->startupId());
|
||||
else
|
||||
id = KStartupInfo::currentStartupIdEnv();
|
||||
if( !id.none())
|
||||
{ // notice about pid change
|
||||
Display* disp = XOpenDisplay( NULL );
|
||||
if( disp != NULL ) // use extra X connection
|
||||
{
|
||||
KStartupInfoData data;
|
||||
data.addPid( getpid());
|
||||
KStartupInfo::sendChangeX( disp, id, data );
|
||||
XCloseDisplay( disp );
|
||||
}
|
||||
}
|
||||
#else //FIXME(E): Implement
|
||||
#endif
|
||||
}
|
||||
result = 0;
|
||||
::write(fd[1], &result, 1);
|
||||
::close(fd[1]);
|
||||
return true; // Finished.
|
||||
default:
|
||||
// Parent
|
||||
|
||||
if (forceNewProcess)
|
||||
appName.append("-").append(QString::number(fork_result));
|
||||
::close(fd[1]);
|
||||
|
||||
Q_FOREVER
|
||||
{
|
||||
int n = ::read(fd[0], &result, 1);
|
||||
if (n == 1) break;
|
||||
if (n == 0)
|
||||
{
|
||||
kError() << "KUniqueApplication: Pipe closed unexpectedly.";
|
||||
::exit(255);
|
||||
}
|
||||
if (errno != EINTR)
|
||||
{
|
||||
kError() << "KUniqueApplication: Error reading from pipe.";
|
||||
::exit(255);
|
||||
}
|
||||
}
|
||||
::close(fd[0]);
|
||||
|
||||
if (result != 0)
|
||||
::exit(result); // Error occurred in child.
|
||||
|
||||
QDBusConnectionInterface* dbusService = tryToInitDBusConnection();
|
||||
if (!dbusService->isServiceRegistered(appName))
|
||||
{
|
||||
kError() << "KUniqueApplication: Registering failed!";
|
||||
}
|
||||
|
||||
QByteArray saved_args;
|
||||
QDataStream ds(&saved_args, QIODevice::WriteOnly);
|
||||
KCmdLineArgs::saveAppArgs(ds);
|
||||
|
||||
QByteArray new_asn_id;
|
||||
#if defined Q_WS_X11
|
||||
KStartupInfoId id;
|
||||
if( kapp != NULL ) // KApplication constructor unsets the env. variable
|
||||
id.initId( kapp->startupId());
|
||||
else
|
||||
id = KStartupInfo::currentStartupIdEnv();
|
||||
if( !id.none())
|
||||
new_asn_id = id.id();
|
||||
#endif
|
||||
|
||||
QDBusMessage msg = QDBusMessage::createMethodCall(appName, "/MainApplication", "org.kde.KUniqueApplication",
|
||||
"newInstance");
|
||||
msg << new_asn_id << saved_args;
|
||||
QDBusReply<int> reply = QDBusConnection::sessionBus().call(msg, QDBus::Block, INT_MAX);
|
||||
|
||||
if (!reply.isValid())
|
||||
{
|
||||
QDBusError err = reply.error();
|
||||
kError() << "Communication problem with " << KCmdLineArgs::aboutData()->appName() << ", it probably crashed.\n"
|
||||
<< "Error message was: " << err.name() << ": \"" << err.message() << "\"";
|
||||
::exit(255);
|
||||
}
|
||||
::exit(reply);
|
||||
break;
|
||||
}
|
||||
return false; // make insure++ happy
|
||||
// We'll call newInstance in the constructor. Do nothing here.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
KUniqueApplication::KUniqueApplication(bool configUnique)
|
||||
: KApplication( Private::initHack( configUnique )),
|
||||
: KApplication( Private::initHack(configUnique)),
|
||||
d(new Private(this))
|
||||
{
|
||||
d->firstInstance = true;
|
||||
d->firstInstance = true;
|
||||
|
||||
// the sanity checking happened in initHack
|
||||
new KUniqueApplicationAdaptor(this);
|
||||
// the sanity checking happened in initHack
|
||||
new KUniqueApplicationAdaptor(this);
|
||||
|
||||
if (Private::s_nofork)
|
||||
// Can't call newInstance directly from the constructor since it's virtual...
|
||||
QTimer::singleShot( 0, this, SLOT(_k_newInstanceNoFork()) );
|
||||
QTimer::singleShot(0, this, SLOT(_k_newInstance()));
|
||||
}
|
||||
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
KUniqueApplication::KUniqueApplication(Display *display, Qt::HANDLE visual,
|
||||
Qt::HANDLE colormap, bool configUnique)
|
||||
: KApplication( display, visual, colormap, Private::initHack( configUnique )),
|
||||
Qt::HANDLE colormap, bool configUnique)
|
||||
: KApplication(display, visual, colormap, Private::initHack(configUnique)),
|
||||
d(new Private(this))
|
||||
{
|
||||
d->firstInstance = true;
|
||||
d->firstInstance = true;
|
||||
|
||||
// the sanity checking happened in initHack
|
||||
new KUniqueApplicationAdaptor(this);
|
||||
// the sanity checking happened in initHack
|
||||
new KUniqueApplicationAdaptor(this);
|
||||
|
||||
if (Private::s_nofork)
|
||||
// Can't call newInstance directly from the constructor since it's virtual...
|
||||
QTimer::singleShot( 0, this, SLOT(_k_newInstanceNoFork()) );
|
||||
QTimer::singleShot(0, this, SLOT(_k_newInstance()));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
KUniqueApplication::~KUniqueApplication()
|
||||
{
|
||||
delete d;
|
||||
delete d;
|
||||
}
|
||||
|
||||
// this gets called before even entering QApplication::QApplication()
|
||||
KComponentData KUniqueApplication::Private::initHack(bool configUnique)
|
||||
{
|
||||
KComponentData cData(KCmdLineArgs::aboutData());
|
||||
if (configUnique)
|
||||
{
|
||||
KConfigGroup cg(cData.config(), "KDE");
|
||||
s_multipleInstances = cg.readEntry("MultipleInstances", false);
|
||||
}
|
||||
if( !KUniqueApplication::start())
|
||||
// Already running
|
||||
::exit( 0 );
|
||||
return cData;
|
||||
KComponentData cData(KCmdLineArgs::aboutData());
|
||||
if (configUnique) {
|
||||
KConfigGroup cg(cData.config(), "KDE");
|
||||
s_multipleInstances = cg.readEntry("MultipleInstances", false);
|
||||
}
|
||||
if (!KUniqueApplication::start()) {
|
||||
// Already running
|
||||
::exit(0);
|
||||
}
|
||||
return cData;
|
||||
}
|
||||
|
||||
void KUniqueApplication::Private::_k_newInstanceNoFork()
|
||||
void KUniqueApplication::Private::_k_newInstance()
|
||||
{
|
||||
q->newInstance();
|
||||
firstInstance = false;
|
||||
q->newInstance();
|
||||
firstInstance = false;
|
||||
}
|
||||
|
||||
bool KUniqueApplication::restoringSession()
|
||||
{
|
||||
return d->firstInstance && isSessionRestored();
|
||||
return d->firstInstance && isSessionRestored();
|
||||
}
|
||||
|
||||
int KUniqueApplication::newInstance()
|
||||
|
@ -355,16 +168,16 @@ int KUniqueApplication::newInstance()
|
|||
}
|
||||
}
|
||||
}
|
||||
return 0; // do nothing in default implementation
|
||||
// do nothing in default implementation
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
////
|
||||
|
||||
int KUniqueApplicationAdaptor::newInstance(const QByteArray &asn_id, const QByteArray &args)
|
||||
{
|
||||
if (!asn_id.isEmpty())
|
||||
parent()->setStartupId(asn_id);
|
||||
if (!asn_id.isEmpty()) {
|
||||
parent()->setStartupId(asn_id);
|
||||
}
|
||||
|
||||
QDataStream ds(args);
|
||||
KCmdLineArgs::loadAppArgs(ds);
|
||||
|
|
|
@ -42,9 +42,6 @@
|
|||
* The .desktop file for the application should state X-DBUS-StartupType=Unique,
|
||||
* see ktoolinvocation.h
|
||||
*
|
||||
* If you use command line options before start() is called, you MUST call addCmdLineOptions()
|
||||
* so that the KUniqueApplication-specific command-line options can still work.
|
||||
*
|
||||
* If your application is used to open files, it should also support the --tempfile
|
||||
* option (see KCmdLineArgs::addTempFileOption()), to delete tempfiles after use.
|
||||
* Add X-KDE-HasTempFileOption=true to the .desktop file to indicate this.
|
||||
|
@ -54,165 +51,151 @@
|
|||
*/
|
||||
class KDEUI_EXPORT KUniqueApplication : public KApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Constructor. Takes command line arguments from KCmdLineArgs
|
||||
*
|
||||
* @param configUnique If true, the uniqueness of the application will
|
||||
* depend on the value of the "MultipleInstances"
|
||||
* key in the "KDE" group of the application config file.
|
||||
*/
|
||||
explicit KUniqueApplication( bool configUnique=false);
|
||||
/**
|
||||
* Constructor. Takes command line arguments from KCmdLineArgs
|
||||
*
|
||||
* @param configUnique If true, the uniqueness of the application will
|
||||
* depend on the value of the "MultipleInstances"
|
||||
* key in the "KDE" group of the application config file.
|
||||
*/
|
||||
explicit KUniqueApplication(bool configUnique = false);
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
/**
|
||||
* Constructor. Takes command line arguments from KCmdLineArgs
|
||||
*
|
||||
* @param display Will be passed to Qt as the X display. The display
|
||||
* must be valid and already opened.
|
||||
*
|
||||
* @param visual Pointer to the X11 visual that should be used by the
|
||||
* application. If NULL, the default visual will be used instead.
|
||||
*
|
||||
* @param colormap The colormap that should be used by the application.
|
||||
* If 0, the default colormap will be used instead.
|
||||
*
|
||||
* @param configUnique If true, the uniqueness of the application will
|
||||
* depend on the value of the "MultipleInstances"
|
||||
* key in the "KDE" group of the application config file.
|
||||
*/
|
||||
explicit KUniqueApplication( Display *display,
|
||||
Qt::HANDLE visual=0,
|
||||
Qt::HANDLE colormap=0,
|
||||
bool configUnique=false);
|
||||
/**
|
||||
* Constructor. Takes command line arguments from KCmdLineArgs
|
||||
*
|
||||
* @param display Will be passed to Qt as the X display. The display
|
||||
* must be valid and already opened.
|
||||
*
|
||||
* @param visual Pointer to the X11 visual that should be used by the
|
||||
* application. If NULL, the default visual will be used instead.
|
||||
*
|
||||
* @param colormap The colormap that should be used by the application.
|
||||
* If 0, the default colormap will be used instead.
|
||||
*
|
||||
* @param configUnique If true, the uniqueness of the application will
|
||||
* depend on the value of the "MultipleInstances"
|
||||
* key in the "KDE" group of the application config file.
|
||||
*/
|
||||
explicit KUniqueApplication(Display *display,
|
||||
Qt::HANDLE visual=0,
|
||||
Qt::HANDLE colormap=0,
|
||||
bool configUnique=false);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Adds command line options specific for KUniqueApplication.
|
||||
*
|
||||
* Should be called before calling KUniqueApplication constructor
|
||||
* and / or start().
|
||||
*/
|
||||
static void addCmdLineOptions();
|
||||
/**
|
||||
* These flags can be used to specify how new instances of
|
||||
* unique applications are created.
|
||||
*/
|
||||
enum StartFlag {
|
||||
/**
|
||||
* Create a new instance of the application in a new process and
|
||||
* do not attempt to re-use an existing process.
|
||||
*
|
||||
* With this flag set, the new instance of the application will
|
||||
* behave as if it were a plain KApplication rather than a KUniqueApplication.
|
||||
*
|
||||
* This is useful if you have an application where all instances are typically run
|
||||
* in a single process but under certain circumstances new instances may require
|
||||
* their own process.
|
||||
*/
|
||||
NonUniqueInstance = 0x1
|
||||
};
|
||||
Q_DECLARE_FLAGS(StartFlags,StartFlag)
|
||||
|
||||
/**
|
||||
* These flags can be used to specify how new instances of
|
||||
* unique applications are created.
|
||||
*/
|
||||
enum StartFlag
|
||||
{
|
||||
/**
|
||||
* Create a new instance of the application in a new process and
|
||||
* do not attempt to re-use an existing process.
|
||||
*
|
||||
* With this flag set, the new instance of the application will
|
||||
* behave as if it were a plain KApplication rather than a KUniqueApplication.
|
||||
*
|
||||
* This is useful if you have an application where all instances are typically run
|
||||
* in a single process but under certain circumstances new instances may require
|
||||
* their own process.
|
||||
*/
|
||||
NonUniqueInstance = 0x1
|
||||
};
|
||||
Q_DECLARE_FLAGS(StartFlags,StartFlag)
|
||||
/**
|
||||
* Starts and registers with D-Bus.
|
||||
*
|
||||
* The command line arguments are being sent via D-Bus to newInstance()
|
||||
* and will be received once the application enters the event loop.
|
||||
*
|
||||
* Typically this is used like:
|
||||
* \code
|
||||
* int main(int argc, char **argv) {
|
||||
* KAboutData about("myappname", 0, ki18n("myAppName"), .....);
|
||||
* KCmdLineArgs::init(argc, argv, &about);
|
||||
*
|
||||
* if (!KUniqueApplication::start()) {
|
||||
* fprintf(stderr, "myAppName is already running!\n");
|
||||
* return 0;
|
||||
* }
|
||||
* KUniqueApplication a;
|
||||
* return a.exec();
|
||||
* }
|
||||
* \endcode
|
||||
* Note that it's not necessary to call start() explicitly. It will be
|
||||
* called automatically before creating KUniqueApplication if it hasn't
|
||||
* been called yet, without any performance impact.
|
||||
*
|
||||
* @param flags Optional flags which control how a new instance
|
||||
* of the application is started.
|
||||
* @return true if registration is successful.
|
||||
* false if another process was already running.
|
||||
*/
|
||||
static bool start(StartFlags flags = 0);
|
||||
|
||||
/**
|
||||
* Forks and registers with D-Bus.
|
||||
*
|
||||
* The command line arguments are being sent via D-Bus to newInstance()
|
||||
* and will be received once the application enters the event loop.
|
||||
*
|
||||
* Typically this is used like:
|
||||
* \code
|
||||
* int main(int argc, char **argv) {
|
||||
* KAboutData about("myappname", 0, ki18n("myAppName"), .....);
|
||||
* KCmdLineArgs::init(argc, argv, &about);
|
||||
* KCmdLineArgs::addCmdLineOptions( myCmdOptions );
|
||||
* KUniqueApplication::addCmdLineOptions();
|
||||
*
|
||||
* if (!KUniqueApplication::start()) {
|
||||
* fprintf(stderr, "myAppName is already running!\n");
|
||||
* return 0;
|
||||
* }
|
||||
* KUniqueApplication a;
|
||||
* return a.exec();
|
||||
* }
|
||||
* \endcode
|
||||
* Note that it's not necessary to call start() explicitly. It will be
|
||||
* called automatically before creating KUniqueApplication if it hasn't
|
||||
* been called yet, without any performance impact.
|
||||
*
|
||||
* Also note that you MUST call KUniqueApplication::addCmdLineOptions(),
|
||||
* if you use command line options before start() is called.
|
||||
*
|
||||
* @param flags Optional flags which control how a new instance
|
||||
* of the application is started.
|
||||
* @return true if registration is successful.
|
||||
* false if another process was already running.
|
||||
*/
|
||||
static bool start(StartFlags flags = 0);
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~KUniqueApplication();
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~KUniqueApplication();
|
||||
/**
|
||||
* Creates a new "instance" of the application.
|
||||
*
|
||||
* Usually this will involve making some calls into the GUI portion of your
|
||||
* application asking for a new window to be created, possibly with
|
||||
* some data already loaded based on the arguments received.
|
||||
*
|
||||
* Command line arguments have been passed to KCmdLineArgs before this
|
||||
* function is called and can be checked in the usual way.
|
||||
*
|
||||
* The default implementation ensures the mainwindow of the already
|
||||
* running instance is shown and activated if necessary. If your
|
||||
* application has only one mainwindow, you should call this default
|
||||
* implementation and only add your special handling if needed.
|
||||
*
|
||||
* Note that newInstance() is called also in the first started
|
||||
* application process.
|
||||
*
|
||||
* For applications that share one process for several mainwindows,
|
||||
* the reimplementation could be:
|
||||
* \code
|
||||
int MyApp::newInstance()
|
||||
{
|
||||
KCmdLineArgs::setCwd(QDir::currentPath().toUtf8());
|
||||
KCmdLineArgs* args = KCmdLineArgs::parsedArgs();
|
||||
static bool first = true;
|
||||
if (args->count() > 0) {
|
||||
for (int i = 0; i < args->count(); ++i) {
|
||||
openWindow(args->url(i));
|
||||
}
|
||||
} else if( !first || !isSessionRestored()) {
|
||||
openWindow(KUrl()); // create a new window
|
||||
}
|
||||
first = false;
|
||||
args->clear();
|
||||
return 0;
|
||||
}
|
||||
* \endcode
|
||||
*
|
||||
* @return An exit value. The calling process will exit with this value.
|
||||
*/
|
||||
virtual int newInstance();
|
||||
|
||||
/**
|
||||
* Creates a new "instance" of the application.
|
||||
*
|
||||
* Usually this will involve making some calls into the GUI portion of your
|
||||
* application asking for a new window to be created, possibly with
|
||||
* some data already loaded based on the arguments received.
|
||||
*
|
||||
* Command line arguments have been passed to KCmdLineArgs before this
|
||||
* function is called and can be checked in the usual way.
|
||||
*
|
||||
* The default implementation ensures the mainwindow of the already
|
||||
* running instance is shown and activated if necessary. If your
|
||||
* application has only one mainwindow, you should call this default
|
||||
* implementation and only add your special handling if needed.
|
||||
*
|
||||
* Note that newInstance() is called also in the first started
|
||||
* application process.
|
||||
*
|
||||
* For applications that share one process for several mainwindows,
|
||||
* the reimplementation could be:
|
||||
* \code
|
||||
int MyApp::newInstance()
|
||||
{
|
||||
KCmdLineArgs::setCwd(QDir::currentPath().toUtf8());
|
||||
KCmdLineArgs* args = KCmdLineArgs::parsedArgs();
|
||||
static bool first = true;
|
||||
if (args->count() > 0) {
|
||||
for (int i = 0; i < args->count(); ++i) {
|
||||
openWindow(args->url(i));
|
||||
}
|
||||
} else if( !first || !isSessionRestored()) {
|
||||
openWindow(KUrl()); // create a new window
|
||||
}
|
||||
first = false;
|
||||
args->clear();
|
||||
return 0;
|
||||
}
|
||||
* \endcode
|
||||
*
|
||||
* @return An exit value. The calling process will exit with this value.
|
||||
*/
|
||||
virtual int newInstance();
|
||||
|
||||
/**
|
||||
* Returns whether newInstance() is being called while session
|
||||
* restoration is in progress.
|
||||
*/
|
||||
bool restoringSession();
|
||||
/**
|
||||
* Returns whether newInstance() is being called while session
|
||||
* restoration is in progress.
|
||||
*/
|
||||
bool restoringSession();
|
||||
|
||||
private:
|
||||
friend class KUniqueApplicationAdaptor;
|
||||
class Private;
|
||||
Private * const d;
|
||||
friend class KUniqueApplicationAdaptor;
|
||||
class Private;
|
||||
Private * const d;
|
||||
|
||||
Q_PRIVATE_SLOT(d, void _k_newInstanceNoFork())
|
||||
Q_PRIVATE_SLOT(d, void _k_newInstance())
|
||||
};
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(KUniqueApplication::StartFlags)
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#define KUNIQUEAPPLICATION_P_H
|
||||
|
||||
#include <QtDBus/qdbusabstractadaptor.h>
|
||||
#include <kcmdlineargs.h>
|
||||
|
||||
class KUniqueApplication::Private
|
||||
{
|
||||
|
@ -31,38 +30,31 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
void _k_newInstanceNoFork();
|
||||
void _k_newInstance();
|
||||
|
||||
static KComponentData initHack(bool configUnique);
|
||||
|
||||
KUniqueApplication *q;
|
||||
bool firstInstance;
|
||||
|
||||
static bool s_nofork;
|
||||
static bool s_multipleInstances;
|
||||
};
|
||||
|
||||
class KUniqueApplicationAdaptor: public QDBusAbstractAdaptor
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.kde.KUniqueApplication")
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "org.kde.KUniqueApplication")
|
||||
public:
|
||||
KUniqueApplicationAdaptor(KUniqueApplication *parent)
|
||||
: QDBusAbstractAdaptor(parent)
|
||||
{ }
|
||||
KUniqueApplicationAdaptor(KUniqueApplication *parent)
|
||||
: QDBusAbstractAdaptor(parent)
|
||||
{
|
||||
}
|
||||
|
||||
inline KUniqueApplication *parent() const
|
||||
{ return static_cast<KUniqueApplication *>(QDBusAbstractAdaptor::parent()); }
|
||||
inline KUniqueApplication *parent() const
|
||||
{ return static_cast<KUniqueApplication *>(QDBusAbstractAdaptor::parent()); }
|
||||
|
||||
public Q_SLOTS:
|
||||
int newInstance(const QByteArray &asn_id = QByteArray(), const QByteArray &args = QByteArray());
|
||||
int newInstance(const QByteArray &asn_id = QByteArray(), const QByteArray &args = QByteArray());
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 2
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
#endif // KUNIQUEAPPLICATION_P_H
|
||||
|
|
|
@ -75,7 +75,6 @@ int main(int argc, char *argv[])
|
|||
KAboutData about("kuniqueapptest", 0, ki18n("kuniqueapptest"), "version");
|
||||
KCmdLineArgs::init(argc, argv, &about);
|
||||
KCmdLineArgs::addCmdLineOptions( options );
|
||||
KUniqueApplication::addCmdLineOptions();
|
||||
|
||||
if (!TestApp::start())
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue