kio: move most of the KRun bits to KLauncher

two things doing the same thing - one has to go away. also KRun does not
fork and the launched service/application lifetime was bound to the
process launching it, that is not the case with klauncher - it is bound
to the session (in the usual case)

a few things on the TODO list but mostly for services/applications
lacking features

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2024-05-11 02:15:42 +03:00
parent ceaddee1dd
commit b90f90905b
24 changed files with 414 additions and 2892 deletions

View file

@ -693,11 +693,11 @@ QString KService::docPath() const
return it->toString();
}
bool KService::allowMultipleFiles() const {
bool KService::allowMultipleFiles() const
{
Q_D(const KService);
// Can we pass multiple files on the command line or do we have to start the application for every single file ?
return (d->m_strExec.contains( QLatin1String("%F") ) || d->m_strExec.contains( QLatin1String("%U") ) ||
d->m_strExec.contains( QLatin1String("%N") ) || d->m_strExec.contains( QLatin1String("%D") ));
return (d->m_strExec.contains( QLatin1String("%F") ) || d->m_strExec.contains( QLatin1String("%U") ));
}
QStringList KService::categories() const

View file

@ -43,36 +43,6 @@
#define KTOOLINVOCATION_TIMEOUT 250
// NOTE: keep in sync with:
// kdelibs/kinit/klauncher_adaptor.h
static inline QString getKLauncherError(const int result, const QString &app)
{
switch (result) {
case -1: {
return i18n("Application service is not valid or does not support multiple files: %1.", app);
}
case -2: {
return i18n("Application not found: %1.", app);
}
case -3: {
return i18n("Application could not be processed: %1.", app);
}
case -4: {
return i18n("Application failed to start: %1.", app);
}
}
return i18n("Unknown KLauncher error for application: %1.", app);
}
static inline void printError(const QString &text, QString *error)
{
if (error) {
*error = text;
} else {
kError() << text;
}
}
K_GLOBAL_STATIC(KToolInvocation, kToolInvocation)
KToolInvocation* KToolInvocation::self()
@ -104,113 +74,27 @@ void KToolInvocation::setLaunchEnv(const QString &name, const QString &value)
klauncherIface->asyncCall(QString::fromLatin1("setLaunchEnv"), name, value);
}
int KToolInvocation::startServiceInternal(const char *_function,
const QString &name, const QStringList &URLs,
QString *error,
const QByteArray &startup_id,
const QString &workdir)
bool KToolInvocation::startServiceForUrl(const QString &url, QWidget *window, bool temp)
{
QString function = QString::fromLatin1(_function);
// make sure there is id, so that user timestamp exists
QStringList envs;
if (QX11Info::display()) {
const QString dpystring = QString::fromLatin1(XDisplayString(QX11Info::display()));
envs << QLatin1String("DISPLAY=") + dpystring;
} else {
const QString dpystring = QString::fromLocal8Bit(qgetenv("DISPLAY"));
if (!dpystring.isEmpty()) {
envs << QLatin1String("DISPLAY=") + dpystring;
}
}
QDBusPendingReply<int> reply;
if (qstrcmp(_function, "kdeinit_exec_with_workdir") == 0) {
reply = klauncherIface->asyncCall(
function, name, URLs, envs, QString::fromLatin1(startup_id, startup_id.size()), workdir
);
} else {
reply = klauncherIface->asyncCall(
function, name, URLs, envs, QString::fromLatin1(startup_id, startup_id.size())
return startServiceInternal(
"start_service_by_url", QString(), QStringList() << url, window, temp
);
}
kDebug() << "Waiting for klauncher call to finish" << function;
while (!reply.isFinished()) {
QCoreApplication::processEvents(QEventLoop::AllEvents, KTOOLINVOCATION_TIMEOUT);
}
kDebug() << "Done waiting for klauncher call to finish" << function;
if (!reply.isValid()) {
printError(
i18n("KLauncher error: %1.", reply.error().message()),
error
);
return EINVAL;
}
const int result = reply.value();
if (result < 0) {
printError(
getKLauncherError(result, name),
error
);
// compat
return -result;
} else if (result != 0) {
printError(
i18n("Application failed to start: %1.", name),
error
);
}
return result;
}
int KToolInvocation::startServiceByDesktopPath(const QString &name, const QString &URL,
QString *error, const QByteArray &startup_id)
bool KToolInvocation::startServiceByStorageId(const QString &name, const QStringList &URLs,
QWidget *window, bool temp)
{
QStringList URLs;
if (!URL.isEmpty()) {
URLs.append(URL);
}
return startServiceInternal("start_service_by_desktop_path", name, URLs, error, startup_id);
return startServiceInternal("start_service_by_storage_id", name, URLs, window, temp);
}
int KToolInvocation::startServiceByDesktopPath(const QString &name, const QStringList &URLs,
QString *error, const QByteArray &startup_id)
bool KToolInvocation::startProgram(const QString &name, const QStringList &args, QWidget *window,
bool temp)
{
return startServiceInternal("start_service_by_desktop_path", name, URLs, error, startup_id);
}
int KToolInvocation::startServiceByDesktopName(const QString &name, const QString &URL,
QString *error, const QByteArray &startup_id)
{
QStringList URLs;
if (!URL.isEmpty()) {
URLs.append(URL);
}
return startServiceInternal("start_service_by_desktop_name", name, URLs, error, startup_id);
}
int KToolInvocation::startServiceByDesktopName(const QString &name, const QStringList &URLs,
QString *error, const QByteArray &startup_id)
{
return startServiceInternal("start_service_by_desktop_name", name, URLs, error, startup_id);
}
int KToolInvocation::kdeinitExec(const QString &name, const QStringList &args, QString *error,
const QByteArray &startup_id)
{
return startServiceInternal("kdeinit_exec", name, args, error, startup_id);
}
int KToolInvocation::kdeinitExecWait(const QString &name, const QStringList &args, QString *error,
const QByteArray &startup_id)
{
return startServiceInternal("kdeinit_exec_wait", name, args, error, startup_id);
return startServiceInternal("start_program", name, args, window, temp);
}
void KToolInvocation::invokeHelp(const QString &anchor,
const QString &_appname,
const QByteArray &startup_id)
const QString &_appname)
{
KUrl url;
QString appname;
@ -235,14 +119,12 @@ void KToolInvocation::invokeHelp(const QString &anchor,
invokeBrowser(url.url());
}
void KToolInvocation::invokeMailer(const QString &address, const QString &subject,
const QByteArray &startup_id)
void KToolInvocation::invokeMailer(const QString &address, const QString &subject)
{
invokeMailer(address, QString(), subject, QString(), QStringList(), startup_id);
invokeMailer(address, QString(), subject, QString(), QStringList());
}
void KToolInvocation::invokeMailer(const KUrl &mailtoURL, const QByteArray &startup_id,
bool allowAttachments)
void KToolInvocation::invokeMailer(const KUrl &mailtoURL, bool allowAttachments)
{
QString address = mailtoURL.path();
QString subject;
@ -274,7 +156,50 @@ void KToolInvocation::invokeMailer(const KUrl &mailtoURL, const QByteArray &star
address = address.isEmpty()? KUrl::fromPercentEncoding((*it).mid(3).toLatin1()): address + comma + KUrl::fromPercentEncoding((*it).mid(3).toLatin1());
}
invokeMailer(address, cc, subject, body, attachURLs, startup_id);
invokeMailer(address, cc, subject, body, attachURLs);
}
bool KToolInvocation::startServiceInternal(const char *_function,
const QString &name, const QStringList &URLs,
QWidget *window, bool temp, const QString &workdir)
{
QString function = QString::fromLatin1(_function);
// make sure there is id, so that user timestamp exists
QStringList envs;
if (QX11Info::display()) {
const QString dpystring = QString::fromLatin1(XDisplayString(QX11Info::display()));
envs << QLatin1String("DISPLAY=") + dpystring;
} else {
const QString dpystring = QString::fromLocal8Bit(qgetenv("DISPLAY"));
if (!dpystring.isEmpty()) {
envs << QLatin1String("DISPLAY=") + dpystring;
}
}
QDBusPendingReply<bool> reply;
if (qstrcmp(_function, "start_service_by_url") == 0) {
reply = klauncherIface->asyncCall(
function, URLs.first(), envs, window ? quint64(window->winId()) : 0, temp
);
} else if (qstrcmp(_function, "start_program_with_workdir") == 0) {
reply = klauncherIface->asyncCall(
function, name, URLs, envs, window ? quint64(window->winId()) : 0, temp, workdir
);
} else {
reply = klauncherIface->asyncCall(
function, name, URLs, envs, window ? quint64(window->winId()) : 0, temp
);
}
kDebug() << "Waiting for klauncher call to finish" << function;
while (!reply.isFinished()) {
QCoreApplication::processEvents(QEventLoop::AllEvents, KTOOLINVOCATION_TIMEOUT);
}
kDebug() << "Done waiting for klauncher call to finish" << function;
if (!reply.isValid()) {
kError() << "KLauncher error" << reply.error().message();
return false;
}
return reply.value();
}
#include "moc_ktoolinvocation.cpp"

View file

@ -47,16 +47,14 @@ public:
public Q_SLOTS:
/**
* Invokes the KHelpCenter HTML help viewer from docbook sources.
* Invokes the help viewer.
*
* @param anchor This has to be a defined anchor in your docbook sources. If empty the
* main index is loaded
* @param appname This allows you to show the help of another application. If empty the
* current name() is used
* @param startup_id For app startup notification, "0" for none
*/
void invokeHelp(const QString &anchor = QString(), const QString &appname = QString(),
const QByteArray &startup_id = QByteArray());
void invokeHelp(const QString &anchor = QString(), const QString &appname = QString());
/**
* Convenience method; invokes the standard email application.
@ -65,19 +63,16 @@ public Q_SLOTS:
* @param subject Subject string. Can be QString().
* @param startup_id Ffor app startup notification, "0" for none
*/
void invokeMailer(const QString &address, const QString &subject,
const QByteArray &startup_id = QByteArray());
void invokeMailer(const QString &address, const QString &subject);
/**
* Invokes the standard email application.
*
* @param mailtoURL A mailto URL.
* @param startup_id For app startup notification, "0" for none
* @param allowAttachments Whether attachments specified in mailtoURL should be honoured. The
* default is false; do not honor requests for attachments.
*/
void invokeMailer(const KUrl &mailtoURL, const QByteArray &startup_id = QByteArray(),
bool allowAttachments = false);
void invokeMailer(const KUrl &mailtoURL, bool allowAttachments = false);
/**
* Convenience method; invokes the standard email application.
@ -89,11 +84,9 @@ public Q_SLOTS:
* @param subject Subject string
* @param body A string containing the body of the mail
* @param attachURLs List of URLs to be attached to the mail.
* @param startup_id For app startup notification, "0" for none
*/
void invokeMailer(const QString &to, const QString &cc, const QString &subject,
const QString &body, const QStringList &attachURLs = QStringList(),
const QByteArray &startup_id = QByteArray());
const QString &body, const QStringList &attachURLs = QStringList());
/**
* Invokes the user's preferred browser. Note that you should only do this when you know for
@ -101,21 +94,18 @@ public Q_SLOTS:
* to an image or anything else than HTML, prefer to use KRun.
*
* @param url The destination address
* @param startup_id For app startup notification, "0" for none
*/
void invokeBrowser(const QString &url, const QByteArray &startup_id = QByteArray());
void invokeBrowser(const QString &url);
/**
* Invokes the standard terminal application.
*
* @param command The command to execute, can be empty.
* @param workdir The initial working directory, can be empty.
* @param startup_id For app startup notification, "0" for none
*
* @since 4.1
*/
void invokeTerminal(const QString &command, const QString &workdir = QString(),
const QByteArray &startup_id = QByteArray());
void invokeTerminal(const QString &command, const QString &workdir = QString());
public:
/**
@ -127,89 +117,39 @@ public:
void setLaunchEnv(const QString &name, const QString &value);
/**
* Starts a service based on the desktop path of the service, e.g.
* "Applications/konqueror.desktop" or "/home/user/bla/myfile.desktop"
* Starts a service based on the MIME type of the URL, the MIME type is automatically
* determined
*
* @param name The path of the desktop file
* @param URL If not empty this URL is passed to the service
* @param error On failure, @p error contains a description of the error that occurred.
* If the pointer is null, the argument will be ignored
* @param startup_id For app startup notification, "0" for none
* @param url The URL to start service for
* @param window Window to use for error reporting and job delegation
* @param temp Whether the URL is temporary file or not
* @return an error code indicating success (== 0) or failure (> 0).
*/
int startServiceByDesktopPath(const QString &name, const QString &URL,
QString *error = nullptr,
const QByteArray &startup_id = QByteArray());
bool startServiceForUrl(const QString &url, QWidget *window = nullptr, bool temp = false);
/**
* Starts a service based on the desktop path of the service, e..g.
* "Applications/konqueror.desktop" or "/home/user/bla/myfile.desktop"
*
* @param name The path of the desktop file
* @param URLs If not empty these URLs will be passed to the service
* @param error On failure, @p error contains a description of the error that occurred.
* If the pointer is null, the argument will be ignored
* @param startup_id For app startup notification, "0" for none
* @return an error code indicating success (== 0) or failure (> 0).
*/
int startServiceByDesktopPath(const QString &name, const QStringList &URLs = QStringList(),
QString *error = nullptr,
const QByteArray &startup_id = QByteArray());
/**
* Starts a service based on the desktop name of the service, e.g. "konqueror"
* Starts a service based on the desktop name or entry path of the service, e.g. "konqueror"
*
* @param name The desktop name of the service
* @param URL If not empty this URL is passed to the service
* @param error On failure, @p error contains a description of the error that occurred.
* If the pointer is null, the argument will be ignored
* @param startup_id For app startup notification, "0" for none
* @param urls If not empty these URLs will be passed to the service
* @param window Window to use for error reporting and job delegation
* @param temp Whether any of the URLs is temporary file or not
* @return an error code indicating success (== 0) or failure (> 0)
*/
int startServiceByDesktopName(const QString &name, const QString &URL,
QString *error = nullptr,
const QByteArray &startup_id = QByteArray());
bool startServiceByStorageId(const QString &name, const QStringList &urls = QStringList(),
QWidget *window = nullptr, bool temp = false);
/**
* Starts a service based on the desktop name of the service, e.g. "konqueror"
*
* @param name The desktop name of the service
* @param URLs If not empty these URLs will be passed to the service
* @param error On failure, @p error contains a description of the error that occurred.
* If the pointer is null, the argument will be ignored
* @param startup_id For app startup notification, "0" for none
* @return an error code indicating success (== 0) or failure (> 0)
*/
int startServiceByDesktopName(const QString &name, const QStringList &URLs = QStringList(),
QString *error = nullptr,
const QByteArray &startup_id = QByteArray());
/**
* Starts a program via kdeinit.
* Starts a program.
*
* @param name Name of the program to start
* @param args Arguments to pass to the program
* @param error On failure, @p error contains a description of the error that occurred
* If the pointer is null, the argument will be ignored
* @param startup_id For app startup notification, "0" for none
* @param window Window to use for error reporting and job delegation
* @param temp Whether argument is temporary file or not
* @return an error code indicating success (== 0) or failure (> 0)
*/
int kdeinitExec(const QString &name, const QStringList &args = QStringList(),
QString *error = nullptr, const QByteArray &startup_id = QByteArray());
/**
* Starts a program via kdeinit and wait for it to finish, it behaves similar to the system()
* function.
*
* @param name Name of the program to start
* @param args Arguments to pass to the program
* @param error On failure, @p error contains a description of the error that occurred
* If the pointer is null, the argument will be ignored
* @param startup_id For app startup notification, "0" for none
* @return an error code indicating success (== 0) or failure (> 0)
*/
int kdeinitExecWait(const QString &name, const QStringList &args = QStringList(),
QString *error = nullptr, const QByteArray &startup_id = QByteArray());
bool startProgram(const QString &name, const QStringList &args = QStringList(),
QWidget *window = nullptr, bool temp = false);
private:
Q_DISABLE_COPY(KToolInvocation);
@ -217,10 +157,9 @@ private:
/**
* @internal
*/
int startServiceInternal(const char *_function,
const QString &name, const QStringList &URLs,
QString *error,
const QByteArray &startup_id,
bool startServiceInternal(const char *_function,
const QString &name, const QStringList &urls,
QWidget *window, const bool temp,
const QString &workdir = QString());
QDBusInterface *klauncherIface;

View file

@ -110,8 +110,7 @@ static QStringList splitEmailAddressList( const QString & aStr )
void KToolInvocation::invokeMailer(const QString &to, const QString &cc,
const QString &subject, const QString &body,
const QStringList &attachURLs,
const QByteArray &startup_id)
const QStringList &attachURLs)
{
KConfig config(QString::fromLatin1("emaildefaults"));
KConfigGroup profileGrp(&config, "General");
@ -202,90 +201,43 @@ void KToolInvocation::invokeMailer(const QString &to, const QString &cc,
}
}
QString error;
// TODO this should check if cmd has a .desktop file, and use data from it, together
// with sending more ASN data
if (kdeinitExec(cmd, cmdTokens, &error, startup_id) != 0) {
KMessageBox::queuedMessageBox(
nullptr, KMessageBox::Error,
i18n("Could not launch the mail client:\n\n%1", error),
i18n("Could not launch Mail Client")
);
}
startProgram(cmd, cmdTokens);
}
void KToolInvocation::invokeBrowser(const QString &url, const QByteArray& startup_id)
void KToolInvocation::invokeBrowser(const QString &url)
{
QStringList args;
args << url;
QString error;
// This method should launch a webbrowser, preferably without doing a mimetype
// check first, like KRun (i.e. kde-open) would do.
// check first like kde-open would do.
const KService::Ptr htmlApp = KMimeTypeTrader::self()->preferredService(QLatin1String("text/html"));
if (htmlApp) {
QString error;
const int err = startServiceByDesktopPath(htmlApp->entryPath(), url, &error, startup_id);
if (err != 0) {
KMessageBox::queuedMessageBox(
nullptr, KMessageBox::Error,
// TODO: i18n("Could not launch %1:\n\n%2", htmlApp->exec(), error),
i18n("Could not launch the browser:\n\n%1", error),
i18n("Could not launch Browser")
);
}
startServiceByStorageId(htmlApp->entryPath(), QStringList() << url);
return;
}
QString exe = KStandardDirs::findExe(QString::fromLatin1("kde-open"));
if (exe.isEmpty()) {
exe = KStandardDirs::findExe(QString::fromLatin1("xdg-open"));
}
if (kdeinitExec(exe, args, &error, startup_id) != 0) {
KMessageBox::queuedMessageBox(
nullptr, KMessageBox::Error,
// TODO: i18n("Could not launch %1:\n\n%2", exe, error),
i18n("Could not launch the browser:\n\n%1", error),
i18n("Could not launch Browser")
);
}
// if one cannot be found then launch the service for the URL MIME type
startServiceForUrl(url);
}
void KToolInvocation::invokeTerminal(const QString &command,
const QString &workdir,
const QByteArray &startup_id)
const QString &workdir)
{
KConfigGroup confGroup( KGlobal::config(), "General" );
QString exec = confGroup.readPathEntry("TerminalApplication", QString::fromLatin1("konsole"));
QStringList cmdTokens = KShell::splitArgs(exec);
if (!command.isEmpty()) {
if (exec == QLatin1String("konsole")) {
exec += QString::fromLatin1(" --noclose");
} else if (exec == QLatin1String("xterm")) {
exec += QString::fromLatin1(" -hold");
cmdTokens << QString::fromLatin1("--noclose");
} else if (exec.startsWith(QLatin1String("xterm"))) {
cmdTokens << QString::fromLatin1("-hold");
}
exec += QString::fromLatin1(" -e ") + command;
cmdTokens << QString::fromLatin1("-e") << command;
}
QStringList cmdTokens = KShell::splitArgs(exec);
QString cmd = cmdTokens.takeFirst();
if (exec == QLatin1String("konsole") && !workdir.isEmpty()) {
cmdTokens << QString::fromLatin1("--workdir");
cmdTokens << workdir;
// For other terminals like xterm, we'll simply change the working
// directory before launching them, see below.
}
QString error;
if (self()->startServiceInternal("kdeinit_exec_with_workdir",
cmd, cmdTokens, &error, startup_id, workdir)) {
KMessageBox::queuedMessageBox(
nullptr, KMessageBox::Error,
i18n("Could not launch the terminal client:\n\n%1", error),
i18n("Could not launch Terminal Client")
startServiceInternal(
"start_program_with_workdir", cmd, cmdTokens, nullptr, false, workdir
);
}
}

View file

@ -22,47 +22,50 @@
#include "kautostart.h"
#include "kshell.h"
#include "kconfiggroup.h"
#include "kmessagebox.h"
#include "kmimetype.h"
#include "kmimetypetrader.h"
#include "kprotocolmanager.h"
#include "kio/netaccess.h"
#include "kio/udsentry.h"
#include "kdebug.h"
#include <QDir>
#include <QApplication>
#include <QThread>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
static const int s_eventstime = 250;
static const int s_sleeptime = 50;
// NOTE: keep in sync with:
// kde-workspace/kwin/effects/startupfeedback/startupfeedback.cpp
// kde-workspace/kcontrol/launch/kcmlaunch.cpp
static const qint64 s_startuptimeout = 10; // 10sec
// klauncher is the last process to quit in a session (see kde-workspace/startkde.cmake) so 5sec
// for each child process is more than enough
// klauncher is the last process to quit in a session so 5sec for each child process is more than
// enough
static const qint64 s_processtimeout = 5000; // 5sec
static inline bool isPIDAlive(const pid_t pid)
static inline void removeTemp(const bool temp, const QStringList &args)
{
return (::kill(pid, 0) >= 0);
if (temp) {
foreach (const QString &arg, args) {
if (QFile::exists(arg)) {
kDebug() << "removing temporary file" << arg;
QFile::remove(arg);
}
}
}
}
static inline int getExitStatus(const pid_t pid)
static inline void showError(const QString &error, const quint64 window)
{
int pidstate = 0;
::waitpid(pid, &pidstate, WNOHANG);
return WEXITSTATUS(pidstate);
}
static inline bool isASNValid(const QByteArray &asn)
{
return (!asn.isEmpty() && asn != "0");
KMessageBox::errorWId(static_cast<WId>(window), error);
}
KLauncherProcess::KLauncherProcess(QObject *parent)
: QProcess(parent),
m_kstartupinfo(nullptr),
m_startuptimer(nullptr)
m_startuptimer(nullptr),
m_temp(false)
{
connect(
this, SIGNAL(stateChanged(QProcess::ProcessState)),
@ -70,13 +73,18 @@ KLauncherProcess::KLauncherProcess(QObject *parent)
);
}
void KLauncherProcess::setupStartup(const QByteArray &startup_id, const QString &appexe,
const KService::Ptr kservice, const qint64 timeout)
KLauncherProcess::~KLauncherProcess()
{
removeTemp(m_temp, m_args);
}
void KLauncherProcess::setupStartup(const QString &appexe, const KService::Ptr kservice,
const qint64 timeout, const bool temp, const QStringList &args)
{
Q_ASSERT(m_kstartupinfoid.none() == true);
QByteArray startupwmclass;
if (KRun::checkStartupNotify(kservice.data(), &startupwmclass)) {
m_kstartupinfoid.initId(!isASNValid(startup_id) ? KStartupInfo::createNewStartupId() : startup_id);
m_kstartupinfoid.initId(KStartupInfo::createNewStartupId());
kDebug() << "setting up ASN for" << kservice->entryPath() << m_kstartupinfoid.id();
m_kstartupinfodata.setHostname();
m_kstartupinfodata.setBin(QFileInfo(appexe).fileName());
@ -88,19 +96,11 @@ void KLauncherProcess::setupStartup(const QByteArray &startup_id, const QString
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;
}
m_temp = temp;
m_args = args;
}
void KLauncherProcess::slotProcessStateChanged(QProcess::ProcessState state)
@ -282,32 +282,18 @@ void KLauncherAdaptor::cleanup()
}
}
int KLauncherAdaptor::kdeinit_exec(const QString &app, const QStringList &args, const QStringList &envs, const QString& startup_id)
bool KLauncherAdaptor::start_program(const QString &app, const QStringList &args,
const QStringList &envs, quint64 window, bool temp)
{
return kdeinit_exec_with_workdir(app, args, envs, startup_id, QDir::currentPath());
return start_program_with_workdir(app, args, envs, window, temp, QDir::currentPath());
}
int KLauncherAdaptor::kdeinit_exec_wait(const QString &app, const QStringList &args, const QStringList &envs, const QString &startup_id)
bool KLauncherAdaptor::start_program_with_workdir(const QString &app, const QStringList &args,
const QStringList &envs, quint64 window,
bool temp, const QString &workdir)
{
qint64 pid = 0;
int result = startProgram(app, args, envs, startup_id, QDir::currentPath(), pid, m_startuptimeout);
if (result != KLauncherAdaptor::NoError) {
return result;
}
kDebug() << "waiting for" << pid;
while (isPIDAlive(pid)) {
QApplication::processEvents(QEventLoop::AllEvents, s_eventstime);
QThread::msleep(s_sleeptime);
}
result = getExitStatus(pid);
kDebug() << "done waiting for" << pid << ", exit status" << result;
return result;
}
int KLauncherAdaptor::kdeinit_exec_with_workdir(const QString &app, const QStringList &args, const QStringList &envs, const QString &startup_id, const QString &workdir)
{
qint64 pid = 0;
return startProgram(app, args, envs, startup_id, workdir, pid, m_startuptimeout);
return startProgram(app, args, envs, window, temp, workdir, pid, m_startuptimeout);
}
void KLauncherAdaptor::setLaunchEnv(const QString &name, const QString &value)
@ -320,31 +306,31 @@ void KLauncherAdaptor::setLaunchEnv(const QString &name, const QString &value)
m_environment.insert(name, value);
}
int KLauncherAdaptor::start_service_by_desktop_name(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id)
{
KService::Ptr kservice = KService::serviceByDesktopName(serviceName);
if (!kservice) {
kWarning() << "invalid service name" << serviceName;
return KLauncherAdaptor::ServiceError;
}
return start_service_by_desktop_path(kservice->entryPath(), urls, envs, startup_id);
}
int KLauncherAdaptor::start_service_by_desktop_path(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id)
bool KLauncherAdaptor::start_service_by_storage_id(const QString &serviceName,
const QStringList &urls,
const QStringList &envs, quint64 window,
bool temp)
{
KService::Ptr kservice = KService::serviceByStorageId(serviceName);
if (!kservice) {
kWarning() << "invalid service path" << serviceName;
return KLauncherAdaptor::ServiceError;
kError() << "invalid service path" << serviceName;
showError(i18n("Invalid service: %1", serviceName), window);
removeTemp(temp, urls);
return false;
}
// TODO: start one service for each
if (urls.size() > 1 && !kservice->allowMultipleFiles()) {
kWarning() << "service does not support multiple files" << serviceName;
return KLauncherAdaptor::ServiceError;
kError() << "service does not support multiple files" << serviceName;
showError(i18n("Service does not support multiple files: %1", serviceName), window);
return false;
}
// TODO: for applications which do not support URLs - download
QStringList programandargs = KRun::processDesktopExec(*kservice, urls);
if (programandargs.isEmpty()) {
kWarning() << "could not process service" << kservice->entryPath();
return KLauncherAdaptor::ArgumentsError;
kError() << "could not process service" << kservice->entryPath();
showError(i18n("Could not process service: %1", serviceName), window);
removeTemp(temp, urls);
return false;
}
QString programworkdir = kservice->path();
if (programworkdir.isEmpty()) {
@ -353,7 +339,52 @@ int KLauncherAdaptor::start_service_by_desktop_path(const QString &serviceName,
kDebug() << "starting" << kservice->entryPath() << urls;
const QString program = programandargs.takeFirst();
qint64 pid = 0;
return startProgram(program, programandargs, envs, QString(), programworkdir, pid, m_startuptimeout, kservice);
return startProgram(program, programandargs, envs, window, temp, programworkdir, pid, m_startuptimeout, kservice);
}
bool KLauncherAdaptor::start_service_by_url(const QString &url, const QStringList &envs,
quint64 window, bool temp)
{
const KUrl realurl = KUrl(url);
QString urlmimetype;
if (realurl.isLocalFile()) {
KMimeType::Ptr kmimetype = KMimeType::findByUrl(realurl);
if (kmimetype) {
urlmimetype = kmimetype->name();
}
} else {
KIO::UDSEntry kioudsentry;
// TODO: unless WId is passed around QWidget::find() will not find external windows
if (!KIO::NetAccess::stat(realurl, kioudsentry, QWidget::find(static_cast<WId>(window)))) {
kWarning() << "could not stat URL for MIME type" << url;
urlmimetype = KProtocolManager::defaultMimetype(realurl);
} else {
urlmimetype = kioudsentry.stringValue(KIO::UDSEntry::UDS_MIME_TYPE);
}
}
if (urlmimetype.isEmpty()) {
kError() << "invalid MIME type for path" << url;
showError(i18n("Could not determine the MIME type of: %1", url), window);
removeTemp(temp, QStringList() << url);
return false;
}
kDebug() << "MIME type of" << url << "is" << urlmimetype;
if (KRun::isExecutableFile(realurl, urlmimetype)) {
kDebug() << "execuable file" << url;
KMessageBox::sorryWId(
static_cast<WId>(window),
i18n("The file <tt>%1</tt> is an executable program.<br/>For safety it will not be started.", Qt::escape(realurl.prettyUrl()))
);
return false;
}
KService::Ptr kservice = KMimeTypeTrader::self()->preferredService(urlmimetype);
if (!kservice) {
kError() << "invalid service for MIME type" << urlmimetype;
showError(i18n("No service can handle: %1", urlmimetype), window);
removeTemp(temp, QStringList() << url);
return false;
}
return start_service_by_storage_id(kservice->entryPath(), QStringList() << url, envs, window, temp);
}
#ifdef KLAUNCHER_DEBUG
@ -384,14 +415,16 @@ 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,
const qint64 timeout, const KService::Ptr kservice)
bool KLauncherAdaptor::startProgram(const QString &app, const QStringList &args, const QStringList &envs,
const quint64 window, const bool temp, const QString &workdir,
qint64 &pid, const qint64 timeout, const KService::Ptr kservice)
{
const QString appexe = findExe(app);
if (appexe.isEmpty()) {
kWarning() << "could not find" << app;
return KLauncherAdaptor::FindError;
kError() << "could not find" << app;
showError(i18n("Could not find the application: %1", app), window);
removeTemp(temp, args);
return false;
}
KLauncherProcess* process = new KLauncherProcess(this);
@ -411,7 +444,7 @@ int KLauncherAdaptor::startProgram(const QString &app, const QStringList &args,
}
process->setProcessEnvironment(processenv);
process->setWorkingDirectory(workdir);
process->setupStartup(startup_id.toLatin1(), appexe, kservice, timeout);
process->setupStartup(appexe, kservice, timeout, temp, args);
kDebug() << "starting" << appexe << args << envs << workdir;
process->start(appexe, args);
while (process->state() == QProcess::Starting) {
@ -420,11 +453,11 @@ int KLauncherAdaptor::startProgram(const QString &app, const QStringList &args,
}
if (process->error() == QProcess::FailedToStart || process->error() == QProcess::Crashed) {
kWarning() << "could not start" << appexe;
return KLauncherAdaptor::ExecError;
return false;
}
pid = process->pid();
return KLauncherAdaptor::NoError;
return true;
}
#include "moc_klauncher_adaptor.cpp"

View file

@ -33,9 +33,10 @@ class KLauncherProcess : public QProcess
Q_OBJECT
public:
explicit KLauncherProcess(QObject *parent);
~KLauncherProcess();
void setupStartup(const QByteArray &startup_id, const QString &appexe,
const KService::Ptr kservice, const qint64 timeout);
void setupStartup(const QString &appexe, const KService::Ptr kservice, const qint64 timeout,
const bool temp, const QStringList &args);
private Q_SLOTS:
void slotProcessStateChanged(QProcess::ProcessState state);
@ -53,6 +54,8 @@ private:
QTimer* m_startuptimer;
KStartupInfoId m_kstartupinfoid;
KStartupInfoData m_kstartupinfodata;
bool m_temp;
QStringList m_args;
};
// Adaptor class for interface org.kde.KLauncher
@ -61,14 +64,6 @@ class KLauncherAdaptor: public QDBusAbstractAdaptor
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.KLauncher")
public:
enum KLauncherError {
NoError = 0,
ServiceError = -1,
FindError = -2,
ArgumentsError = -3,
ExecError = -4
};
KLauncherAdaptor(QObject *parent);
~KLauncherAdaptor();
@ -83,11 +78,15 @@ public Q_SLOTS:
// used by KToolInvocation
void setLaunchEnv(const QString &name, const QString &value);
int kdeinit_exec(const QString &app, const QStringList &args, const QStringList &envs, const QString &startup_id);
int kdeinit_exec_wait(const QString &app, const QStringList &args, const QStringList &envs, const QString &startup_id);
int kdeinit_exec_with_workdir(const QString &app, const QStringList &args, const QStringList &envs, const QString &startup_id, const QString &workdir);
int start_service_by_desktop_name(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id);
int start_service_by_desktop_path(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id);
bool start_program(const QString &app, const QStringList &args, const QStringList &envs,
quint64 window, bool temp);
bool start_program_with_workdir(const QString &app, const QStringList &args,
const QStringList &envs, quint64 window, bool temp,
const QString &workdir);
bool start_service_by_storage_id(const QString &serviceName, const QStringList &urls,
const QStringList &envs, quint64 window, bool temp);
bool start_service_by_url(const QString &url, const QStringList &envs, quint64 window,
bool temp);
// for debugging
#ifdef KLAUNCHER_DEBUG
@ -104,8 +103,8 @@ private Q_SLOTS:
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,
bool startProgram(const QString &app, const QStringList &args, const QStringList &envs,
const quint64 window, const bool temp, const QString &workdir, qint64 &pid,
const qint64 timeout, const KService::Ptr kservice = KService::Ptr(nullptr));
QProcessEnvironment m_environment;

View file

@ -35,7 +35,7 @@
#include <kmenu.h>
#include <kstandardshortcut.h>
#include <kstandardaction.h>
#include <krun.h>
#include <ktoolinvocation.h>
#include <kactioncollection.h>
/********************************************************************/
@ -638,7 +638,7 @@ KBookmarkAction::KBookmarkAction(const KBookmark &bk, KBookmarkOwner *owner, QOb
void KBookmarkAction::slotSelected(Qt::MouseButtons mb, Qt::KeyboardModifiers km)
{
if (!m_pOwner) {
new KRun(bookmark().url(), (QWidget*)0);
KToolInvocation::self()->startServiceForUrl(bookmark().url().url());
} else {
m_pOwner->openBookmark(bookmark(), mb, km);
}

View file

@ -26,6 +26,7 @@
#include "kfileitem.h"
#include "kimagefilepreview.h"
#include "knewfilemenu.h"
#include "ktoolinvocation.h"
#include <config-kfile.h>
@ -71,7 +72,6 @@
#include <kio/previewjob.h>
#include <kio/renamedialog.h>
#include <kfilepreviewgenerator.h>
#include <krun.h>
#include <kpropertiesdialog.h>
#include <kstandardshortcut.h>
#include <kde_file.h>
@ -649,7 +649,7 @@ void KDirOperator::Private::_k_toggleInlinePreviews(bool show)
void KDirOperator::Private::_k_slotOpenFileManager()
{
new KRun(currUrl, parent);
KToolInvocation::self()->startServiceForUrl(currUrl.url(), parent);
}
void KDirOperator::Private::_k_slotSortByName()

View file

@ -78,6 +78,7 @@
#include "kpreviewprops.h"
#include "kmetaprops.h"
#include "krun.h"
#include "ktoolinvocation.h"
#include "kvbox.h"
#include "kacl.h"
#include "kconfiggroup.h"
@ -1100,14 +1101,11 @@ void KFilePropsPlugin::slotEditFileType()
} else {
mime = d->mimeType;
}
QString keditfiletype = QString::fromLatin1("keditfiletype");
KRun::runCommand(keditfiletype
#ifdef Q_WS_X11
+ " --parent " + QString::number( (ulong)properties->window()->winId())
#endif
+ " --caption " + KShell::quoteArg(KGlobal::caption())
+ ' ' + KShell::quoteArg(mime),
keditfiletype, keditfiletype /*unused*/, properties->window());
QStringList args;
args << "--parent" << QString::number( (ulong)properties->window()->winId());
args << "--caption" << KGlobal::caption();
args << mime;
KToolInvocation::self()->startProgram(QLatin1String("keditfiletype"), args, properties->window());
}
void KFilePropsPlugin::slotIconChanged()
@ -3256,9 +3254,7 @@ void KDesktopPropsPlugin::slotBrowseExec()
return;
}
QString path = f.toLocalFile();
path = KShell::quoteArg(path);
d->w->commandEdit->setText(path);
d->w->commandEdit->setText(KShell::quoteArg(f.toLocalFile()));
}
void KDesktopPropsPlugin::slotAdvanced()

View file

@ -18,10 +18,11 @@
#include "kautomount.h"
#include <krun.h>
#include <ktoolinvocation.h>
#include <kdirnotify.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <kurl.h>
#include <kdebug.h>
#include <QDBusInterface>
@ -112,10 +113,9 @@ void KAutoMountPrivate::slotFinished(QDBusPendingCallWatcher *watcher)
return;
}
const KUrl url(m_mountPoint);
// kDebug(7015) << "KAutoMount: m_strDevice=" << m_strDevice << " -> mountpoint=" << m_mountPoint;
if (m_bShowFilemanagerWindow) {
KRun::runUrl(url, "inode/directory", nullptr /*TODO - window*/);
KToolInvocation::self()->startServiceForUrl(m_mountPoint);
}
// Update the desktop file which is used for mount/unmount (icon change)

View file

@ -21,24 +21,24 @@
#include "krun.h"
#include "kautomount.h"
#include "kmimetype.h"
#include "kmessagebox.h"
#include "kdirnotify.h"
#include "kmountpoint.h"
#include "kstandarddirs.h"
#include "kdesktopfile.h"
#include "kconfiggroup.h"
#include "ktoolinvocation.h"
#include "klocale.h"
#include "kservice.h"
#include "kdebug.h"
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusReply>
#include <kmessagebox.h>
#include <kdirnotify.h>
#include <kmountpoint.h>
#include <kstandarddirs.h>
#include <kdesktopfile.h>
#include <kconfiggroup.h>
#include <klocale.h>
#include <kservice.h>
#include <kdebug.h>
enum BuiltinServiceType { ST_MOUNT = 0x0E1B05B0, ST_UNMOUNT = 0x0E1B05B1 }; // random numbers
static bool runFSDevice( const KUrl& _url, const KDesktopFile &cfg );
static bool runApplication( const KUrl& _url, const QString & _serviceFile );
static bool runLink( const KUrl& _url, const KDesktopFile &cfg );
bool KDesktopFileActions::run( const KUrl& u, bool _is_local )
@ -64,7 +64,7 @@ bool KDesktopFileActions::run( const KUrl& u, bool _is_local )
return runFSDevice( u, cfg );
else if ( cfg.hasApplicationType()
|| (cfg.readType() == "Service" && !cfg.desktopGroup().readEntry("Exec").isEmpty())) // for kio_settings
return runApplication( u, u.toLocalFile() );
return KToolInvocation::self()->startServiceByStorageId( u.toLocalFile() );
else if ( cfg.hasLinkType() )
return runLink( u, cfg );
@ -94,9 +94,8 @@ static bool runFSDevice( const KUrl& _url, const KDesktopFile &cfg )
KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByDevice( dev );
// Is the device already mounted ?
if (mp) {
KUrl mpURL(mp->mountPoint());
// Open a new window
retval = KRun::runUrl( mpURL, QLatin1String("inode/directory"), 0 /*TODO - window*/ );
retval = KToolInvocation::self()->startServiceForUrl(mp->mountPoint());
} else {
KConfigGroup cg = cfg.desktopGroup();
bool ro = cg.readEntry("ReadOnly", false);
@ -108,18 +107,6 @@ static bool runFSDevice( const KUrl& _url, const KDesktopFile &cfg )
return retval;
}
static bool runApplication( const KUrl& , const QString & _serviceFile )
{
KService s( _serviceFile );
if ( !s.isValid() )
// The error message was already displayed, so we can just quit here
// ### KDE4: is this still the case?
return false;
KUrl::List lst;
return KRun::run( s, lst, 0 /*TODO - window*/ );
}
static bool runLink( const KUrl& _url, const KDesktopFile &cfg )
{
QString u = cfg.readUrl();
@ -132,17 +119,19 @@ static bool runLink( const KUrl& _url, const KDesktopFile &cfg )
return false;
}
KUrl url ( u );
KRun* run = new KRun(url,(QWidget*)0);
// X-KDE-LastOpenedWith holds the service desktop entry name that
// was should be preferred for opening this URL if possible.
// should be preferred for opening this URL if possible.
// This is used by the Recent Documents menu for instance.
QString lastOpenedWidth = cfg.desktopGroup().readEntry( "X-KDE-LastOpenedWith" );
if ( !lastOpenedWidth.isEmpty() )
run->setPreferredService( lastOpenedWidth );
return false;
if ( !lastOpenedWidth.isEmpty() ) {
KService::Ptr service = KService::serviceByStorageId(lastOpenedWidth);
if (!service.isNull()) {
return KToolInvocation::self()->startServiceByStorageId(service->entryPath(), QStringList() << u, nullptr);
} else {
kWarning() << "Last opened with service is not valid" << lastOpenedWidth;
}
}
return KToolInvocation::self()->startServiceForUrl(u, nullptr);
}
QList<KServiceAction> KDesktopFileActions::builtinServices( const KUrl& _url )
@ -291,7 +280,14 @@ void KDesktopFileActions::executeService( const KUrl::List& urls, const KService
}
} else {
kDebug() << action.name() << "first url's path=" << urls.first().toLocalFile() << "exec=" << action.exec();
KRun::run( action.exec(), urls, 0, action.text(), action.icon());
KService actionService(action.text(), action.exec(), action.icon());
QStringList actionArgs = KRun::processDesktopExec(actionService, urls);
if (actionArgs.isEmpty()) {
kWarning() << "empty service command" << action.text() << action.exec();
} else {
const QString actionProgram = actionArgs.takeFirst();
KToolInvocation::self()->startProgram(actionProgram, actionArgs);
}
// The action may update the desktop file. Example: eject unmounts (#5129).
org::kde::KDirNotify::emitFilesChanged( urls.toStringList() );
}

View file

@ -90,7 +90,7 @@ namespace KDesktopFileActions
* @param _url the url to run
* @param _is_local true if the URL is local, false otherwise
* @return true on success and false on failure.
* @see KRun::runUrl
* @see KRun, KToolInvocation
*/
KIO_EXPORT bool run( const KUrl& _url, bool _is_local );
}

View file

@ -42,6 +42,7 @@
#include <kmountpoint.h>
#include <kconfiggroup.h>
#include <kuser.h>
#include <ktoolinvocation.h>
#include <kfilesystemtype_p.h>
static bool isKDirShare(const QString &dirpath)
@ -993,7 +994,7 @@ void KFileItem::run(QWidget *parentWidget) const
kWarning() << "null item";
return;
}
(void) new KRun(targetUrl(), parentWidget, d->m_fileMode, d->m_bIsLocalUrl);
KToolInvocation::self()->startServiceForUrl(targetUrl().url(), parentWidget);
}
bool KFileItem::cmp(const KFileItem &item) const

View file

@ -23,7 +23,6 @@
#include <kaction.h>
#include <krun.h>
#include <kmimetypetrader.h>
#include <kdebug.h>
#include <kdesktopfileactions.h>
#include <kmenu.h>
#include <klocale.h>
@ -33,6 +32,8 @@
#include <kicon.h>
#include <kstandarddirs.h>
#include <kservicetypetrader.h>
#include <ktoolinvocation.h>
#include <kdebug.h>
#include <QFile>
#include <QtCore/qalgorithms.h>
@ -577,7 +578,7 @@ void KFileItemActionsPrivate::slotRunPreferredApplications()
const QStringList mimeTypeList = listMimeTypes(fileItems);
const QStringList serviceIdList = listPreferredServiceIds(mimeTypeList, m_traderConstraint);
foreach (const QString serviceId, serviceIdList) {
foreach (const QString &serviceId, serviceIdList) {
KFileItemList serviceItems;
foreach (const KFileItem& item, fileItems) {
const KService::Ptr serv = preferredService(item.mimetype(), m_traderConstraint);
@ -597,7 +598,9 @@ void KFileItemActionsPrivate::slotRunPreferredApplications()
KRun::displayOpenWithDialog(serviceItems.urlList(), m_parentWidget);
continue;
}
KRun::run(*servicePtr, serviceItems.urlList(), m_parentWidget);
KToolInvocation::self()->startServiceByStorageId(
servicePtr->entryPath(), serviceItems.urlList().toStringList(), m_parentWidget
);
}
}
@ -628,7 +631,9 @@ void KFileItemActionsPrivate::slotRunApplication(QAction* act)
KService::Ptr app = act->data().value<KService::Ptr>();
Q_ASSERT(app);
if (app) {
KRun::run(*app, m_props.urlList(), m_parentWidget);
KToolInvocation::self()->startServiceByStorageId(
app->entryPath(), m_props.urlList().toStringList(), m_parentWidget
);
}
}

View file

@ -21,7 +21,7 @@
#include <klocale.h>
#include <kmimetype.h>
#include <kshell.h>
#include <krun.h>
#include <ktoolinvocation.h>
#include <ksycoca.h>
#include <QLabel>
@ -203,12 +203,11 @@ void KMimeTypeChooserPrivate::_k_editMimeType()
// thanks to libkonq/konq_operations.cc
q->connect(KSycoca::self(), SIGNAL(databaseChanged(QStringList)),
q, SLOT(_k_slotSycocaDatabaseChanged(QStringList)));
QString keditfiletype = QString::fromLatin1("keditfiletype");
KRun::runCommand( keditfiletype
+ " --parent " + QString::number( (ulong)q->window()->winId())
+ " --caption " + KShell::quoteArg(KGlobal::caption())
+ ' ' + KShell::quoteArg(mt),
keditfiletype, keditfiletype /*unused*/, q->window());
QStringList args;
args << "--parent" << QString::number((ulong)q->window()->winId());
args << "--caption" << KGlobal::caption();
args << mt;
KToolInvocation::self()->startProgram(QLatin1String("keditfiletype"), args, q->window());
}
void KMimeTypeChooserPrivate::_k_slotCurrentChanged(QTreeWidgetItem* item)

File diff suppressed because it is too large Load diff

View file

@ -1,12 +1,10 @@
// -*- mode: c++; c-basic-offset: 2 -*-
/* This file is part of the KDE project
Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
Copyright (C) 2006 David Faure <faure@kde.org>
/*
This file is part of the KDE libraries
Copyright (C) 2024 Ivailo Monev <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
License version 2, as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@ -24,19 +22,11 @@
#include <kio/kio_export.h>
#include <QtCore/QObject>
#include <QtCore/QTimer>
#include <QtCore/QString>
#include <sys/types.h>
#include <QString>
#include <kurl.h>
#include <kservice.h>
class KService;
class KStartupInfo;
class KJob;
namespace KIO
{
class Job;
}
class KRunPrivate;
/**
* To open files with their associated applications in KDE, use KRun.
@ -56,249 +46,28 @@ class Job;
*
* @short Opens files with their associated applications in KDE
*/
class KIO_EXPORT KRun : public QObject
class KIO_EXPORT KRun
{
Q_OBJECT
public:
/**
* @param url the URL of the file or directory to 'run'
*
* @param window
* The top-level widget of the app that invoked this object.
* It is used to make sure private information like passwords
* are properly handled per application.
*
* @param mode The @p st_mode field of <tt>struct stat</tt>. If
* you don't know this set it to 0.
*
* @param isLocalFile
* If this parameter is set to @p false then @p url is
* examined to find out whether it is a local URL or
* not. This flag is just used to improve speed, since the
* function KUrl::isLocalFile is a bit slow.
*
* @param showProgressInfo
* Whether to show progress information when determining the
* type of the file (i.e. when using KIO::stat and KIO::mimetype)
* Before you set this to false to avoid a dialog box, think about
* a very slow FTP server...
* It is always better to provide progress info in such cases.
* @param asn
* Application startup notification id, if available (otherwise "").
*/
KRun(const KUrl& url, QWidget* window, mode_t mode = 0,
bool isLocalFile = false, bool showProgressInfo = true,
const QByteArray& asn = QByteArray());
/**
* Destructor. Don't call it yourself, since a KRun object auto-deletes
* itself.
*/
virtual ~KRun();
/**
* Abort this KRun. This kills any jobs launched by it,
* and leads to deletion if auto-deletion is on.
* This is much safer than deleting the KRun (in case it's
* currently showing an error dialog box, for instance)
*/
void abort();
/**
* Returns true if the KRun instance has an error.
* @return true when an error occurred
* @see error()
*/
bool hasError() const;
/**
* Returns true if the KRun instance has finished.
* @return true if the KRun instance has finished
* @see finished()
*/
bool hasFinished() const;
/**
* Checks whether auto delete is activated.
* Auto-deletion causes the KRun instance to delete itself
* when it finished its task.
* By default auto deletion is on.
* @return true if auto deletion is on, false otherwise
*/
bool autoDelete() const;
/**
* Enables or disabled auto deletion.
* Auto deletion causes the KRun instance to delete itself
* when it finished its task. If you allocate the KRun
* object on the stack you must disable auto deletion.
* By default auto deletion is on.
* @param b true to enable auto deletion, false to disable
*/
void setAutoDelete(bool b);
/**
* Set the preferred service for opening this URL, after
* its mimetype will have been found by KRun. IMPORTANT: the service is
* only used if its configuration says it can handle this mimetype.
* This is used for instance for the X-KDE-LastOpenedWith key in
* the recent documents list.
* @param desktopEntryName the desktopEntryName of the service, e.g. "kate".
*/
void setPreferredService(const QString& desktopEntryName);
/**
* Sets whether executables, .desktop files or shell scripts should
* be run by KRun. This is enabled by default.
* @param b whether to run executable files or not.
* @see isExecutable()
*/
void setRunExecutables(bool b);
/**
* Sets the file name to use in the case of downloading the file to a tempfile
* in order to give to a non-url-aware application. Some apps rely on the extension
* to determine the mimetype of the file. Usually the file name comes from the URL,
* but in the case of the HTTP Content-Disposition header, we need to override the
* file name.
*/
void setSuggestedFileName(const QString& fileName);
/**
* Suggested file name given by the server (e.g. HTTP content-disposition)
*/
QString suggestedFileName() const;
/**
* Associated window, as passed to the constructor
* @since 4.9.3
*/
QWidget* window() const;
/**
* Open a list of URLs with a certain service (application).
*
* @param service the service to run
* @param urls the list of URLs, can be empty (app launched
* without argument)
* @param window The top-level widget of the app that invoked this object.
* @param tempFiles if true and urls are local files, they will be deleted
* when the application exits.
* @param suggestedFileName see setSuggestedFileName
* @param asn Application startup notification id, if any (otherwise "").
* @return @c true on success, @c false on error
*/
static bool run(const KService& service, const KUrl::List& urls, QWidget* window,
bool tempFiles = false, const QString& suggestedFileName = QString(),
const QByteArray& asn = QByteArray());
/**
* Open a list of URLs with an executable.
*
* @param exec the name of the executable, for example
* "/usr/bin/netscape %u".
* Don't forget to include the %u if you know that the applications
* supports URLs. Otherwise, non-local urls will first be downloaded
* to a temp file (using kioexec).
* @param urls the list of URLs to open, can be empty (app launched without argument)
* @param window The top-level widget of the app that invoked this object.
* @param name the logical name of the application, for example
* "Netscape 4.06".
* @param icon the icon which should be used by the application.
* @param asn Application startup notification id, if any (otherwise "").
* @return @c true on success, @c false on error
*/
static bool run(const QString& exec, const KUrl::List& urls, QWidget* window,
const QString& name = QString(),
const QString& icon = QString(),
const QByteArray& asn = QByteArray());
/**
* Open the given URL.
*
* This function is used after the mime type
* is found out. It will search for all services which can handle
* the mime type and call run() afterwards.
* @param url the URL to open
* @param mimetype the mime type of the resource
* @param window The top-level widget of the app that invoked this object.
* @param tempFile if true and url is a local file, it will be deleted
* when the launched application exits.
* @param runExecutables if false then local .desktop files,
* executables and shell scripts will not be run.
* See also isExecutable().
* @param suggestedFileName see setSuggestedFileName
* @param asn Application startup notification id, if any (otherwise "").
* @return @c true on success, @c false on error
*/
static bool runUrl(const KUrl& url, const QString& mimetype, QWidget* window,
bool tempFile = false , bool runExecutables = true,
const QString& suggestedFileName = QString(), const QByteArray& asn = QByteArray());
/**
* Run the given shell command and notifies KDE of the starting
* of the application. If the program to be called doesn't exist,
* an error box will be displayed.
*
* Use only when you know the full command line. Otherwise use the other
* static methods, or KRun's constructor.
*
* @p cmd must be a shell command. You must not append "&"
* to it, since the function will do that for you.
* @param window The top-level widget of the app that invoked this object.
* @param workingDirectory a working directory, so that a command like
* "kwrite file.txt" finds file.txt from the right place.
*
* @return @c true on success, @c false on error
*/
static bool runCommand(const QString &cmd, QWidget* window, const QString& workingDirectory = QString());
/**
* Same as the other runCommand(), but it also takes the name of the
* binary, to display an error message in case it couldn't find it.
*
* @param cmd must be a shell command. You must not append "&"
* to it, since the function will do that for you.
* @param execName the name of the executable
* @param icon icon for app starting notification
* @param window The top-level widget of the app that invoked this object.
* @param asn Application startup notification id, if any (otherwise "").
* @param workingDirectory the working directory for the started process. The default
* (if passing an empty string) is the user's document path.
* @return @c true on success, @c false on error
*/
static bool runCommand(const QString& cmd, const QString& execName,
const QString& icon, QWidget* window, const QByteArray& asn = QByteArray(),
const QString& workingDirectory = QString());
/**
* Display the Open-With dialog for those URLs, and run the chosen application.
* @param lst the list of applications to run
* @param urls the list of applications to run
* @param window The top-level widget of the app that invoked this object.
* @param tempFiles if true and lst are local files, they will be deleted
* when the application exits.
* @param suggestedFileName see setSuggestedFileName
* @param asn Application startup notification id, if any (otherwise "").
* @return false if the dialog was canceled
*/
static bool displayOpenWithDialog(const KUrl::List& lst, QWidget* window,
bool tempFiles = false, const QString& suggestedFileName = QString(),
const QByteArray& asn = QByteArray());
static bool displayOpenWithDialog(const KUrl::List &urls, QWidget* window,
bool tempFiles = false);
/**
* Processes a Exec= line as found in .desktop files.
* @param _service the service to extract information from.
* @param _urls The urls the service should open.
* @param tempFiles if true and urls are local files, they will be deleted
* when the application exits.
* @param suggestedFileName see setSuggestedFileName
* @param service the service to extract information from.
* @param urls The urls the service should open.
*
* @return a list of arguments suitable for KProcess::setProgram().
*/
static QStringList processDesktopExec(const KService &_service, const KUrl::List &_urls,
bool tempFiles = false,
const QString& suggestedFileName = QString());
static QStringList processDesktopExec(const KService &service, const KUrl::List &urls);
/**
* Given a full command line (e.g. the Exec= line from a .desktop file),
@ -330,157 +99,9 @@ public:
static bool isExecutableFile(const KUrl &url, const QString &mimetype);
/**
* @internal
* Returns true if startup notification should be done for the given service, false otherwise
*/
static bool checkStartupNotify(const KService *service, QByteArray *wmclass_arg);
Q_SIGNALS:
/**
* Emitted when the operation finished.
* This signal is emitted in all cases of completion, whether successful or with error.
* @see hasFinished()
*/
void finished();
/**
* Emitted when the operation had an error.
* @see hasError()
*/
void error();
protected Q_SLOTS:
/**
* All following protected slots are used by subclasses of KRun!
*/
/**
* This slot is called whenever the internal timer fired,
* in order to move on to the next step.
*/
void slotTimeout(); // KDE5: rename to slotNextStep() or something like that
/**
* This slot is called when the scan job is finished.
*/
void slotScanFinished(KJob *);
/**
* Call this from subclasses when you have determined the mimetype.
* It will call foundMimeType, but also sets up protection against deletion during message boxes.
* @since 4.0.2
*/
void mimeTypeDetermined(const QString& mimeType);
/**
* This slot is called when the 'stat' job has finished.
*/
virtual void slotStatResult(KJob *);
protected:
/**
* All following protected methods are used by subclasses of KRun!
*/
/**
* Initializes the krun object.
*/
virtual void init();
/**
* Start scanning a file.
*/
virtual void scanFile();
/**
* Called if the mimetype has been detected. The function runs
* the application associated with this mimetype.
* Reimplement this method to implement a different behavior,
* like opening the component for displaying the URL embedded.
*
* Important: call setFinished(true) once you are done!
* Usually at the end of the foundMimeType reimplementation, but if the
* reimplementation is asynchronous (e.g. uses KIO jobs) then
* it can be called later instead.
*/
virtual void foundMimeType(const QString& type);
/**
* Called if error occurres.
*/
virtual void error(const QString& message);
/**
* Kills the file scanning job.
*/
virtual void killJob();
/**
* Sets the url.
*/
void setUrl(const KUrl &url);
/**
* Returns the url.
*/
KUrl url() const;
/**
* Sets whether an error has occurred.
*/
void setError(bool error);
/**
* Sets whether progress information shall be shown.
*/
void setProgressInfo(bool progressInfo);
/**
* Returns whether progress information are shown.
*/
bool progressInfo() const;
/**
* Marks this 'KRun' instance as finished.
*/
void setFinished(bool finished);
/**
* Sets the job.
*/
void setJob(KIO::Job *job);
/**
* Returns the job.
*/
KIO::Job* job();
/**
* Returns whether it is a directory.
*/
bool isDirectory() const;
/**
* Sets whether it is a local file.
*/
void setIsLocalFile(bool isLocalFile);
/**
* Returns whether it is a local file.
*/
bool isLocalFile() const;
/**
* Sets the file mode.
*/
void setMode(mode_t mode);
/**
* Returns the file mode.
*/
mode_t mode() const;
private:
class KRunPrivate;
KRunPrivate* const d;
};
#endif

View file

@ -1,127 +0,0 @@
// -*- mode: c++; c-basic-offset: 2 -*-
/* This file is part of the KDE project
Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
Copyright (C) 2006 David Faure <faure@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KRUN_P_H
#define KRUN_P_H
#include <QtCore/QObject>
#include <QtCore/QPointer>
#include "kprocess.h"
#include "kstartupinfo.h"
/**
* @internal
* This class watches a process launched by KRun.
* It sends a notification when the process exits (for the taskbar)
* and it will show an error message if necessary (e.g. "program not found").
*/
class KProcessRunner : public QObject
{
Q_OBJECT
public:
#ifndef Q_WS_X11
static qint64 run(KProcess *, const QString & executable);
#else
static qint64 run(KProcess *, const QString & executable, const KStartupInfoId& id);
#endif
virtual ~KProcessRunner();
qint64 pid() const;
protected Q_SLOTS:
void slotProcessExited(int, QProcess::ExitStatus);
private:
#ifndef Q_WS_X11
KProcessRunner(KProcess *, const QString & binName);
#else
KProcessRunner(KProcess *, const QString & binName, const KStartupInfoId& id);
#endif
void terminateStartupNotification();
KProcess *m_process;
QString m_executable; // can be a full path
KStartupInfoId m_id;
qint64 m_pid;
Q_DISABLE_COPY(KProcessRunner)
};
/**
* @internal
*/
class KRun::KRunPrivate
{
public:
KRunPrivate(KRun *parent);
void init (const KUrl& url, QWidget* window, mode_t mode,
bool isLocalFile, bool showProgressInfo, const QByteArray& asn);
// This helper method makes debugging easier: a single breakpoint for all
// the code paths that start the timer - at least from KRun itself.
// TODO: add public method startTimer() and deprecate timer() accessor,
// starting is the only valid use of the timer in subclasses
void startTimer();
bool runExecutable(const QString& _exec);
KRun *q;
bool m_showingDialog;
bool m_runExecutables;
QString m_preferredService;
QString m_localPath;
QString m_suggestedFileName;
QPointer <QWidget> m_window;
QByteArray m_asn;
KUrl m_strURL;
bool m_bFault;
bool m_bAutoDelete;
bool m_bProgressInfo;
bool m_bFinished;
KIO::Job * m_job;
QTimer m_timer;
/**
* Used to indicate that the next action is to scan the file.
* This action is invoked from slotTimeout.
*/
bool m_bScanFile;
bool m_bIsDirectory;
/**
* Used to indicate that the next action is to initialize.
* This action is invoked from slotTimeout
*/
bool m_bInit;
bool m_bIsLocalFile;
mode_t m_mode;
};
#endif // KRUN_P_H

View file

@ -38,7 +38,7 @@ int main( int argc, char **argv )
if ( args->count() != 1 )
return 1;
KToolInvocation::self()->invokeMailer(KUrl(args->arg(0)), QByteArray(), true);
KToolInvocation::self()->invokeMailer(KUrl(args->arg(0)), true);
return 0;
}

View file

@ -94,7 +94,7 @@ int main(int argc, char **argv)
cmd << QString::number(url.port());
}
KToolInvocation::self()->kdeinitExec(terminal, cmd);
KToolInvocation::self()->startProgram(terminal, cmd);
return 0;
}

View file

@ -16,7 +16,6 @@ ENDMACRO(KIO_UNIT_TESTS)
# jobtest seems to trigger a ctest problem; jobtest finishes and ctest waits for ever
KIO_UNIT_TESTS(
krununittest
kprotocolinfotest
jobtest
jobguitest

View file

@ -1,266 +0,0 @@
/*
* Copyright (C) 2003 Waldo Bastian <bastian@kde.org>
* Copyright (C) 2007, 2009 David Faure <faure@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "krununittest.h"
#include "moc_krununittest.cpp"
#include <qtest_kde.h>
QTEST_KDEMAIN( KRunUnitTest, NoGUI )
#include "krun.h"
#include <kshell.h>
#include <kservice.h>
#include <kstandarddirs.h>
#include <kconfiggroup.h>
#include <kprocess.h>
#include "kiotesthelper.h" // createTestFile etc.
void KRunUnitTest::initTestCase()
{
// testProcessDesktopExec works only if your terminal application is set to "x-term"
KConfigGroup cg(KGlobal::config(), "General");
cg.writeEntry("TerminalApplication", "x-term");
// Determine the full path of sh - this is needed to make testProcessDesktopExecNoFile()
// pass on systems where KStandardDirs::findExe("sh") is not "/bin/sh".
m_sh = KStandardDirs::findExe("sh");
if (m_sh.isEmpty()) m_sh = "/bin/sh";
}
void KRunUnitTest::testBinaryName_data()
{
QTest::addColumn<QString>("execLine");
QTest::addColumn<bool>("removePath");
QTest::addColumn<QString>("expected");
QTest::newRow("/usr/bin/ls true") << "/usr/bin/ls" << true << "ls";
QTest::newRow("/usr/bin/ls false") << "/usr/bin/ls" << false << "/usr/bin/ls";
QTest::newRow("/path/to/wine \"long argument with path\"") << "/path/to/wine \"long argument with path\"" << true << "wine";
QTest::newRow("/path/with/a/sp\\ ace/exe arg1 arg2") << "/path/with/a/sp\\ ace/exe arg1 arg2" << true << "exe";
QTest::newRow("\"progname\" \"arg1\"") << "\"progname\" \"arg1\"" << true << "progname";
QTest::newRow("'quoted' \"arg1\"") << "'quoted' \"arg1\"" << true << "quoted";
QTest::newRow(" 'leading space' arg1") << " 'leading space' arg1" << true << "leading space";
}
void KRunUnitTest::testBinaryName()
{
QFETCH(QString, execLine);
QFETCH(bool, removePath);
QFETCH(QString, expected);
QCOMPARE(KRun::binaryName(execLine, removePath), expected);
}
//static const char *bt(bool tr) { return tr?"true":"false"; }
static void checkPDE(const char* exec, const char* term, const char* sus,
const KUrl::List &urls, bool tf, const QString& b)
{
QFile out( "kruntest.desktop" );
if ( !out.open( QIODevice::WriteOnly ) )
abort();
QByteArray str ( "[Desktop Entry]\n"
"Type=Application\n"
"Name=just_a_test\n"
"Icon=~/icon.png\n");
str += QByteArray(exec) + '\n';
str += QByteArray(term) + '\n';
str += QByteArray(sus) + '\n';
out.write( str );
out.close();
KService service(QDir::currentPath() + "/kruntest.desktop");
/*qDebug() << QString().sprintf(
"processDesktopExec( "
"service = {\nexec = %s\nterminal = %s, terminalOptions = %s\nsubstituteUid = %s, user = %s },"
"\nURLs = { %s },\ntemp_files = %s )",
service.exec().toLatin1().constData(), bt(service.terminal()), service.terminalOptions().toLatin1().constData(), bt(service.substituteUid()), service.username().toLatin1().constData(),
KShell::joinArgs(urls.toStringList()).toLatin1().constData(), bt(tf));
*/
QCOMPARE(KShell::joinArgs(KRun::processDesktopExec(service,urls,tf)), b);
QFile::remove("kruntest.desktop");
}
void KRunUnitTest::testProcessDesktopExec()
{
KUrl::List l0;
static const char
* const execs[] = { "Exec=date -u", "Exec=echo $PWD" },
* const terms[] = { "Terminal=false", "Terminal=true\nTerminalOptions=-T \"%f - %c\"" },
* const sus[] = { "X-KDE-SubstituteUID=false", "X-KDE-SubstituteUID=true\nX-KDE-Username=sprallo" },
* const rslts[] = {
"/bin/date -u", // 0
"/bin/sh -c 'echo $PWD '", // 1
"x-term -T ' - just_a_test' -e /bin/date -u", // 2
"x-term -T ' - just_a_test' -e /bin/sh -c 'echo $PWD '", // 3
/* kdesudo */ " -u sprallo -c '/bin/date -u'", // 4
/* kdesudo */ " -u sprallo -c '/bin/sh -c '\\''echo $PWD '\\'''", // 5
"x-term -T ' - just_a_test' -e su sprallo -c '/bin/date -u'", // 6
"x-term -T ' - just_a_test' -e su sprallo -c '/bin/sh -c '\\''echo $PWD '\\'''", // 7
};
// Find out the full path of the shell which will be used to execute shell commands
KProcess process;
process.setShellCommand("");
const QString shellPath = process.program().at(0);
// Arch moved /bin/date to /usr/bin/date...
const QString datePath = KStandardDirs::findExe("date");
for (int su = 0; su < 2; su++)
for (int te = 0; te < 2; te++)
for (int ex = 0; ex < 2; ex++) {
int pt = ex+te*2+su*4;
QString exe;
if (pt == 4 || pt == 5) {
exe = KStandardDirs::findExe("kdesudo");
if (exe.isEmpty()) {
qWarning() << "kdesudo not found, skipping test";
continue;
}
}
const QString result = QString::fromLatin1(rslts[pt])
.replace("/bin/sh", shellPath)
.replace("/bin/date", datePath);
checkPDE( execs[ex], terms[te], sus[su], l0, false, exe + result);
}
}
void KRunUnitTest::testProcessDesktopExecNoFile_data()
{
QTest::addColumn<QString>("execLine");
QTest::addColumn<KUrl::List>("urls");
QTest::addColumn<bool>("tempfiles");
QTest::addColumn<QString>("expected");
KUrl::List l0;
KUrl::List l1; l1 << KUrl( "file:/tmp" );
KUrl::List l2; l2 << KUrl( "http://localhost/foo" );
KUrl::List l3; l3 << KUrl( "file:/local/file" ) << KUrl( "http://remotehost.org/bar" );
KUrl::List l4; l4 << KUrl( "http://login:password@www.kde.org" );
// A real-world use case would be kate.
// But I picked klauncher4 since it's installed by kdelibs
QString klauncher = KStandardDirs::findExe("klauncher4");
if (klauncher.isEmpty()) klauncher = "klauncher4";
QString kioexec = KStandardDirs::findExe("kioexec");
if (kioexec.isEmpty())
QSKIP("kioexec not found, kdebase needed", SkipAll);
QString kmailservice = KStandardDirs::findExe("kmailservice");
if (kmailservice.isEmpty()) kmailservice = "kmailservice";
if (!klauncher.isEmpty()) {
QVERIFY(!kmailservice.isEmpty());
}
// NOTE: using QString() for concats to avoid QStringBuilder metatype, which is not valid
QTest::newRow("%U l0") << "klauncher4 %U" << l0 << false << klauncher;
QTest::newRow("%U l1") << "klauncher4 %U" << l1 << false << QString(klauncher + " /tmp");
QTest::newRow("%U l2") << "klauncher4 %U" << l2 << false << QString(klauncher + " http://localhost/foo");
QTest::newRow("%U l3") << "klauncher4 %U" << l3 << false << QString(klauncher + " /local/file http://remotehost.org/bar");
//QTest::newRow("%u l0") << "klauncher4 %u" << l0 << false << klauncher; // gives runtime warning
QTest::newRow("%u l1") << "klauncher4 %u" << l1 << false << QString(klauncher + " /tmp");
QTest::newRow("%u l2") << "klauncher4 %u" << l2 << false << QString(klauncher + " http://localhost/foo");
//QTest::newRow("%u l3") << "klauncher4 %u" << l3 << false << klauncher; // gives runtime warning
QTest::newRow("%F l0") << "klauncher4 %F" << l0 << false << klauncher;
QTest::newRow("%F l1") << "klauncher4 %F" << l1 << false << QString(klauncher + " /tmp");
QTest::newRow("%F l2") << "klauncher4 %F" << l2 << false << QString(kioexec + " 'klauncher4 %F' http://localhost/foo");
QTest::newRow("%F l3") << "klauncher4 %F" << l3 << false << QString(kioexec + " 'klauncher4 %F' /local/file http://remotehost.org/bar");
QTest::newRow("%F l1 tempfile") << "klauncher4 %F" << l1 << true << QString(kioexec + " --tempfiles 'klauncher4 %F' /tmp");
QTest::newRow("sh -c klauncher4 %F") << "sh -c \"klauncher4 \"'\\\"'\"%F\"'\\\"'"
<< l1 << false << QString(m_sh + " -c 'klauncher4 \\\"/tmp\\\"'");
QTest::newRow("kmailservice %u l1") << "kmailservice %u" << l1 << false << QString(kmailservice + " /tmp");
QTest::newRow("kmailservice %u l4") << "kmailservice %u" << l4 << false << QString(kmailservice + " http://login:password@www.kde.org");
}
void KRunUnitTest::testProcessDesktopExecNoFile()
{
QFETCH(QString, execLine);
KService service("dummy", execLine, "app");
QFETCH(KUrl::List, urls);
QFETCH(bool, tempfiles);
QFETCH(QString, expected);
QCOMPARE(KShell::joinArgs(KRun::processDesktopExec(service,urls,tempfiles)), expected);
}
class KRunImpl : public KRun
{
public:
KRunImpl(const KUrl& url, bool isLocalFile = false)
: KRun(url, 0, 0, isLocalFile, false) {}
void foundMimeType(const QString& type) final {
m_mimeType = type;
// don't call KRun::foundMimeType, we don't want to start an app ;-)
setFinished(true);
}
void error(const QString& message) final {
// don't show message box, this is unit test
Q_UNUSED(message);
}
QString mimeTypeFound() const { return m_mimeType; }
private:
QString m_mimeType;
};
void KRunUnitTest::testMimeTypeFile()
{
const QString filePath = homeTmpDir() + "file";
createTestFile(filePath, true);
KRunImpl* krun = new KRunImpl(filePath, true);
QTest::kWaitForSignal(krun, SIGNAL(finished()), 1000);
QCOMPARE(krun->mimeTypeFound(), QString::fromLatin1("text/plain"));
}
void KRunUnitTest::testMimeTypeDirectory()
{
const QString dir = homeTmpDir() + "dir";
createTestDirectory(dir);
KRunImpl* krun = new KRunImpl(dir, true);
QTest::kWaitForSignal(krun, SIGNAL(finished()), 1000);
QCOMPARE(krun->mimeTypeFound(), QString::fromLatin1("inode/directory"));
}
void KRunUnitTest::testMimeTypeBrokenLink()
{
const QString dir = homeTmpDir() + "dir";
createTestDirectory(dir);
KRunImpl* krun = new KRunImpl(KUrl(dir + "/testlink"), true);
QSignalSpy spyError(krun, SIGNAL(error()));
QTest::kWaitForSignal(krun, SIGNAL(finished()), 1000);
QVERIFY(krun->mimeTypeFound().isEmpty());
QCOMPARE(spyError.count(), 1);
}
void KRunUnitTest::testMimeTypeDoesNotExist()
{
KRunImpl* krun = new KRunImpl(KUrl("/does/not/exist"));
QSignalSpy spyError(krun, SIGNAL(error()));
QTest::kWaitForSignal(krun, SIGNAL(finished()), 1000);
QVERIFY(krun->mimeTypeFound().isEmpty());
QCOMPARE(spyError.count(), 1);
}

View file

@ -1,49 +0,0 @@
/*
* Copyright (C) 2005, 2009 David Faure <faure@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KRUNUNITTEST_H
#define KRUNUNITTEST_H
#include <QtCore/QObject>
class KRunUnitTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void testBinaryName_data();
void testBinaryName();
void testProcessDesktopExec();
void testProcessDesktopExecNoFile_data();
void testProcessDesktopExecNoFile();
void testMimeTypeFile();
void testMimeTypeDirectory();
void testMimeTypeBrokenLink();
void testMimeTypeDoesNotExist();
private:
QString m_sh;
};
#endif /* KRUNUNITTEST_H */

View file

@ -25,7 +25,7 @@
#include <kstandarddirs.h>
#include <kicon.h>
#include <krun.h>
#include <ktoolinvocation.h>
namespace Plasma
{
@ -79,7 +79,7 @@ AssociatedApplicationManager *AssociatedApplicationManager::self()
void AssociatedApplicationManager::setApplication(Plasma::Applet *applet, const QString &application)
{
KService::Ptr service = KService::serviceByDesktopName(application);
KService::Ptr service = KService::serviceByStorageId(application);
if (service || !KStandardDirs::findExe(application).isNull() || QFile::exists(application)) {
d->applicationNames[applet] = application;
if (!d->urlLists.contains(applet)) {
@ -106,14 +106,15 @@ KUrl::List AssociatedApplicationManager::urls(const Plasma::Applet *applet) cons
void AssociatedApplicationManager::run(Plasma::Applet *applet)
{
if (d->applicationNames.contains(applet)) {
bool success = KRun::run(d->applicationNames.value(applet), d->urlLists.value(applet), 0);
bool success = KToolInvocation::self()->startServiceByStorageId(
d->applicationNames.value(applet), d->urlLists.value(applet).toStringList()
);
if (!success) {
applet->showMessage(KIcon("application-exit"), i18n("There was an error attempting to exec the associated application with this widget."), ButtonOk);
}
} else if (d->urlLists.contains(applet) && !d->urlLists.value(applet).isEmpty()) {
KRun *krun = new KRun(d->urlLists.value(applet).first(), 0);
krun->setAutoDelete(true);
KToolInvocation::self()->startServiceForUrl(d->urlLists.value(applet).first().url());
}
}