diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | ce4a32fe52ef09d8f5ff1dd22c001110902b60a2 (patch) | |
tree | 5ac38a06f3dde268dc7927dc155896926aaf7012 /kded/kded.cpp | |
download | tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.tar.gz tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kded/kded.cpp')
-rw-r--r-- | kded/kded.cpp | 969 |
1 files changed, 969 insertions, 0 deletions
diff --git a/kded/kded.cpp b/kded/kded.cpp new file mode 100644 index 000000000..ed4c5e75e --- /dev/null +++ b/kded/kded.cpp @@ -0,0 +1,969 @@ +/* This file is part of the KDE libraries + * Copyright (C) 1999 David Faure <faure@kde.org> + * Copyright (C) 2000 Waldo Bastian <bastian@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 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 + * 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 <qdir.h> + +#include "kded.h" +#include "kdedmodule.h" + +#include <kresourcelist.h> +#include <kcrash.h> + +#include <unistd.h> +#include <stdlib.h> +#include <signal.h> +#include <time.h> + +#include <qfile.h> +#include <qtimer.h> + +#include <dcopclient.h> + +#include <kuniqueapplication.h> +#include <kcmdlineargs.h> +#include <kaboutdata.h> +#include <klocale.h> +#include <kglobal.h> +#include <kprocess.h> +#include <kdebug.h> +#include <kdirwatch.h> +#include <kstandarddirs.h> +#include <kdatastream.h> +#include <kio/global.h> +#include <kservicetype.h> + +#ifdef Q_WS_X11 +#include <X11/Xlib.h> +#include <fixx11h.h> +#endif + +Kded *Kded::_self = 0; + +static bool checkStamps = true; +static bool delayedCheck = false; + +static void runBuildSycoca(QObject *callBackObj=0, const char *callBackSlot=0) +{ + QStringList args; + args.append("--incremental"); + if(checkStamps) + args.append("--checkstamps"); + if(delayedCheck) + args.append("--nocheckfiles"); + else + checkStamps = false; // useful only during kded startup + if (callBackObj) + { + QByteArray data; + QDataStream dataStream( data, IO_WriteOnly ); + dataStream << QString("kbuildsycoca") << args; + QCString _launcher = KApplication::launcher(); + + kapp->dcopClient()->callAsync(_launcher, _launcher, "kdeinit_exec_wait(QString,QStringList)", data, callBackObj, callBackSlot); + } + else + { + KApplication::kdeinitExecWait( "kbuildsycoca", args ); + } +} + +static void runKonfUpdate() +{ + KApplication::kdeinitExecWait( "kconf_update", QStringList(), 0, 0, "0" /*no startup notification*/ ); +} + +static void runDontChangeHostname(const QCString &oldName, const QCString &newName) +{ + QStringList args; + args.append(QFile::decodeName(oldName)); + args.append(QFile::decodeName(newName)); + KApplication::kdeinitExecWait( "kdontchangethehostname", args ); +} + +Kded::Kded(bool checkUpdates, bool new_startup) + : DCOPObject("kbuildsycoca"), DCOPObjectProxy(), + b_checkUpdates(checkUpdates), + m_needDelayedCheck(false), + m_newStartup( new_startup ) +{ + _self = this; + QCString cPath; + QCString ksycoca_env = getenv("KDESYCOCA"); + if (ksycoca_env.isEmpty()) + cPath = QFile::encodeName(KGlobal::dirs()->saveLocation("tmp")+"ksycoca"); + else + cPath = ksycoca_env; + m_pTimer = new QTimer(this); + connect(m_pTimer, SIGNAL(timeout()), this, SLOT(recreate())); + + QTimer::singleShot(100, this, SLOT(installCrashHandler())); + + m_pDirWatch = 0; + + m_windowIdList.setAutoDelete(true); + + m_recreateCount = 0; + m_recreateBusy = false; +} + +Kded::~Kded() +{ + _self = 0; + m_pTimer->stop(); + delete m_pTimer; + delete m_pDirWatch; + // We have to delete the modules while we're still able to process incoming + // DCOP messages, since modules might make DCOP calls in their destructors. + QAsciiDictIterator<KDEDModule> it(m_modules); + while (!it.isEmpty()) + delete it.toFirst(); +} + +bool Kded::process(const QCString &obj, const QCString &fun, + const QByteArray &data, + QCString &replyType, QByteArray &replyData) +{ + if (obj == "ksycoca") return false; // Ignore this one. + + if (m_dontLoad[obj]) + return false; + + KDEDModule *module = loadModule(obj, true); + if (!module) + return false; + + module->setCallingDcopClient(kapp->dcopClient()); + return module->process(fun, data, replyType, replyData); +} + +void Kded::initModules() +{ + m_dontLoad.clear(); + KConfig *config = kapp->config(); + bool kde_running = !( getenv( "KDE_FULL_SESSION" ) == NULL || getenv( "KDE_FULL_SESSION" )[ 0 ] == '\0' ); + // not the same user like the one running the session (most likely we're run via sudo or something) + if( getenv( "KDE_SESSION_UID" ) != NULL && uid_t( atoi( getenv( "KDE_SESSION_UID" ))) != getuid()) + kde_running = false; + // Preload kded modules. + KService::List kdedModules = KServiceType::offers("KDEDModule"); + for(KService::List::ConstIterator it = kdedModules.begin(); it != kdedModules.end(); ++it) + { + KService::Ptr service = *it; + bool autoload = service->property("X-KDE-Kded-autoload", QVariant::Bool).toBool(); + config->setGroup(QString("Module-%1").arg(service->desktopEntryName())); + autoload = config->readBoolEntry("autoload", autoload); + if( m_newStartup ) + { + // see ksmserver's README for description of the phases + QVariant phasev = service->property("X-KDE-Kded-phase", QVariant::Int ); + int phase = phasev.isValid() ? phasev.toInt() : 2; + bool prevent_autoload = false; + switch( phase ) + { + case 0: // always autoload + break; + case 1: // autoload only in KDE + if( !kde_running ) + prevent_autoload = true; + break; + case 2: // autoload delayed, only in KDE + default: + prevent_autoload = true; + break; + } + if (autoload && !prevent_autoload) + loadModule(service, false); + } + else + { + if (autoload && kde_running) + loadModule(service, false); + } + bool dontLoad = false; + QVariant p = service->property("X-KDE-Kded-load-on-demand", QVariant::Bool); + if (p.isValid() && (p.toBool() == false)) + dontLoad = true; + if (dontLoad) + noDemandLoad(service->desktopEntryName()); + + if (dontLoad && !autoload) + unloadModule(service->desktopEntryName().latin1()); + } +} + +void Kded::loadSecondPhase() +{ + kdDebug(7020) << "Loading second phase autoload" << endl; + KConfig *config = kapp->config(); + KService::List kdedModules = KServiceType::offers("KDEDModule"); + for(KService::List::ConstIterator it = kdedModules.begin(); it != kdedModules.end(); ++it) + { + KService::Ptr service = *it; + bool autoload = service->property("X-KDE-Kded-autoload", QVariant::Bool).toBool(); + config->setGroup(QString("Module-%1").arg(service->desktopEntryName())); + autoload = config->readBoolEntry("autoload", autoload); + QVariant phasev = service->property("X-KDE-Kded-phase", QVariant::Int ); + int phase = phasev.isValid() ? phasev.toInt() : 2; + if( phase == 2 && autoload ) + loadModule(service, false); + } +} + +void Kded::noDemandLoad(const QString &obj) +{ + m_dontLoad.insert(obj.latin1(), this); +} + +KDEDModule *Kded::loadModule(const QCString &obj, bool onDemand) +{ + KDEDModule *module = m_modules.find(obj); + if (module) + return module; + KService::Ptr s = KService::serviceByDesktopPath("kded/"+obj+".desktop"); + return loadModule(s, onDemand); +} + +KDEDModule *Kded::loadModule(const KService *s, bool onDemand) +{ + KDEDModule *module = 0; + if (s && !s->library().isEmpty()) + { + QCString obj = s->desktopEntryName().latin1(); + KDEDModule *oldModule = m_modules.find(obj); + if (oldModule) + return oldModule; + + if (onDemand) + { + QVariant p = s->property("X-KDE-Kded-load-on-demand", QVariant::Bool); + if (p.isValid() && (p.toBool() == false)) + { + noDemandLoad(s->desktopEntryName()); + return 0; + } + } + // get the library loader instance + + KLibLoader *loader = KLibLoader::self(); + + QVariant v = s->property("X-KDE-FactoryName", QVariant::String); + QString factory = v.isValid() ? v.toString() : QString::null; + if (factory.isEmpty()) + { + // Stay bugward compatible + v = s->property("X-KDE-Factory", QVariant::String); + factory = v.isValid() ? v.toString() : QString::null; + } + if (factory.isEmpty()) + factory = s->library(); + + factory = "create_" + factory; + QString libname = "kded_"+s->library(); + + KLibrary *lib = loader->library(QFile::encodeName(libname)); + if (!lib) + { + kdWarning() << k_funcinfo << "Could not load library. [ " + << loader->lastErrorMessage() << " ]" << endl; + libname.prepend("lib"); + lib = loader->library(QFile::encodeName(libname)); + } + if (lib) + { + // get the create_ function + void *create = lib->symbol(QFile::encodeName(factory)); + + if (create) + { + // create the module + KDEDModule* (*func)(const QCString &); + func = (KDEDModule* (*)(const QCString &)) create; + module = func(obj); + if (module) + { + m_modules.insert(obj, module); + m_libs.insert(obj, lib); + connect(module, SIGNAL(moduleDeleted(KDEDModule *)), SLOT(slotKDEDModuleRemoved(KDEDModule *))); + kdDebug(7020) << "Successfully loaded module '" << obj << "'\n"; + return module; + } + } + loader->unloadLibrary(QFile::encodeName(libname)); + } + else + { + kdWarning() << k_funcinfo << "Could not load library. [ " + << loader->lastErrorMessage() << " ]" << endl; + } + kdDebug(7020) << "Could not load module '" << obj << "'\n"; + } + return 0; +} + +bool Kded::unloadModule(const QCString &obj) +{ + KDEDModule *module = m_modules.take(obj); + if (!module) + return false; + kdDebug(7020) << "Unloading module '" << obj << "'\n"; + delete module; + return true; +} + +// DCOP +QCStringList Kded::loadedModules() +{ + QCStringList modules; + QAsciiDictIterator<KDEDModule> it( m_modules ); + for ( ; it.current(); ++it) + modules.append( it.currentKey() ); + + return modules; +} + +QCStringList Kded::functions() +{ + QCStringList res = DCOPObject::functions(); + res += "ASYNC recreate()"; + return res; +} + +void Kded::slotKDEDModuleRemoved(KDEDModule *module) +{ + m_modules.remove(module->objId()); + KLibrary *lib = m_libs.take(module->objId()); + if (lib) + lib->unload(); +} + +void Kded::slotApplicationRemoved(const QCString &appId) +{ + for(QAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it) + { + it.current()->removeAll(appId); + } + + QValueList<long> *windowIds = m_windowIdList.find(appId); + if (windowIds) + { + for( QValueList<long>::ConstIterator it = windowIds->begin(); + it != windowIds->end(); ++it) + { + long windowId = *it; + m_globalWindowIdList.remove(windowId); + for(QAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it) + { + emit it.current()->windowUnregistered(windowId); + } + } + m_windowIdList.remove(appId); + } +} + +void Kded::updateDirWatch() +{ + if (!b_checkUpdates) return; + + delete m_pDirWatch; + m_pDirWatch = new KDirWatch; + + QObject::connect( m_pDirWatch, SIGNAL(dirty(const QString&)), + this, SLOT(update(const QString&))); + QObject::connect( m_pDirWatch, SIGNAL(created(const QString&)), + this, SLOT(update(const QString&))); + QObject::connect( m_pDirWatch, SIGNAL(deleted(const QString&)), + this, SLOT(dirDeleted(const QString&))); + + // For each resource + for( QStringList::ConstIterator it = m_allResourceDirs.begin(); + it != m_allResourceDirs.end(); + ++it ) + { + readDirectory( *it ); + } +} + +void Kded::updateResourceList() +{ + delete KSycoca::self(); + + if (!b_checkUpdates) return; + + if (delayedCheck) return; + + QStringList dirs = KSycoca::self()->allResourceDirs(); + // For each resource + for( QStringList::ConstIterator it = dirs.begin(); + it != dirs.end(); + ++it ) + { + if (m_allResourceDirs.find(*it) == m_allResourceDirs.end()) + { + m_allResourceDirs.append(*it); + readDirectory(*it); + } + } +} + +void Kded::crashHandler(int) +{ + DCOPClient::emergencyClose(); + if (_self) // Don't restart if we were closing down + system("kded"); +qWarning("Last DCOP call before KDED crash was from application '%s'\n" + "to object '%s', function '%s'.", + DCOPClient::postMortemSender(), + DCOPClient::postMortemObject(), + DCOPClient::postMortemFunction()); +} + +void Kded::installCrashHandler() +{ + KCrash::setEmergencySaveFunction(crashHandler); +} + +void Kded::recreate() +{ + recreate(false); +} + +void Kded::runDelayedCheck() +{ + if( m_needDelayedCheck ) + recreate(false); + m_needDelayedCheck = false; +} + +void Kded::recreate(bool initial) +{ + m_recreateBusy = true; + // Using KLauncher here is difficult since we might not have a + // database + + if (!initial) + { + updateDirWatch(); // Update tree first, to be sure to miss nothing. + runBuildSycoca(this, SLOT(recreateDone())); + } + else + { + if(!delayedCheck) + updateDirWatch(); // this would search all the directories + runBuildSycoca(); + recreateDone(); + if(delayedCheck) + { + // do a proper ksycoca check after a delay + QTimer::singleShot( 60000, this, SLOT( runDelayedCheck())); + m_needDelayedCheck = true; + delayedCheck = false; + } + else + m_needDelayedCheck = false; + } +} + +void Kded::recreateDone() +{ + updateResourceList(); + + for(; m_recreateCount; m_recreateCount--) + { + QCString replyType = "void"; + QByteArray replyData; + DCOPClientTransaction *transaction = m_recreateRequests.first(); + if (transaction) + kapp->dcopClient()->endTransaction(transaction, replyType, replyData); + m_recreateRequests.remove(m_recreateRequests.begin()); + } + m_recreateBusy = false; + + // Did a new request come in while building? + if (!m_recreateRequests.isEmpty()) + { + m_pTimer->start(2000, true /* single shot */ ); + m_recreateCount = m_recreateRequests.count(); + } +} + +void Kded::dirDeleted(const QString& path) +{ + update(path); +} + +void Kded::update(const QString& ) +{ + if (!m_recreateBusy) + { + m_pTimer->start( 2000, true /* single shot */ ); + } + else + { + m_recreateRequests.append(0); + } +} + +bool Kded::process(const QCString &fun, const QByteArray &data, + QCString &replyType, QByteArray &replyData) +{ + if (fun == "recreate()") { + if (!m_recreateBusy) + { + if (m_recreateRequests.isEmpty()) + { + m_pTimer->start(0, true /* single shot */ ); + m_recreateCount = 0; + } + m_recreateCount++; + } + m_recreateRequests.append(kapp->dcopClient()->beginTransaction()); + replyType = "void"; + return true; + } else { + return DCOPObject::process(fun, data, replyType, replyData); + } +} + + +void Kded::readDirectory( const QString& _path ) +{ + QString path( _path ); + if ( path.right(1) != "/" ) + path += "/"; + + if ( m_pDirWatch->contains( path ) ) // Already seen this one? + return; + + QDir d( _path, QString::null, QDir::Unsorted, QDir::Readable | QDir::Executable | QDir::Dirs | QDir::Hidden ); + // set QDir ... + + + //************************************************************************ + // Setting dirs + //************************************************************************ + + m_pDirWatch->addDir(path); // add watch on this dir + + if ( !d.exists() ) // exists&isdir? + { + kdDebug(7020) << QString("Does not exist! (%1)").arg(_path) << endl; + return; // return false + } + + // Note: If some directory is gone, dirwatch will delete it from the list. + + //************************************************************************ + // Reading + //************************************************************************ + QString file; + unsigned int i; // counter and string length. + unsigned int count = d.count(); + for( i = 0; i < count; i++ ) // check all entries + { + if (d[i] == "." || d[i] == ".." || d[i] == "magic") + continue; // discard those ".", "..", "magic"... + + file = path; // set full path + file += d[i]; // and add the file name. + + readDirectory( file ); // yes, dive into it. + } +} + +bool Kded::isWindowRegistered(long windowId) +{ + return m_globalWindowIdList.find(windowId) != 0; + +} + +// DCOP +void Kded::registerWindowId(long windowId) +{ + m_globalWindowIdList.replace(windowId, &windowId); + QCString sender = callingDcopClient()->senderId(); + if( sender.isEmpty()) // local call + sender = callingDcopClient()->appId(); + QValueList<long> *windowIds = m_windowIdList.find(sender); + if (!windowIds) + { + windowIds = new QValueList<long>; + m_windowIdList.insert(sender, windowIds); + } + windowIds->append(windowId); + + + for(QAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it) + { + emit it.current()->windowRegistered(windowId); + } +} + +// DCOP +void Kded::unregisterWindowId(long windowId) +{ + m_globalWindowIdList.remove(windowId); + QCString sender = callingDcopClient()->senderId(); + if( sender.isEmpty()) // local call + sender = callingDcopClient()->appId(); + QValueList<long> *windowIds = m_windowIdList.find(sender); + if (windowIds) + { + windowIds->remove(windowId); + if (windowIds->isEmpty()) + m_windowIdList.remove(sender); + } + + for(QAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it) + { + emit it.current()->windowUnregistered(windowId); + } +} + + +static void sighandler(int /*sig*/) +{ + if (kapp) + kapp->quit(); +} + +KUpdateD::KUpdateD() +{ + m_pDirWatch = new KDirWatch; + m_pTimer = new QTimer; + connect(m_pTimer, SIGNAL(timeout()), this, SLOT(runKonfUpdate())); + QObject::connect( m_pDirWatch, SIGNAL(dirty(const QString&)), + this, SLOT(slotNewUpdateFile())); + + QStringList dirs = KGlobal::dirs()->findDirs("data", "kconf_update"); + for( QStringList::ConstIterator it = dirs.begin(); + it != dirs.end(); + ++it ) + { + QString path = *it; + if (path[path.length()-1] != '/') + path += "/"; + + if (!m_pDirWatch->contains(path)) + m_pDirWatch->addDir(path); + } +} + +KUpdateD::~KUpdateD() +{ + delete m_pDirWatch; + delete m_pTimer; +} + +void KUpdateD::runKonfUpdate() +{ + ::runKonfUpdate(); +} + +void KUpdateD::slotNewUpdateFile() +{ + m_pTimer->start( 500, true /* single shot */ ); +} + +KHostnameD::KHostnameD(int pollInterval) +{ + m_Timer.start(pollInterval, false /* repetitive */ ); + connect(&m_Timer, SIGNAL(timeout()), this, SLOT(checkHostname())); + checkHostname(); +} + +KHostnameD::~KHostnameD() +{ + // Empty +} + +void KHostnameD::checkHostname() +{ + char buf[1024+1]; + if (gethostname(buf, 1024) != 0) + return; + buf[sizeof(buf)-1] = '\0'; + + if (m_hostname.isEmpty()) + { + m_hostname = buf; + return; + } + + if (m_hostname == buf) + return; + + QCString newHostname = buf; + + runDontChangeHostname(m_hostname, newHostname); + m_hostname = newHostname; +} + + +static KCmdLineOptions options[] = +{ + { "check", I18N_NOOP("Check Sycoca database only once"), 0 }, + { "new-startup", "Internal", 0 }, + KCmdLineLastOption +}; + +class KDEDQtDCOPObject : public DCOPObject +{ +public: + KDEDQtDCOPObject() : DCOPObject("qt/kded") { } + + virtual bool process(const QCString &fun, const QByteArray &data, + QCString& replyType, QByteArray &replyData) + { + if ( kapp && (fun == "quit()") ) + { + kapp->quit(); + replyType = "void"; + return true; + } + return DCOPObject::process(fun, data, replyType, replyData); + } + + QCStringList functions() + { + QCStringList res = DCOPObject::functions(); + res += "void quit()"; + return res; + } +}; + +class KDEDApplication : public KUniqueApplication +{ +public: + KDEDApplication() : KUniqueApplication( ) + { + startup = true; + dcopClient()->connectDCOPSignal( "DCOPServer", "", "terminateKDE()", + objId(), "quit()", false ); + } + + int newInstance() + { + if (startup) { + startup = false; + if( Kded::self()->newStartup()) + Kded::self()->initModules(); + else + QTimer::singleShot(500, Kded::self(), SLOT(initModules())); + } else + runBuildSycoca(); + + return 0; + } + + QCStringList functions() + { + QCStringList res = KUniqueApplication::functions(); + res += "bool loadModule(QCString)"; + res += "bool unloadModule(QCString)"; + res += "void registerWindowId(long int)"; + res += "void unregisterWindowId(long int)"; + res += "QCStringList loadedModules()"; + res += "void reconfigure()"; + res += "void loadSecondPhase()"; + res += "void quit()"; + return res; + } + + bool process(const QCString &fun, const QByteArray &data, + QCString &replyType, QByteArray &replyData) + { + if (fun == "loadModule(QCString)") { + QCString module; + QDataStream arg( data, IO_ReadOnly ); + arg >> module; + bool result = (Kded::self()->loadModule(module, false) != 0); + replyType = "bool"; + QDataStream _replyStream( replyData, IO_WriteOnly ); + _replyStream << result; + return true; + } + else if (fun == "unloadModule(QCString)") { + QCString module; + QDataStream arg( data, IO_ReadOnly ); + arg >> module; + bool result = Kded::self()->unloadModule(module); + replyType = "bool"; + QDataStream _replyStream( replyData, IO_WriteOnly ); + _replyStream << result; + return true; + } + else if (fun == "registerWindowId(long int)") { + long windowId; + QDataStream arg( data, IO_ReadOnly ); + arg >> windowId; + Kded::self()->setCallingDcopClient(callingDcopClient()); + Kded::self()->registerWindowId(windowId); + replyType = "void"; + return true; + } + else if (fun == "unregisterWindowId(long int)") { + long windowId; + QDataStream arg( data, IO_ReadOnly ); + arg >> windowId; + Kded::self()->setCallingDcopClient(callingDcopClient()); + Kded::self()->unregisterWindowId(windowId); + replyType = "void"; + return true; + } + else if (fun == "loadedModules()") { + replyType = "QCStringList"; + QDataStream _replyStream(replyData, IO_WriteOnly); + _replyStream << Kded::self()->loadedModules(); + return true; + } + else if (fun == "reconfigure()") { + config()->reparseConfiguration(); + Kded::self()->initModules(); + replyType = "void"; + return true; + } + else if (fun == "loadSecondPhase()") { + Kded::self()->loadSecondPhase(); + replyType = "void"; + return true; + } + else if (fun == "quit()") { + quit(); + replyType = "void"; + return true; + } + return KUniqueApplication::process(fun, data, replyType, replyData); + } + + bool startup; + KDEDQtDCOPObject kdedQtDcopObject; +}; + +extern "C" KDE_EXPORT int kdemain(int argc, char *argv[]) +{ + KAboutData aboutData( "kded", I18N_NOOP("KDE Daemon"), + "$Id$", + I18N_NOOP("KDE Daemon - triggers Sycoca database updates when needed")); + + KApplication::installSigpipeHandler(); + + KCmdLineArgs::init(argc, argv, &aboutData); + + KUniqueApplication::addCmdLineOptions(); + + KCmdLineArgs::addCmdLineOptions( options ); + + // this program is in kdelibs so it uses kdelibs as catalog + KLocale::setMainCatalogue("kdelibs"); + + // WABA: Make sure not to enable session management. + putenv(strdup("SESSION_MANAGER=")); + + // Parse command line before checking DCOP + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + // Check DCOP communication. + { + DCOPClient testDCOP; + QCString dcopName = testDCOP.registerAs("kded", false); + if (dcopName.isEmpty()) + { + kdFatal() << "DCOP communication problem!" << endl; + return 1; + } + } + + KInstance *instance = new KInstance(&aboutData); + KConfig *config = instance->config(); // Enable translations. + + if (args->isSet("check")) + { + config->setGroup("General"); + checkStamps = config->readBoolEntry("CheckFileStamps", true); + runBuildSycoca(); + runKonfUpdate(); + exit(0); + } + + if (!KUniqueApplication::start()) + { + fprintf(stderr, "KDE Daemon (kded) already running.\n"); + exit(0); + } + + KUniqueApplication::dcopClient()->setQtBridgeEnabled(false); + + config->setGroup("General"); + int HostnamePollInterval = config->readNumEntry("HostnamePollInterval", 5000); + bool bCheckSycoca = config->readBoolEntry("CheckSycoca", true); + bool bCheckUpdates = config->readBoolEntry("CheckUpdates", true); + bool bCheckHostname = config->readBoolEntry("CheckHostname", true); + checkStamps = config->readBoolEntry("CheckFileStamps", true); + delayedCheck = config->readBoolEntry("DelayedCheck", false); + + Kded *kded = new Kded(bCheckSycoca, args->isSet("new-startup")); // Build data base + + signal(SIGTERM, sighandler); + signal(SIGHUP, sighandler); + KDEDApplication k; + + kded->recreate(true); // initial + + if (bCheckUpdates) + (void) new KUpdateD; // Watch for updates + + runKonfUpdate(); // Run it once. + + if (bCheckHostname) + (void) new KHostnameD(HostnamePollInterval); // Watch for hostname changes + + DCOPClient *client = kapp->dcopClient(); + QObject::connect(client, SIGNAL(applicationRemoved(const QCString&)), + kded, SLOT(slotApplicationRemoved(const QCString&))); + client->setNotifications(true); + client->setDaemonMode( true ); + + // During startup kdesktop waits for KDED to finish. + // Send a notifyDatabaseChanged signal even if the database hasn't + // changed. + // If the database changed, kbuildsycoca's signal didn't go anywhere + // anyway, because it was too early, so let's send this signal + // unconditionnally (David) + QByteArray data; + client->send( "*", "ksycoca", "notifyDatabaseChanged()", data ); + client->send( "ksplash", "", "upAndRunning(QString)", QString("kded")); +#ifdef Q_WS_X11 + XEvent e; + e.xclient.type = ClientMessage; + e.xclient.message_type = XInternAtom( qt_xdisplay(), "_KDE_SPLASH_PROGRESS", False ); + e.xclient.display = qt_xdisplay(); + e.xclient.window = qt_xrootwin(); + e.xclient.format = 8; + strcpy( e.xclient.data.b, "kded" ); + XSendEvent( qt_xdisplay(), qt_xrootwin(), False, SubstructureNotifyMask, &e ); +#endif + int result = k.exec(); // keep running + + delete kded; + delete instance; // Deletes config as well + + return result; +} + +#include "kded.moc" |