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
|
* // 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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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:
|
|
||||||
*/
|
|
||||||
|
|
|
@ -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())
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Reference in a new issue