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:
Ivailo Monev 2023-07-13 17:22:49 +03:00
parent 0220b5bd85
commit cd8ab8d93e
5 changed files with 214 additions and 430 deletions

View file

@ -157,9 +157,6 @@ class KAboutData;
* // Register the supported options * // Register the supported options
* KCmdLineArgs::addCmdLineOptions( options ); * KCmdLineArgs::addCmdLineOptions( options );
* *
* // Add options from other components
* KUniqueApplication::addCmdLineOptions();
*
* .... * ....
* *
* // Create application object without passing 'argc' and 'argv' again. * // Create application object without passing 'argc' and 'argv' again.

View file

@ -17,321 +17,134 @@
Boston, MA 02110-1301, USA. Boston, MA 02110-1301, USA.
*/ */
#include "config.h"
#include "kuniqueapplication.h" #include "kuniqueapplication.h"
#include "kuniqueapplication_p.h" #include "kuniqueapplication_p.h"
#include "kmainwindow.h" #include "kmainwindow.h"
#include "kcmdlineargs.h" #include "kcmdlineargs.h"
#include "kstandarddirs.h"
#include "kaboutdata.h" #include "kaboutdata.h"
#include "kconfiggroup.h" #include "kconfiggroup.h"
#include "kwindowsystem.h" #include "kconfig.h"
#include "kstartupinfo.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 "kdebug.h" #include "kdebug.h"
#include <QList>
#include <QTimer>
#include <QDBusConnection>
#include <QDBusConnectionInterface>
#include <sys/types.h>
#include <unistd.h>
#if defined Q_WS_X11 #if defined Q_WS_X11
#include <netwm.h> # include <X11/Xlib.h>
#include <X11/Xlib.h>
#define DISPLAY "DISPLAY"
#else
# ifdef Q_WS_QWS
# define DISPLAY "QWS_DISPLAY"
# else
# define DISPLAY "DISPLAY"
# endif
#endif #endif
bool KUniqueApplication::Private::s_nofork = false;
bool KUniqueApplication::Private::s_multipleInstances = false; bool KUniqueApplication::Private::s_multipleInstances = false;
bool s_kuniqueapplication_startCalled = false; bool s_kuniqueapplication_startCalled = false;
void bool KUniqueApplication::start(StartFlags flags)
KUniqueApplication::addCmdLineOptions()
{ {
KCmdLineOptions kunique_options; if (s_kuniqueapplication_startCalled) {
kunique_options.add("nofork", ki18n("Do not run in the background.")); return true;
KCmdLineArgs::addCmdLineOptions(kunique_options, KLocalizedString(), "kuniqueapp", "kde"); }
} 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 // Check the D-Bus connection health
QDBusConnectionInterface* dbusService = 0; QDBusConnectionInterface* dbusService = nullptr;
QDBusConnection sessionBus = QDBusConnection::sessionBus(); 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(); kError() << "KUniqueApplication: Cannot find the D-Bus session server: " << sessionBus.lastError().message();
::exit(255); ::exit(255);
} }
return dbusService;
}
bool if (Private::s_multipleInstances || flags & KUniqueApplication::NonUniqueInstance) {
KUniqueApplication::start(StartFlags flags) appName = appName + '-' + QString::number(::getpid());
{ }
if( s_kuniqueapplication_startCalled )
return true;
s_kuniqueapplication_startCalled = true;
addCmdLineOptions(); // Make sure to add cmd line options // Check to make sure that we're actually able to register with the D-Bus session
KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kuniqueapp"); // server.
Private::s_nofork = !args->isSet("fork"); bool registered = dbusService->registerService(appName) == QDBusConnectionInterface::ServiceRegistered;
if (!registered) {
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)
{
kError() << "KUniqueApplication: Can't setup D-Bus service. Probably already running."; kError() << "KUniqueApplication: Can't setup D-Bus service. Probably already running.";
::exit(255); ::exit(255);
} }
// We'll call newInstance in the constructor. Do nothing here. // We'll call newInstance in the constructor. Do nothing here.
return true; 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
} }
KUniqueApplication::KUniqueApplication(bool configUnique) KUniqueApplication::KUniqueApplication(bool configUnique)
: KApplication( Private::initHack( configUnique )), : KApplication( Private::initHack(configUnique)),
d(new Private(this)) d(new Private(this))
{ {
d->firstInstance = true; d->firstInstance = true;
// the sanity checking happened in initHack // the sanity checking happened in initHack
new KUniqueApplicationAdaptor(this); new KUniqueApplicationAdaptor(this);
if (Private::s_nofork)
// Can't call newInstance directly from the constructor since it's virtual... // 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 #ifdef Q_WS_X11
KUniqueApplication::KUniqueApplication(Display *display, Qt::HANDLE visual, KUniqueApplication::KUniqueApplication(Display *display, Qt::HANDLE visual,
Qt::HANDLE colormap, bool configUnique) Qt::HANDLE colormap, bool configUnique)
: KApplication( display, visual, colormap, Private::initHack( configUnique )), : KApplication(display, visual, colormap, Private::initHack(configUnique)),
d(new Private(this)) d(new Private(this))
{ {
d->firstInstance = true; d->firstInstance = true;
// the sanity checking happened in initHack // the sanity checking happened in initHack
new KUniqueApplicationAdaptor(this); new KUniqueApplicationAdaptor(this);
if (Private::s_nofork)
// Can't call newInstance directly from the constructor since it's virtual... // 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 #endif
KUniqueApplication::~KUniqueApplication() KUniqueApplication::~KUniqueApplication()
{ {
delete d; delete d;
} }
// this gets called before even entering QApplication::QApplication() // this gets called before even entering QApplication::QApplication()
KComponentData KUniqueApplication::Private::initHack(bool configUnique) KComponentData KUniqueApplication::Private::initHack(bool configUnique)
{ {
KComponentData cData(KCmdLineArgs::aboutData()); KComponentData cData(KCmdLineArgs::aboutData());
if (configUnique) if (configUnique) {
{ KConfigGroup cg(cData.config(), "KDE");
KConfigGroup cg(cData.config(), "KDE"); s_multipleInstances = cg.readEntry("MultipleInstances", false);
s_multipleInstances = cg.readEntry("MultipleInstances", false); }
} if (!KUniqueApplication::start()) {
if( !KUniqueApplication::start()) // Already running
// Already running ::exit(0);
::exit( 0 ); }
return cData; return cData;
} }
void KUniqueApplication::Private::_k_newInstanceNoFork() void KUniqueApplication::Private::_k_newInstance()
{ {
q->newInstance(); q->newInstance();
firstInstance = false; firstInstance = false;
} }
bool KUniqueApplication::restoringSession() bool KUniqueApplication::restoringSession()
{ {
return d->firstInstance && isSessionRestored(); return d->firstInstance && isSessionRestored();
} }
int KUniqueApplication::newInstance() 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) int KUniqueApplicationAdaptor::newInstance(const QByteArray &asn_id, const QByteArray &args)
{ {
if (!asn_id.isEmpty()) if (!asn_id.isEmpty()) {
parent()->setStartupId(asn_id); parent()->setStartupId(asn_id);
}
QDataStream ds(args); QDataStream ds(args);
KCmdLineArgs::loadAppArgs(ds); KCmdLineArgs::loadAppArgs(ds);

View file

@ -42,9 +42,6 @@
* The .desktop file for the application should state X-DBUS-StartupType=Unique, * The .desktop file for the application should state X-DBUS-StartupType=Unique,
* see ktoolinvocation.h * 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 * If your application is used to open files, it should also support the --tempfile
* option (see KCmdLineArgs::addTempFileOption()), to delete tempfiles after use. * option (see KCmdLineArgs::addTempFileOption()), to delete tempfiles after use.
* Add X-KDE-HasTempFileOption=true to the .desktop file to indicate this. * Add X-KDE-HasTempFileOption=true to the .desktop file to indicate this.
@ -54,165 +51,151 @@
*/ */
class KDEUI_EXPORT KUniqueApplication : public KApplication class KDEUI_EXPORT KUniqueApplication : public KApplication
{ {
Q_OBJECT Q_OBJECT
public: public:
/** /**
* Constructor. Takes command line arguments from KCmdLineArgs * Constructor. Takes command line arguments from KCmdLineArgs
* *
* @param configUnique If true, the uniqueness of the application will * @param configUnique If true, the uniqueness of the application will
* depend on the value of the "MultipleInstances" * depend on the value of the "MultipleInstances"
* key in the "KDE" group of the application config file. * key in the "KDE" group of the application config file.
*/ */
explicit KUniqueApplication( bool configUnique=false); explicit KUniqueApplication(bool configUnique = false);
#ifdef Q_WS_X11 #ifdef Q_WS_X11
/** /**
* Constructor. Takes command line arguments from KCmdLineArgs * Constructor. Takes command line arguments from KCmdLineArgs
* *
* @param display Will be passed to Qt as the X display. The display * @param display Will be passed to Qt as the X display. The display
* must be valid and already opened. * must be valid and already opened.
* *
* @param visual Pointer to the X11 visual that should be used by the * @param visual Pointer to the X11 visual that should be used by the
* application. If NULL, the default visual will be used instead. * application. If NULL, the default visual will be used instead.
* *
* @param colormap The colormap that should be used by the application. * @param colormap The colormap that should be used by the application.
* If 0, the default colormap will be used instead. * If 0, the default colormap will be used instead.
* *
* @param configUnique If true, the uniqueness of the application will * @param configUnique If true, the uniqueness of the application will
* depend on the value of the "MultipleInstances" * depend on the value of the "MultipleInstances"
* key in the "KDE" group of the application config file. * key in the "KDE" group of the application config file.
*/ */
explicit KUniqueApplication( Display *display, explicit KUniqueApplication(Display *display,
Qt::HANDLE visual=0, Qt::HANDLE visual=0,
Qt::HANDLE colormap=0, Qt::HANDLE colormap=0,
bool configUnique=false); bool configUnique=false);
#endif #endif
/** /**
* Adds command line options specific for KUniqueApplication. * These flags can be used to specify how new instances of
* * unique applications are created.
* Should be called before calling KUniqueApplication constructor */
* and / or start(). enum StartFlag {
*/ /**
static void addCmdLineOptions(); * 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 * Starts and registers with D-Bus.
* unique applications are created. *
*/ * The command line arguments are being sent via D-Bus to newInstance()
enum StartFlag * and will be received once the application enters the event loop.
{ *
/** * Typically this is used like:
* Create a new instance of the application in a new process and * \code
* do not attempt to re-use an existing process. * int main(int argc, char **argv) {
* * KAboutData about("myappname", 0, ki18n("myAppName"), .....);
* With this flag set, the new instance of the application will * KCmdLineArgs::init(argc, argv, &about);
* behave as if it were a plain KApplication rather than a KUniqueApplication. *
* * if (!KUniqueApplication::start()) {
* This is useful if you have an application where all instances are typically run * fprintf(stderr, "myAppName is already running!\n");
* in a single process but under certain circumstances new instances may require * return 0;
* their own process. * }
*/ * KUniqueApplication a;
NonUniqueInstance = 0x1 * return a.exec();
}; * }
Q_DECLARE_FLAGS(StartFlags,StartFlag) * \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. * Destructor
* */
* The command line arguments are being sent via D-Bus to newInstance() virtual ~KUniqueApplication();
* 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 * Creates a new "instance" of the application.
*/ *
virtual ~KUniqueApplication(); * 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. * Returns whether newInstance() is being called while session
* * restoration is in progress.
* Usually this will involve making some calls into the GUI portion of your */
* application asking for a new window to be created, possibly with bool restoringSession();
* 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();
private: private:
friend class KUniqueApplicationAdaptor; friend class KUniqueApplicationAdaptor;
class Private; class Private;
Private * const d; Private * const d;
Q_PRIVATE_SLOT(d, void _k_newInstanceNoFork()) Q_PRIVATE_SLOT(d, void _k_newInstance())
}; };
Q_DECLARE_OPERATORS_FOR_FLAGS(KUniqueApplication::StartFlags) Q_DECLARE_OPERATORS_FOR_FLAGS(KUniqueApplication::StartFlags)

View file

@ -21,7 +21,6 @@
#define KUNIQUEAPPLICATION_P_H #define KUNIQUEAPPLICATION_P_H
#include <QtDBus/qdbusabstractadaptor.h> #include <QtDBus/qdbusabstractadaptor.h>
#include <kcmdlineargs.h>
class KUniqueApplication::Private class KUniqueApplication::Private
{ {
@ -31,38 +30,31 @@ public:
{ {
} }
void _k_newInstanceNoFork(); void _k_newInstance();
static KComponentData initHack(bool configUnique); static KComponentData initHack(bool configUnique);
KUniqueApplication *q; KUniqueApplication *q;
bool firstInstance; bool firstInstance;
static bool s_nofork;
static bool s_multipleInstances; static bool s_multipleInstances;
}; };
class KUniqueApplicationAdaptor: public QDBusAbstractAdaptor class KUniqueApplicationAdaptor: public QDBusAbstractAdaptor
{ {
Q_OBJECT Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.KUniqueApplication") Q_CLASSINFO("D-Bus Interface", "org.kde.KUniqueApplication")
public: public:
KUniqueApplicationAdaptor(KUniqueApplication *parent) KUniqueApplicationAdaptor(KUniqueApplication *parent)
: QDBusAbstractAdaptor(parent) : QDBusAbstractAdaptor(parent)
{ } {
}
inline KUniqueApplication *parent() const inline KUniqueApplication *parent() const
{ return static_cast<KUniqueApplication *>(QDBusAbstractAdaptor::parent()); } { return static_cast<KUniqueApplication *>(QDBusAbstractAdaptor::parent()); }
public Q_SLOTS: 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 #endif // KUNIQUEAPPLICATION_P_H
/*
* Local variables:
* c-basic-offset: 2
* indent-tabs-mode: nil
* End:
*/

View file

@ -75,7 +75,6 @@ int main(int argc, char *argv[])
KAboutData about("kuniqueapptest", 0, ki18n("kuniqueapptest"), "version"); KAboutData about("kuniqueapptest", 0, ki18n("kuniqueapptest"), "version");
KCmdLineArgs::init(argc, argv, &about); KCmdLineArgs::init(argc, argv, &about);
KCmdLineArgs::addCmdLineOptions( options ); KCmdLineArgs::addCmdLineOptions( options );
KUniqueApplication::addCmdLineOptions();
if (!TestApp::start()) if (!TestApp::start())
{ {