KDECore
ktoolinvocation.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2005 Brad Hards <bradh@frogmouth.net> 00003 Copyright (C) 2006 Thiago Macieira <thiago@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "ktoolinvocation.h" 00022 #include "klauncher_iface.h" 00023 #include "kdebug.h" 00024 #include "kglobal.h" 00025 #include "kstandarddirs.h" 00026 #include "kcomponentdata.h" 00027 #include "kurl.h" 00028 #include "kmessage.h" 00029 #include "kservice.h" 00030 #include <klockfile.h> 00031 #include <klocale.h> 00032 00033 #include <QMutex> 00034 #include <QMutexLocker> 00035 #include <QCoreApplication> 00036 #include <QThread> 00037 00038 #include <errno.h> 00039 00040 00041 KToolInvocation *KToolInvocation::self() 00042 { 00043 K_GLOBAL_STATIC(KToolInvocation, s_self) 00044 return s_self; 00045 } 00046 00047 KToolInvocation::KToolInvocation() : QObject(0), d(0) 00048 { 00049 } 00050 00051 KToolInvocation::~KToolInvocation() 00052 { 00053 } 00054 00055 Q_GLOBAL_STATIC_WITH_ARGS(org::kde::KLauncher, klauncherIface, 00056 (QString::fromLatin1("org.kde.klauncher"), QString::fromLatin1("/KLauncher"), QDBusConnection::sessionBus())) 00057 00058 org::kde::KLauncher *KToolInvocation::klauncher() 00059 { 00060 if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(QString::fromLatin1("org.kde.klauncher"))) { 00061 kDebug(180) << "klauncher not running... launching kdeinit"; 00062 KToolInvocation::startKdeinit(); 00063 } 00064 return ::klauncherIface(); 00065 } 00066 00067 static void printError(const QString& text, QString* error) 00068 { 00069 if (error) 00070 *error = text; 00071 else 00072 kError() << text << endl; 00073 } 00074 00075 bool KToolInvocation::isMainThreadActive(QString* error) 00076 { 00077 if (QCoreApplication::instance() && QCoreApplication::instance()->thread() != QThread::currentThread()) 00078 { 00079 printError(i18n("Function must be called from the main thread."), error); 00080 return false; 00081 } 00082 00083 return true; 00084 } 00085 00086 int KToolInvocation::startServiceInternal(const char *_function, 00087 const QString& _name, const QStringList &URLs, 00088 QString *error, QString *serviceName, int *pid, 00089 const QByteArray& startup_id, bool noWait, 00090 const QString& workdir) 00091 { 00092 QString function = QLatin1String(_function); 00093 org::kde::KLauncher *launcher = KToolInvocation::klauncher(); 00094 QDBusMessage msg = QDBusMessage::createMethodCall(launcher->service(), 00095 launcher->path(), 00096 launcher->interface(), 00097 function); 00098 msg << _name << URLs; 00099 if (function == QLatin1String("kdeinit_exec_with_workdir")) 00100 msg << workdir; 00101 #ifdef Q_WS_X11 00102 // make sure there is id, so that user timestamp exists 00103 QStringList envs; 00104 QByteArray s = startup_id; 00105 emit kapplication_hook(envs, s); 00106 msg << envs; 00107 msg << QString::fromLatin1(s); 00108 #else 00109 msg << QStringList(); 00110 msg << QString(); 00111 #endif 00112 if( !function.startsWith( QLatin1String("kdeinit_exec") ) ) 00113 msg << noWait; 00114 00115 QDBusMessage reply = QDBusConnection::sessionBus().call(msg); 00116 if ( reply.type() != QDBusMessage::ReplyMessage ) 00117 { 00118 QDBusReply<QString> replyObj(reply); 00119 if (replyObj.error().type() == QDBusError::NoReply) { 00120 printError(i18n("Error launching %1. Either KLauncher is not running anymore, or it failed to start the application.", _name), error); 00121 } else { 00122 const QString rpl = reply.arguments().count() > 0 ? reply.arguments().at(0).toString() : reply.errorMessage(); 00123 printError(i18n("KLauncher could not be reached via D-Bus. Error when calling %1:\n%2\n",function, rpl), error); 00124 } 00125 //qDebug() << reply; 00126 return EINVAL; 00127 } 00128 00129 if (noWait) 00130 return 0; 00131 00132 Q_ASSERT(reply.arguments().count() == 4); 00133 if (serviceName) 00134 *serviceName = reply.arguments().at(1).toString(); 00135 if (error) 00136 *error = reply.arguments().at(2).toString(); 00137 if (pid) 00138 *pid = reply.arguments().at(3).toInt(); 00139 return reply.arguments().at(0).toInt(); 00140 } 00141 00142 #ifndef KDE_NO_DEPRECATED 00143 int 00144 KToolInvocation::startServiceByName( const QString& _name, const QString &URL, 00145 QString *error, QString *serviceName, int *pid, 00146 const QByteArray& startup_id, bool noWait ) 00147 { 00148 if (!isMainThreadActive(error)) 00149 return EINVAL; 00150 00151 QStringList URLs; 00152 if (!URL.isEmpty()) 00153 URLs.append(URL); 00154 return self()->startServiceInternal("start_service_by_name", 00155 _name, URLs, error, serviceName, pid, startup_id, noWait); 00156 } 00157 #endif 00158 00159 #ifndef KDE_NO_DEPRECATED 00160 int 00161 KToolInvocation::startServiceByName( const QString& _name, const QStringList &URLs, 00162 QString *error, QString *serviceName, int *pid, 00163 const QByteArray& startup_id, bool noWait ) 00164 { 00165 if (!isMainThreadActive(error)) 00166 return EINVAL; 00167 00168 return self()->startServiceInternal("start_service_by_name", 00169 _name, URLs, error, serviceName, pid, startup_id, noWait); 00170 } 00171 #endif 00172 00173 int 00174 KToolInvocation::startServiceByDesktopPath( const QString& _name, const QString &URL, 00175 QString *error, QString *serviceName, 00176 int *pid, const QByteArray& startup_id, bool noWait ) 00177 { 00178 if (!isMainThreadActive(error)) 00179 return EINVAL; 00180 00181 QStringList URLs; 00182 if (!URL.isEmpty()) 00183 URLs.append(URL); 00184 return self()->startServiceInternal("start_service_by_desktop_path", 00185 _name, URLs, error, serviceName, pid, startup_id, noWait); 00186 } 00187 00188 int 00189 KToolInvocation::startServiceByDesktopPath( const QString& _name, const QStringList &URLs, 00190 QString *error, QString *serviceName, int *pid, 00191 const QByteArray& startup_id, bool noWait ) 00192 { 00193 if (!isMainThreadActive(error)) 00194 return EINVAL; 00195 00196 return self()->startServiceInternal("start_service_by_desktop_path", 00197 _name, URLs, error, serviceName, pid, startup_id, noWait); 00198 } 00199 00200 int 00201 KToolInvocation::startServiceByDesktopName( const QString& _name, const QString &URL, 00202 QString *error, QString *serviceName, int *pid, 00203 const QByteArray& startup_id, bool noWait ) 00204 { 00205 if (!isMainThreadActive(error)) 00206 return EINVAL; 00207 00208 QStringList URLs; 00209 if (!URL.isEmpty()) 00210 URLs.append(URL); 00211 return self()->startServiceInternal("start_service_by_desktop_name", 00212 _name, URLs, error, serviceName, pid, startup_id, noWait); 00213 } 00214 00215 int 00216 KToolInvocation::startServiceByDesktopName( const QString& _name, const QStringList &URLs, 00217 QString *error, QString *serviceName, int *pid, 00218 const QByteArray& startup_id, bool noWait ) 00219 { 00220 if (!isMainThreadActive(error)) 00221 return EINVAL; 00222 00223 return self()->startServiceInternal("start_service_by_desktop_name", 00224 _name, URLs, error, serviceName, pid, startup_id, noWait); 00225 } 00226 00227 int 00228 KToolInvocation::kdeinitExec( const QString& name, const QStringList &args, 00229 QString *error, int *pid, const QByteArray& startup_id ) 00230 { 00231 if (!isMainThreadActive(error)) 00232 return EINVAL; 00233 00234 return self()->startServiceInternal("kdeinit_exec", 00235 name, args, error, 0, pid, startup_id, false); 00236 } 00237 00238 00239 int 00240 KToolInvocation::kdeinitExecWait( const QString& name, const QStringList &args, 00241 QString *error, int *pid, const QByteArray& startup_id ) 00242 { 00243 if (!isMainThreadActive(error)) 00244 return EINVAL; 00245 00246 return self()->startServiceInternal("kdeinit_exec_wait", 00247 name, args, error, 0, pid, startup_id, false); 00248 } 00249 00250 void KToolInvocation::invokeHelp( const QString& anchor, 00251 const QString& _appname, 00252 const QByteArray& startup_id ) 00253 { 00254 if (!isMainThreadActive()) 00255 return; 00256 00257 KUrl url; 00258 QString appname; 00259 QString docPath; 00260 if (_appname.isEmpty()) { 00261 appname = QCoreApplication::instance()->applicationName(); 00262 } else 00263 appname = _appname; 00264 00265 KService::Ptr service(KService::serviceByDesktopName(appname)); 00266 if (service) { 00267 docPath = service->docPath(); 00268 } 00269 00270 if (!docPath.isEmpty()) { 00271 url = KUrl(KUrl("help:/"), docPath); 00272 } else { 00273 url = QString::fromLatin1("help:/%1/index.html").arg(appname); 00274 } 00275 00276 if (!anchor.isEmpty()) { 00277 url.addQueryItem(QString::fromLatin1("anchor"), anchor); 00278 } 00279 00280 // launch a browser for URIs not handled by khelpcenter 00281 // (following KCMultiDialog::slotHelpClicked()) 00282 if (!(url.protocol() == QLatin1String("help") || url.protocol() == QLatin1String("man") || url.protocol() == QLatin1String("info"))) { 00283 invokeBrowser(url.url()); 00284 return; 00285 } 00286 00287 QDBusInterface *iface = new QDBusInterface(QLatin1String("org.kde.khelpcenter"), 00288 QLatin1String("/KHelpCenter"), 00289 QLatin1String("org.kde.khelpcenter.khelpcenter"), 00290 QDBusConnection::sessionBus()); 00291 if ( !iface->isValid() ) 00292 { 00293 QString error; 00294 #ifdef Q_WS_WIN 00295 // startServiceByDesktopName() does not work yet; KRun:processDesktopExec returned 'KRun: syntax error in command "khelpcenter %u" , service "KHelpCenter" ' 00296 if (kdeinitExec(QLatin1String("khelpcenter"), QStringList() << url.url(), &error, 0, startup_id)) 00297 #else 00298 if (startServiceByDesktopName(QLatin1String("khelpcenter"), url.url(), &error, 0, 0, startup_id, false)) 00299 #endif 00300 { 00301 KMessage::message(KMessage::Error, 00302 i18n("Could not launch the KDE Help Center:\n\n%1", error), 00303 i18n("Could not Launch Help Center")); 00304 delete iface; 00305 return; 00306 } 00307 00308 delete iface; 00309 iface = new QDBusInterface(QLatin1String("org.kde.khelpcenter"), 00310 QLatin1String("/KHelpCenter"), 00311 QLatin1String("org.kde.khelpcenter.khelpcenter"), 00312 QDBusConnection::sessionBus()); 00313 } 00314 00315 iface->call(QString::fromLatin1("openUrl"), url.url(), startup_id ); 00316 delete iface; 00317 } 00318 00319 void KToolInvocation::invokeMailer(const QString &address, const QString &subject, const QByteArray& startup_id) 00320 { 00321 if (!isMainThreadActive()) 00322 return; 00323 00324 invokeMailer(address, QString(), QString(), subject, QString(), QString(), 00325 QStringList(), startup_id ); 00326 } 00327 00328 void KToolInvocation::invokeMailer(const KUrl &mailtoURL, const QByteArray& startup_id, bool allowAttachments ) 00329 { 00330 if (!isMainThreadActive()) 00331 return; 00332 00333 QString address = mailtoURL.path(); 00334 QString subject; 00335 QString cc; 00336 QString bcc; 00337 QString body; 00338 00339 const QStringList queries = mailtoURL.query().mid(1).split(QLatin1Char('&')); 00340 const QChar comma = QChar::fromLatin1(','); 00341 QStringList attachURLs; 00342 for (QStringList::ConstIterator it = queries.begin(); it != queries.end(); ++it) 00343 { 00344 QString q = (*it).toLower(); 00345 if (q.startsWith(QLatin1String("subject="))) 00346 subject = KUrl::fromPercentEncoding((*it).mid(8).toLatin1()); 00347 else 00348 if (q.startsWith(QLatin1String("cc="))) 00349 cc = cc.isEmpty()? KUrl::fromPercentEncoding((*it).mid(3).toLatin1()): cc + comma + KUrl::fromPercentEncoding((*it).mid(3).toLatin1()); 00350 else 00351 if (q.startsWith(QLatin1String("bcc="))) 00352 bcc = bcc.isEmpty()? KUrl::fromPercentEncoding((*it).mid(4).toLatin1()): bcc + comma + KUrl::fromPercentEncoding((*it).mid(4).toLatin1()); 00353 else 00354 if (q.startsWith(QLatin1String("body="))) 00355 body = KUrl::fromPercentEncoding((*it).mid(5).toLatin1()); 00356 else 00357 if (allowAttachments && q.startsWith(QLatin1String("attach="))) 00358 attachURLs.push_back(KUrl::fromPercentEncoding((*it).mid(7).toLatin1())); 00359 else 00360 if (allowAttachments && q.startsWith(QLatin1String("attachment="))) 00361 attachURLs.push_back(KUrl::fromPercentEncoding((*it).mid(11).toLatin1())); 00362 else 00363 if (q.startsWith(QLatin1String("to="))) 00364 address = address.isEmpty()? KUrl::fromPercentEncoding((*it).mid(3).toLatin1()): address + comma + KUrl::fromPercentEncoding((*it).mid(3).toLatin1()); 00365 } 00366 00367 invokeMailer( address, cc, bcc, subject, body, QString(), attachURLs, startup_id ); 00368 } 00369 00370 void KToolInvocation::startKdeinit() 00371 { 00372 KComponentData inst( "startkdeinitlock" ); 00373 KLockFile lock( KStandardDirs::locateLocal("tmp", QString::fromLatin1("startkdeinitlock"), inst )); 00374 if( lock.lock( KLockFile::NoBlockFlag ) != KLockFile::LockOK ) { 00375 lock.lock(); 00376 if( QDBusConnection::sessionBus().interface()->isServiceRegistered(QString::fromLatin1("org.kde.klauncher"))) 00377 return; // whoever held the lock has already started it 00378 } 00379 // Try to launch kdeinit. 00380 QString srv = KStandardDirs::findExe(QLatin1String("kdeinit4")); 00381 if (srv.isEmpty()) 00382 return; 00383 // this is disabled because we are in kdecore 00384 // const bool gui = qApp && qApp->type() != QApplication::Tty; 00385 // if ( gui ) 00386 // qApp->setOverrideCursor( Qt::WaitCursor ); 00387 QStringList args; 00388 #ifndef Q_WS_WIN 00389 args += QString::fromLatin1("--suicide"); 00390 #endif 00391 QProcess::execute(srv, args); 00392 // if ( gui ) 00393 // qApp->restoreOverrideCursor(); 00394 } 00395 00396 #include "ktoolinvocation.moc"
KDE 4.6 API Reference