From a50c72de913cc0acf1c7f9d0eecba19759aeeb67 Mon Sep 17 00:00:00 2001 From: Ivailo Monev Date: Sat, 19 Aug 2023 19:25:01 +0300 Subject: [PATCH] generic: drop support for startup notification via D-Bus service just another way to do what ASN does, the KService::DBusWait mode was not used too. with this change however all of the process setup code is moved to a seperate class and the responsibility of KLauncher about ASN is reduced (ASN now works better for process that fork but if application claims ASN support and does not send ASN finish then the timeout will be reached) Signed-off-by: Ivailo Monev --- kdecore/kernel/kaboutdata.h | 3 - kdecore/services/kservice.cpp | 23 +- kdecore/services/kservice.h | 24 +- kdecore/services/kservice_p.h | 1 - kdecore/tests/kservicetest.cpp | 14 -- kdecore/tests/kservicetest.h | 1 - kdeui/kernel/ktoolinvocation.h | 35 +-- kdeui/kernel/kuniqueapplication.h | 3 - kinit/klauncher_adaptor.cpp | 303 ++++++++++++------------- kinit/klauncher_adaptor.h | 49 ++-- kio/application.desktop | 6 - kio/kfile/kpropertiesdesktopadvbase.ui | 55 ----- kio/kfile/kpropertiesdialog.cpp | 35 +-- 13 files changed, 185 insertions(+), 367 deletions(-) diff --git a/kdecore/kernel/kaboutdata.h b/kdecore/kernel/kaboutdata.h index 2106ee0e..90c63955 100644 --- a/kdecore/kernel/kaboutdata.h +++ b/kdecore/kernel/kaboutdata.h @@ -373,9 +373,6 @@ public: * * Used by the automatic registration to D-Bus done by KApplication and KUniqueApplication. * - * IMPORTANT: if the organization domain is set, the .desktop file that describes your - * application should have an entry like X-DBUS-ServiceName=reversed_domain.kmyapp. - * * @param domain the domain name, for instance kde.org, koffice.org, kdevelop.org, etc. */ KAboutData& setOrganizationDomain(const QByteArray &domain); diff --git a/kdecore/services/kservice.cpp b/kdecore/services/kservice.cpp index a4c4417f..443f465d 100644 --- a/kdecore/services/kservice.cpp +++ b/kdecore/services/kservice.cpp @@ -242,17 +242,6 @@ void KServicePrivate::init( const KDesktopFile *config, KService* q ) parseActions(config, q); } - QString dbusStartupType = desktopGroup.readEntry("X-DBUS-StartupType").toLower(); - entryMap.remove(QLatin1String("X-DBUS-StartupType")); - if (dbusStartupType == QLatin1String("unique")) - m_DBUSStartusType = KService::DBusUnique; - else if (dbusStartupType == QLatin1String("multi")) - m_DBUSStartusType = KService::DBusMulti; - else if (dbusStartupType == QLatin1String("wait")) - m_DBUSStartusType = KService::DBusWait; - else - m_DBUSStartusType = KService::DBusNone; - m_strDesktopEntryName = _name.toLower(); m_bAllowAsDefault = desktopGroup.readEntry("AllowDefault", true); @@ -319,14 +308,13 @@ void KServicePrivate::parseActions(const KDesktopFile *config, KService* q) void KServicePrivate::load(QDataStream& s) { qint8 def, term; - qint8 dst, initpref; + qint8 initpref; // NOTE: make sure to update the version number in ksycoca.cpp s >> m_strType >> m_strName >> m_strExec >> m_strIcon >> term >> m_strTerminalOptions >> m_strPath >> m_strComment >> def >> m_mapProps >> m_strLibrary - >> dst >> m_strDesktopEntryName >> initpref >> m_lstKeywords >> m_strGenName @@ -334,7 +322,6 @@ void KServicePrivate::load(QDataStream& s) m_bAllowAsDefault = (bool)def; m_bTerminal = (bool)term; - m_DBUSStartusType = (KService::DBusStartupType) dst; m_initialPreference = initpref; m_bValid = true; @@ -345,14 +332,12 @@ void KServicePrivate::save(QDataStream& s) KSycocaEntryPrivate::save( s ); qint8 def = m_bAllowAsDefault, initpref = m_initialPreference; qint8 term = m_bTerminal; - qint8 dst = (qint8) m_DBUSStartusType; // NOTE: make sure to update the version number in ksycoca.cpp s << m_strType << m_strName << m_strExec << m_strIcon << term << m_strTerminalOptions << m_strPath << m_strComment << def << m_mapProps << m_strLibrary - << dst << m_strDesktopEntryName << initpref << m_lstKeywords << m_strGenName @@ -829,12 +814,6 @@ QString KService::desktopEntryName() const return d->m_strDesktopEntryName; } -KService::DBusStartupType KService::dbusStartupType() const -{ - Q_D(const KService); - return d->m_DBUSStartusType; -} - QString KService::path() const { Q_D(const KService); diff --git a/kdecore/services/kservice.h b/kdecore/services/kservice.h index 9eb18d17..c40b3456 100644 --- a/kdecore/services/kservice.h +++ b/kdecore/services/kservice.h @@ -163,26 +163,6 @@ public: */ QString storageId() const; - /** - * Describes the DBUS Startup type of the service. - * @li None - This service has no DBUS support - * @li Unique - This service provides a unique DBUS service. - * The service name is equal to the desktopEntryName. - * @li Multi - This service provides a DBUS service which can be run - * with multiple instances in parallel. The service name of - * an instance is equal to the desktopEntryName + "-" + - * the PID of the process. - * @li Wait - This service has no DBUS support, the launcher will wait - * till it is finished. - */ - enum DBusStartupType { DBusNone = 0, DBusUnique, DBusMulti, DBusWait }; - - /** - * Returns the DBUSStartupType supported by this service. - * @return the DBUSStartupType supported by this service - */ - DBusStartupType dbusStartupType() const; - /** * Returns the working directory to run the program in. * @return the working directory to run the program in, @@ -268,8 +248,8 @@ public: QList actions() const; /** - * Checks whether this service can handle several files as - * startup arguments. + * Checks whether this service can handle several files as startup arguments. + * * @return true if multiple files may be passed to this service at * startup. False if only one file at a time may be passed. */ diff --git a/kdecore/services/kservice_p.h b/kdecore/services/kservice_p.h index 214cdb2a..93771cbf 100644 --- a/kdecore/services/kservice_p.h +++ b/kdecore/services/kservice_p.h @@ -87,7 +87,6 @@ public: QVector m_serviceTypes; QString m_strDesktopEntryName; - KService::DBusStartupType m_DBUSStartusType; QMap m_mapProps; QStringList m_lstKeywords; QString m_strGenName; diff --git a/kdecore/tests/kservicetest.cpp b/kdecore/tests/kservicetest.cpp index 71cacd95..93f61e10 100644 --- a/kdecore/tests/kservicetest.cpp +++ b/kdecore/tests/kservicetest.cpp @@ -230,20 +230,6 @@ static bool offerListHasService( const KService::List& offers, return found; } -void KServiceTest::testDBUSStartupType() -{ - if ( !KSycoca::isAvailable() ) - QSKIP( "ksycoca not available", SkipAll ); - if ( !m_hasKde4Konsole ) - QSKIP( "kde4-konsole.desktop not available", SkipAll ); - //KService::Ptr konsole = KService::serviceByMenuId( "kde4-konsole.desktop" ); - KService::Ptr konsole = KService::serviceByDesktopName( "konsole" ); - QVERIFY(konsole); - QCOMPARE(konsole->menuId(), QString("kde4-konsole.desktop")); - //qDebug() << konsole->entryPath(); - QCOMPARE((int)konsole->dbusStartupType(), (int)KService::DBusMulti); -} - void KServiceTest::testByStorageId() { if ( !KSycoca::isAvailable() ) diff --git a/kdecore/tests/kservicetest.h b/kdecore/tests/kservicetest.h index 72f7a18d..258e9e63 100644 --- a/kdecore/tests/kservicetest.h +++ b/kdecore/tests/kservicetest.h @@ -37,7 +37,6 @@ private Q_SLOTS: void testTraderConstraints(); void testHasServiceType1(); void testHasServiceType2(); - void testDBUSStartupType(); void testByStorageId(); void testActionsAndDataStream(); void testServiceGroups(); diff --git a/kdeui/kernel/ktoolinvocation.h b/kdeui/kernel/ktoolinvocation.h index 3324b259..34f46d60 100644 --- a/kdeui/kernel/ktoolinvocation.h +++ b/kdeui/kernel/ktoolinvocation.h @@ -33,33 +33,7 @@ class KUrl; /** - * KToolInvocation: for starting other programs - * - * @section desktopfiles Desktop files for startServiceBy - * - * The way a service gets started depends on the 'X-DBUS-StartupType' - * entry in the desktop file of the service: - * - * There are three possibilities: - * @li X-DBUS-StartupType=None (default) - * Always start a new service, - * don't wait till the service registers with D-Bus. - * @li X-DBUS-StartupType=Multi - * Always start a new service, - * wait until the service has registered with D-Bus. - * @li X-DBUS-StartupType=Unique - * Only start the service if it isn't already running, - * wait until the service has registered with D-Bus. - * The .desktop file can specify the name that the application will use when registering - * using X-DBUS-ServiceName=org.domain.mykapp. Otherwise org.kde.binaryname is assumed. - * - * @section thread Multi-threading - * - * The static members (apart from self()), have to be called from the QApplication main thread. - * Calls to members are only allowed if there is a Q(Core)Application object created - * If you call the members with signal/slot connections across threads, you can't use the return values - * If a function is called from the wrong thread and it has a return value -1 is returned - * Investigate if this is really needed or if D-Bus is threadsafe anyway + * KToolInvocation starts other programs */ class KDECORE_EXPORT KToolInvocation : public QObject { @@ -276,13 +250,6 @@ public: static int kdeinitExecWait(const QString &name, const QStringList &args = QStringList(), QString *error = 0, const QByteArray &startup_id = QByteArray()); -Q_SIGNALS: - /** - * Hook for KApplication in kdeui - * @internal - */ - void kapplication_hook(QStringList &env , QByteArray &startup_id); - private: /** * @internal diff --git a/kdeui/kernel/kuniqueapplication.h b/kdeui/kernel/kuniqueapplication.h index 20d3a37c..3e36e2e0 100644 --- a/kdeui/kernel/kuniqueapplication.h +++ b/kdeui/kernel/kuniqueapplication.h @@ -39,9 +39,6 @@ * your application can only be opened once per user or once per host, you * need to ensure this independently of KUniqueApplication. * - * The .desktop file for the application should state X-DBUS-StartupType=Unique, - * see ktoolinvocation.h - * * 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. diff --git a/kinit/klauncher_adaptor.cpp b/kinit/klauncher_adaptor.cpp index 22cbd3ec..ecdb21d3 100644 --- a/kinit/klauncher_adaptor.cpp +++ b/kinit/klauncher_adaptor.cpp @@ -19,7 +19,6 @@ #include "klauncher_adaptor.h" #include "krun.h" #include "kstandarddirs.h" -#include "kservice.h" #include "kautostart.h" #include "kshell.h" #include "kconfiggroup.h" @@ -28,10 +27,6 @@ #include #include #include -#include -#include -#include -#include #include #include @@ -59,13 +54,138 @@ static inline int getExitStatus(const pid_t pid) return WEXITSTATUS(pidstate); } +static inline bool isASNValid(const QByteArray &asn) +{ + return (!asn.isEmpty() && asn != "0"); +} + +KLauncherProcess::KLauncherProcess(QObject *parent) + : QProcess(parent), + m_kstartupinfo(nullptr), + m_startuptimer(nullptr) +{ + connect( + this, SIGNAL(stateChanged(QProcess::ProcessState)), + this, SLOT(slotProcessStateChanged(QProcess::ProcessState)) + ); +} + +void KLauncherProcess::setupStartup(const QByteArray &startup_id, const QString &appexe, + const KService::Ptr kservice, const qint64 timeout) +{ + Q_ASSERT(m_kstartupinfoid.none() == true); + bool startupsilent = false; + QByteArray startupwmclass; + if (KRun::checkStartupNotify(kservice.data(), &startupsilent, &startupwmclass)) { + m_kstartupinfoid.initId(!isASNValid(startup_id) ? KStartupInfo::createNewStartupId() : startup_id); + kDebug() << "setting up ASN for" << kservice->entryPath() << m_kstartupinfoid.id(); + m_kstartupinfodata.setHostname(); + m_kstartupinfodata.setBin(QFileInfo(appexe).fileName()); + m_kstartupinfodata.setDescription(i18n("Launching %1", kservice->name())); + m_kstartupinfodata.setIcon(kservice->icon()); + m_kstartupinfodata.setApplicationId(kservice->entryPath()); + m_kstartupinfodata.setSilent(startupsilent ? KStartupInfoData::Yes : KStartupInfoData::No); + m_kstartupinfodata.setWMClass(startupwmclass); + QProcessEnvironment processenv = QProcess::processEnvironment(); + processenv.insert(QString::fromLatin1("DESKTOP_STARTUP_ID"), m_kstartupinfoid.id()); + QProcess::setProcessEnvironment(processenv); + sendSIStart(timeout); + } else if (isASNValid(startup_id)) { + kDebug() << "setting up ASN for" << startup_id; + m_kstartupinfoid.initId(startup_id); + m_kstartupinfodata.setHostname(); + m_kstartupinfodata.setBin(QFileInfo(appexe).fileName()); + m_kstartupinfodata.setDescription(i18n("Launching %1", m_kstartupinfodata.bin())); + QProcessEnvironment processenv = QProcess::processEnvironment(); + processenv.insert(QString::fromLatin1("DESKTOP_STARTUP_ID"), QString::fromLatin1(startup_id.constData(), startup_id.size())); + QProcess::setProcessEnvironment(processenv); + sendSIStart(timeout); + } else { + kDebug() << "no ASN for" << appexe; + } +} + +void KLauncherProcess::slotProcessStateChanged(QProcess::ProcessState state) +{ + kDebug() << "process state changed" << this << state; + if (state == QProcess::Starting && !m_kstartupinfoid.none()) { + m_kstartupinfodata.addPid(QProcess::pid()); + sendSIChange(); + } else if (state == QProcess::NotRunning && !m_kstartupinfoid.none()) { + sendSIFinish(); + } +} + +void KLauncherProcess::slotStartupRemoved(const KStartupInfoId &kstartupinfoid, + const KStartupInfoData &kstartupinfodata) +{ + if (m_kstartupinfoid.none()) { + return; + } + + kDebug() << "startup removed" << kstartupinfoid.id() << m_kstartupinfoid.id(); + if (kstartupinfoid.id() == m_kstartupinfoid.id() || kstartupinfodata.is_pid(QProcess::pid())) { + kDebug() << "startup done for process" << this; + sendSIFinish(); + } +} + +void KLauncherProcess::slotStartupTimeout() +{ + kWarning() << "timed out while waiting for process" << this; + sendSIFinish(); +} + +void KLauncherProcess::sendSIStart(const qint64 timeout) +{ + if (m_kstartupinfoid.none()) { + return; + } + + kDebug() << "sending ASN start for" << m_kstartupinfodata.bin(); + m_kstartupinfo = new KStartupInfo(this); + connect( + m_kstartupinfo, SIGNAL(gotRemoveStartup(KStartupInfoId,KStartupInfoData)), + this, SLOT(slotStartupRemoved(KStartupInfoId,KStartupInfoData)) + ); + + m_startuptimer = new QTimer(this); + m_startuptimer->setSingleShot(true); + m_startuptimer->setInterval(timeout); + connect(m_startuptimer, SIGNAL(timeout()), this, SLOT(slotStartupTimeout())); + m_startuptimer->start(); + + KStartupInfo::sendStartup(m_kstartupinfoid, m_kstartupinfodata); +} + +void KLauncherProcess::sendSIChange() +{ + if (m_kstartupinfoid.none()) { + return; + } + kDebug() << "sending ASN change for" << m_kstartupinfodata.bin(); + KStartupInfo::sendChange(m_kstartupinfoid, m_kstartupinfodata); +} + +void KLauncherProcess::sendSIFinish() +{ + if (m_kstartupinfoid.none()) { + return; + } + kDebug() << "sending ASN finish for" << m_kstartupinfodata.bin(); + KStartupInfo::sendFinish(m_kstartupinfoid, m_kstartupinfodata); + m_kstartupinfoid = KStartupInfoId(); + m_kstartupinfodata = KStartupInfoData(); + if (m_startuptimer) { + m_startuptimer->stop(); + } +} + KLauncherAdaptor::KLauncherAdaptor(QObject *parent) : QDBusAbstractAdaptor(parent), - m_dbusconnectioninterface(nullptr), - m_startuptimeout(s_startuptimeout * 1000) + m_startuptimeout(0) { m_environment = QProcessEnvironment::systemEnvironment(); - m_dbusconnectioninterface = QDBusConnection::sessionBus().interface(); // TODO: config watch KConfig klauncherconfig("klaunchrc", KConfig::NoGlobals); @@ -78,7 +198,6 @@ KLauncherAdaptor::KLauncherAdaptor(QObject *parent) KLauncherAdaptor::~KLauncherAdaptor() { - kDebug() << "terminating processes" << m_processes.size(); cleanup(); } @@ -154,8 +273,9 @@ void KLauncherAdaptor::exec_blind(const QString &name, const QStringList &arg_li void KLauncherAdaptor::cleanup() { + kDebug() << "terminating processes" << m_processes.size(); while (!m_processes.isEmpty()) { - QProcess* process = m_processes.takeLast(); + KLauncherProcess* process = m_processes.takeLast(); disconnect(process, 0, this, 0); process->terminate(); if (!process->waitForFinished(s_processtimeout)) { @@ -173,9 +293,8 @@ int KLauncherAdaptor::kdeinit_exec(const QString &app, const QStringList &args, int KLauncherAdaptor::kdeinit_exec_wait(const QString &app, const QStringList &args, const QStringList &envs, const QString &startup_id) { - QMutexLocker locker(&m_mutex); qint64 pid = 0; - int result = startProgram(app, args, envs, startup_id, QDir::currentPath(), pid); + int result = startProgram(app, args, envs, startup_id, QDir::currentPath(), pid, m_startuptimeout); if (result != KLauncherAdaptor::NoError) { return result; } @@ -191,9 +310,8 @@ int KLauncherAdaptor::kdeinit_exec_wait(const QString &app, const QStringList &a int KLauncherAdaptor::kdeinit_exec_with_workdir(const QString &app, const QStringList &args, const QStringList &envs, const QString &startup_id, const QString &workdir) { - QMutexLocker locker(&m_mutex); qint64 pid = 0; - return startProgram(app, args, envs, startup_id, workdir, pid); + return startProgram(app, args, envs, startup_id, workdir, pid, m_startuptimeout); } void KLauncherAdaptor::setLaunchEnv(const QString &name, const QString &value) @@ -218,29 +336,12 @@ int KLauncherAdaptor::start_service_by_desktop_name(const QString &serviceName, int KLauncherAdaptor::start_service_by_desktop_path(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id) { - QMutexLocker locker(&m_mutex); KService::Ptr kservice = KService::serviceByStorageId(serviceName); if (!kservice) { kWarning() << "invalid service path" << serviceName; return KLauncherAdaptor::ServiceError; } - const KService::DBusStartupType dbusstartuptype = kservice->dbusStartupType(); - QString dbusServiceName = kservice->property(QString::fromLatin1("X-DBUS-ServiceName"), QVariant::String).toString(); - // any unique Katana application/service checks if another instance is running, if it is - // already running starting it may raise its window instead (if it uses KUniqueApplication) - if (dbusstartuptype == KService::DBusUnique && !dbusServiceName.startsWith(QLatin1String("org.kde."))) { - QDBusReply sessionreply = m_dbusconnectioninterface->isServiceRegistered(dbusServiceName); - if (!sessionreply.isValid()) { - kWarning() << "invalid D-Bus reply for" << dbusServiceName; - return KLauncherAdaptor::DBusError; - } - if (sessionreply.value() == true) { - kDebug() << "service already started" << dbusServiceName; - return KLauncherAdaptor::NoError; - } - } if (urls.size() > 1 && !kservice->allowMultipleFiles()) { - // TODO: start multiple instances for each URL kWarning() << "service does not support multiple files" << serviceName; return KLauncherAdaptor::ServiceError; } @@ -249,80 +350,10 @@ int KLauncherAdaptor::start_service_by_desktop_path(const QString &serviceName, kWarning() << "could not process service" << kservice->entryPath(); return KLauncherAdaptor::ArgumentsError; } - kDebug() << "starting" << kservice->entryPath() << urls << dbusServiceName; + kDebug() << "starting" << kservice->entryPath() << urls; const QString program = programandargs.takeFirst(); - const QStringList programargs = programandargs; - Q_ASSERT(m_kstartupinfoid.none() == true); - m_kstartupinfoid = KStartupInfoId(); - m_kstartupinfodata = KStartupInfoData(); - bool startupsilent = false; - QByteArray startupwmclass; - if (KRun::checkStartupNotify(kservice.data(), &startupsilent, &startupwmclass)) { - m_kstartupinfoid.initId(startup_id.toLatin1()); - m_kstartupinfodata.setBin(QFileInfo(program).fileName()); - m_kstartupinfodata.setDescription(i18n("Launching %1", kservice->name())); - m_kstartupinfodata.setIcon(kservice->icon()); - m_kstartupinfodata.setApplicationId(kservice->entryPath()); - m_kstartupinfodata.setSilent(startupsilent ? KStartupInfoData::Yes : KStartupInfoData::No); - m_kstartupinfodata.setWMClass(startupwmclass); - sendSIStart(); - } else { - kDebug() << "no ASN for" << kservice->entryPath(); - } qint64 pid = 0; - int result = startProgram(program, programargs, envs, QString(), QDir::currentPath(), pid); - if (result != KLauncherAdaptor::NoError) { - // sendSIFinish() is called on exec error - return result; - } - if (dbusstartuptype == KService::DBusNone) { - sendSIFinish(); - return result; - } else if (dbusstartuptype != KService::DBusNone && dbusServiceName.isEmpty()) { - // not going to guess what service to wait for, bud - kWarning() << "X-DBUS-ServiceName not specified in" << kservice->entryPath(); - sendSIFinish(); - return result; - } else if (dbusstartuptype == KService::DBusMulti) { - dbusServiceName.append(QLatin1Char('-')); - dbusServiceName.append(QString::number(pid)); - } - kDebug() << "waiting for" << pid << dbusServiceName << m_startuptimeout; - QElapsedTimer elapsedtime; - elapsedtime.start(); - while (true) { - QDBusReply sessionreply = m_dbusconnectioninterface->isServiceRegistered(dbusServiceName); - if (!sessionreply.isValid()) { - kWarning() << "invalid D-Bus reply for" << dbusServiceName; - sendSIFinish(); - return KLauncherAdaptor::DBusError; - } - // the service unregistered - if (sessionreply.value() == false && dbusstartuptype == KService::DBusWait) { - kDebug() << "service unregistered" << dbusServiceName; - break; - } - // the service registered - if (sessionreply.value() == true && dbusstartuptype != KService::DBusWait) { - kDebug() << "service registered" << dbusServiceName; - break; - } - // or the program is just not registering the service at all - if (elapsedtime.elapsed() >= m_startuptimeout && dbusstartuptype != KService::DBusWait) { - kWarning() << "timed out while waiting for service" << dbusServiceName; - break; - } - // or the program is not even running - if (!isPIDAlive(pid)) { - kWarning() << "service process is not running" << dbusServiceName; - result = getExitStatus(pid); - break; - } - QApplication::processEvents(QEventLoop::AllEvents, s_eventstime); - QThread::msleep(s_sleeptime); - } - sendSIFinish(); - return result; + return startProgram(program, programandargs, envs, QString(), QDir::currentPath(), pid, m_startuptimeout, kservice); } #ifdef KLAUNCHER_DEBUG @@ -332,21 +363,9 @@ QStringList KLauncherAdaptor::environment() const } #endif -void KLauncherAdaptor::slotProcessStateChanged(QProcess::ProcessState state) -{ - QProcess* process = qobject_cast(sender()); - kDebug() << "process state changed" << process << state; - if (state == QProcess::Starting && !m_kstartupinfoid.none()) { - m_kstartupinfodata.addPid(process->pid()); - sendSIChange(); - } else if (state == QProcess::NotRunning && m_kstartupinfodata.is_pid(process->pid())) { - sendSIFinish(); - } -} - void KLauncherAdaptor::slotProcessFinished(int exitcode) { - QProcess* process = qobject_cast(sender()); + KLauncherProcess* process = qobject_cast(sender()); kDebug() << "process finished" << process << exitcode; m_processes.removeAll(process); } @@ -364,7 +383,9 @@ QString KLauncherAdaptor::findExe(const QString &app) const return KStandardDirs::findExe(app, environmentpath); } -int KLauncherAdaptor::startProgram(const QString &app, const QStringList &args, const QStringList &envs, const QString &startup_id, const QString &workdir, qint64 &pid) +int KLauncherAdaptor::startProgram(const QString &app, const QStringList &args, const QStringList &envs, + const QString &startup_id, const QString &workdir, qint64 &pid, + const qint64 timeout, const KService::Ptr kservice) { const QString appexe = findExe(app); if (appexe.isEmpty()) { @@ -372,8 +393,7 @@ int KLauncherAdaptor::startProgram(const QString &app, const QStringList &args, return KLauncherAdaptor::FindError; } - QProcess* process = new QProcess(this); - connect(process, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(slotProcessStateChanged(QProcess::ProcessState))); + KLauncherProcess* process = new KLauncherProcess(this); connect(process, SIGNAL(finished(int)), this, SLOT(slotProcessFinished(int))); m_processes.append(process); QProcessEnvironment processenv = m_environment; @@ -390,61 +410,20 @@ int KLauncherAdaptor::startProgram(const QString &app, const QStringList &args, } process->setProcessEnvironment(processenv); process->setWorkingDirectory(workdir); - kDebug() << "starting" << appexe << args << envs; - if (!startup_id.isEmpty()) { - Q_ASSERT(m_kstartupinfoid.none() == true); - m_kstartupinfoid = KStartupInfoId(); - m_kstartupinfodata = KStartupInfoData(); - m_kstartupinfoid.initId(startup_id.toLatin1()); - m_kstartupinfodata.setBin(QFileInfo(appexe).fileName()); - m_kstartupinfodata.setDescription(i18n("Launching %1", m_kstartupinfodata.bin())); - sendSIStart(); - } + process->setupStartup(startup_id.toLatin1(), appexe, kservice, timeout); + kDebug() << "starting" << appexe << args << envs << workdir; process->start(appexe, args); while (process->state() == QProcess::Starting) { QApplication::processEvents(QEventLoop::AllEvents, s_eventstime); QThread::msleep(s_sleeptime); } if (process->error() == QProcess::FailedToStart || process->error() == QProcess::Crashed) { - sendSIFinish(); kWarning() << "could not start" << appexe; return KLauncherAdaptor::ExecError; } - if (!startup_id.isEmpty()) { - sendSIFinish(); - } pid = process->pid(); return KLauncherAdaptor::NoError; } -void KLauncherAdaptor::sendSIStart() const -{ - if (m_kstartupinfoid.none()) { - return; - } - kDebug() << "sending ASN start for" << m_kstartupinfodata.bin(); - KStartupInfo::sendStartup(m_kstartupinfoid, m_kstartupinfodata); -} - -void KLauncherAdaptor::sendSIChange() -{ - if (m_kstartupinfoid.none()) { - return; - } - kDebug() << "sending ASN change for" << m_kstartupinfodata.bin(); - KStartupInfo::sendChange(m_kstartupinfoid, m_kstartupinfodata); -} - -void KLauncherAdaptor::sendSIFinish() -{ - if (m_kstartupinfoid.none()) { - return; - } - kDebug() << "sending ASN finish for" << m_kstartupinfodata.bin(); - KStartupInfo::sendFinish(m_kstartupinfoid, m_kstartupinfodata); - m_kstartupinfoid = KStartupInfoId(); - m_kstartupinfodata = KStartupInfoData(); -} - #include "moc_klauncher_adaptor.cpp" diff --git a/kinit/klauncher_adaptor.h b/kinit/klauncher_adaptor.h index d4163f67..4216e23e 100644 --- a/kinit/klauncher_adaptor.h +++ b/kinit/klauncher_adaptor.h @@ -20,15 +20,41 @@ #define KLAUNCHER_ADAPTOR_H #include "kstartupinfo.h" +#include "kservice.h" #include -#include -#include #include -#include +#include // #define KLAUNCHER_DEBUG +class KLauncherProcess : public QProcess +{ + Q_OBJECT +public: + explicit KLauncherProcess(QObject *parent); + + void setupStartup(const QByteArray &startup_id, const QString &appexe, + const KService::Ptr kservice, const qint64 timeout); + +private Q_SLOTS: + void slotProcessStateChanged(QProcess::ProcessState state); + void slotStartupRemoved(const KStartupInfoId &id, const KStartupInfoData &data); + void slotStartupTimeout(); + +private: + Q_DISABLE_COPY(KLauncherProcess); + + void sendSIStart(const qint64 timeout); + void sendSIChange(); + void sendSIFinish(); + + KStartupInfo* m_kstartupinfo; + QTimer* m_startuptimer; + KStartupInfoId m_kstartupinfoid; + KStartupInfoData m_kstartupinfodata; +}; + // Adaptor class for interface org.kde.KLauncher class KLauncherAdaptor: public QDBusAbstractAdaptor { @@ -40,8 +66,7 @@ public: ServiceError = -1, FindError = -2, ArgumentsError = -3, - ExecError = -4, - DBusError = -5 + ExecError = -4 }; KLauncherAdaptor(QObject *parent); @@ -75,23 +100,17 @@ Q_SIGNALS: void autoStart2Done(); private Q_SLOTS: - void slotProcessStateChanged(QProcess::ProcessState state); void slotProcessFinished(int exitcode); private: QString findExe(const QString &app) const; - int startProgram(const QString &app, const QStringList &args, const QStringList &envs, const QString &startup_id, const QString &workdir, qint64 &pid); - void sendSIStart() const; - void sendSIChange(); - void sendSIFinish(); + int startProgram(const QString &app, const QStringList &args, const QStringList &envs, + const QString &startup_id, const QString &workdir, qint64 &pid, + const qint64 timeout, const KService::Ptr kservice = KService::Ptr(nullptr)); - QMutex m_mutex; QProcessEnvironment m_environment; - QDBusConnectionInterface* m_dbusconnectioninterface; qint64 m_startuptimeout; - KStartupInfoId m_kstartupinfoid; - KStartupInfoData m_kstartupinfodata; - QList m_processes; + QList m_processes; QStringList m_autostart; }; diff --git a/kio/application.desktop b/kio/application.desktop index 74a8269a..c5bcce6f 100644 --- a/kio/application.desktop +++ b/kio/application.desktop @@ -118,12 +118,6 @@ Type=QString [PropertyDef::StartupNotify] Type=bool -[PropertyDef::X-DBUS-ServiceName] -Type=QString - -[PropertyDef::X-DBUS-StartupType] -Type=QString - [PropertyDef::X-KDE-ParentApp] Type=QString diff --git a/kio/kfile/kpropertiesdesktopadvbase.ui b/kio/kfile/kpropertiesdesktopadvbase.ui index 6773a664..015ce6ab 100644 --- a/kio/kfile/kpropertiesdesktopadvbase.ui +++ b/kio/kfile/kpropertiesdesktopadvbase.ui @@ -144,67 +144,12 @@ - - - - &D-Bus registration: - - - dbusCombo - - - - - - - - None - - - - - Multiple Instances - - - - - Single Instance - - - - - Run Until Finished - - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 50 - 20 - - - - - - KComboBox - QComboBox -
kcombobox.h
-
KLineEdit QLineEdit diff --git a/kio/kfile/kpropertiesdialog.cpp b/kio/kfile/kpropertiesdialog.cpp index a58deb43..68db57fb 100644 --- a/kio/kfile/kpropertiesdialog.cpp +++ b/kio/kfile/kpropertiesdialog.cpp @@ -2989,6 +2989,10 @@ public: KDesktopPropsPluginPrivate() : w(new Ui_KPropertiesDesktopBase()) , m_frame(new QFrame()) + , m_terminalBool(false) + , m_suidBool(false) + , m_startupBool(false) + , m_systrayBool(false) { } ~KDesktopPropsPluginPrivate() @@ -3002,8 +3006,6 @@ public: QString m_origCommandStr; QString m_terminalOptionStr; QString m_suidUserStr; - QString m_dbusStartupType; - QString m_dbusServiceName; QString m_origDesktopFile; bool m_terminalBool; bool m_suidBool; @@ -3078,11 +3080,7 @@ KDesktopPropsPlugin::KDesktopPropsPlugin(KPropertiesDialog *props) d->m_terminalOptionStr = config.readEntry( "TerminalOptions"); d->m_suidBool = config.readEntry("X-KDE-SubstituteUID", false); d->m_suidUserStr = config.readEntry("X-KDE-Username"); - d->m_startupBool = config.readEntry("StartupNotify", true); - d->m_dbusStartupType = config.readEntry("X-DBUS-StartupType").toLower(); - // ### should there be a GUI for this setting? - // At least we're copying it over to the local file, to avoid side effects (#157853) - d->m_dbusServiceName = config.readEntry("X-DBUS-ServiceName"); + d->m_startupBool = config.readEntry("StartupNotify", false); const QStringList mimeTypes = config.readXdgListEntry("MimeType"); @@ -3183,8 +3181,6 @@ void KDesktopPropsPlugin::checkCommandChanged() { if (KRun::binaryName(d->w->commandEdit->text(), true) != KRun::binaryName(d->m_origCommandStr, true)) { d->m_origCommandStr = d->w->commandEdit->text(); - d->m_dbusStartupType.clear(); // Reset - d->m_dbusServiceName.clear(); } } @@ -3254,8 +3250,7 @@ void KDesktopPropsPlugin::applyChanges() config.writeEntry("X-KDE-SubstituteUID", d->m_suidBool); config.writeEntry("X-KDE-Username", d->m_suidUserStr); config.writeEntry("StartupNotify", d->m_startupBool); - config.writeEntry("X-DBUS-StartupType", d->m_dbusStartupType); - config.writeEntry("X-DBUS-ServiceName", d->m_dbusServiceName); +#warning TODO: StartupWMClass config.sync(); // KSycoca update needed? @@ -3327,16 +3322,6 @@ void KDesktopPropsPlugin::slotAdvanced() w.startupInfoCheck->setChecked(d->m_startupBool); w.systrayCheck->setChecked(d->m_systrayBool); - if (d->m_dbusStartupType == QLatin1String("unique")) { - w.dbusCombo->setCurrentIndex(2); - } else if (d->m_dbusStartupType == QLatin1String("multi")) { - w.dbusCombo->setCurrentIndex(1); - } else if (d->m_dbusStartupType == QLatin1String("wait")) { - w.dbusCombo->setCurrentIndex(3); - } else { - w.dbusCombo->setCurrentIndex(0); - } - // Provide username completion up to 1000 users. KCompletion *kcom = new KCompletion; kcom->setOrder(KCompletion::Sorted); @@ -3361,7 +3346,6 @@ void KDesktopPropsPlugin::slotAdvanced() connect(w.suidEdit, SIGNAL(textChanged(QString)), this, SIGNAL(changed()) ); connect(w.startupInfoCheck, SIGNAL(toggled(bool)), this, SIGNAL(changed()) ); connect(w.systrayCheck, SIGNAL(toggled(bool)), this, SIGNAL(changed()) ); - connect(w.dbusCombo, SIGNAL(activated(int)), this, SIGNAL(changed()) ); if (dlg.exec() == QDialog::Accepted) { d->m_terminalOptionStr = w.terminalEdit->text().trimmed(); @@ -3374,13 +3358,6 @@ void KDesktopPropsPlugin::slotAdvanced() if (w.terminalCloseCheck->isChecked()) { d->m_terminalOptionStr.append(" --noclose"); } - - switch(w.dbusCombo->currentIndex()) { - case 1: d->m_dbusStartupType = "multi"; break; - case 2: d->m_dbusStartupType = "unique"; break; - case 3: d->m_dbusStartupType = "wait"; break; - default: d->m_dbusStartupType = "none"; break; - } } }