kded.cpp

00001 /*  This file is part of the KDE libraries
00002  *  Copyright (C) 1999 David Faure <faure@kde.org>
00003  *  Copyright (C) 2000 Waldo Bastian <bastian@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 version 2 as published by the Free Software Foundation;
00008  *
00009  *  This library is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  *  Library General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU Library General Public License
00015  *  along with this library; see the file COPYING.LIB.  If not, write to
00016  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  *  Boston, MA 02110-1301, USA.
00018  **/
00019 
00020 #include <qdir.h>
00021 
00022 #include "kded.h"
00023 #include "kdedmodule.h"
00024 
00025 #include <kresourcelist.h>
00026 #include <kcrash.h>
00027 
00028 #include <unistd.h>
00029 #include <stdlib.h>
00030 #include <signal.h>
00031 #include <time.h>
00032 
00033 #include <qfile.h>
00034 #include <qtimer.h>
00035 
00036 #include <dcopclient.h>
00037 
00038 #include <kuniqueapplication.h>
00039 #include <kcmdlineargs.h>
00040 #include <kaboutdata.h>
00041 #include <klocale.h>
00042 #include <kglobal.h>
00043 #include <kprocess.h>
00044 #include <kdebug.h>
00045 #include <kdirwatch.h>
00046 #include <kstandarddirs.h>
00047 #include <kdatastream.h>
00048 #include <kio/global.h>
00049 #include <kservicetype.h>
00050 
00051 #ifdef Q_WS_X11
00052 #include <X11/Xlib.h>
00053 #include <fixx11h.h>
00054 #endif
00055 
00056 Kded *Kded::_self = 0;
00057 
00058 static bool checkStamps = true;
00059 static bool delayedCheck = false;
00060 
00061 static void runBuildSycoca(QObject *callBackObj=0, const char *callBackSlot=0)
00062 {
00063    QStringList args;
00064    args.append("--incremental");
00065    if(checkStamps)
00066       args.append("--checkstamps");
00067    if(delayedCheck)
00068       args.append("--nocheckfiles");
00069    else
00070       checkStamps = false; // useful only during kded startup
00071    if (callBackObj)
00072    {
00073       QByteArray data;
00074       QDataStream dataStream( data, IO_WriteOnly );
00075       dataStream << QString("kbuildsycoca") << args;
00076       QCString _launcher = KApplication::launcher();
00077 
00078       kapp->dcopClient()->callAsync(_launcher, _launcher, "kdeinit_exec_wait(QString,QStringList)", data, callBackObj, callBackSlot);
00079    }
00080    else
00081    {
00082       KApplication::kdeinitExecWait( "kbuildsycoca", args );
00083    }
00084 }
00085 
00086 static void runKonfUpdate()
00087 {
00088    KApplication::kdeinitExecWait( "kconf_update", QStringList(), 0, 0, "0" /*no startup notification*/ );
00089 }
00090 
00091 static void runDontChangeHostname(const QCString &oldName, const QCString &newName)
00092 {
00093    QStringList args;
00094    args.append(QFile::decodeName(oldName));
00095    args.append(QFile::decodeName(newName));
00096    KApplication::kdeinitExecWait( "kdontchangethehostname", args );
00097 }
00098 
00099 Kded::Kded(bool checkUpdates, bool new_startup)
00100   : DCOPObject("kbuildsycoca"), DCOPObjectProxy(),
00101     b_checkUpdates(checkUpdates),
00102     m_needDelayedCheck(false),
00103     m_newStartup( new_startup )
00104 {
00105   _self = this;
00106   QCString cPath;
00107   QCString ksycoca_env = getenv("KDESYCOCA");
00108   if (ksycoca_env.isEmpty())
00109      cPath = QFile::encodeName(KGlobal::dirs()->saveLocation("tmp")+"ksycoca");
00110   else
00111      cPath = ksycoca_env;
00112   m_pTimer = new QTimer(this);
00113   connect(m_pTimer, SIGNAL(timeout()), this, SLOT(recreate()));
00114 
00115   QTimer::singleShot(100, this, SLOT(installCrashHandler()));
00116 
00117   m_pDirWatch = 0;
00118 
00119   m_windowIdList.setAutoDelete(true);
00120 
00121   m_recreateCount = 0;
00122   m_recreateBusy = false;
00123 }
00124 
00125 Kded::~Kded()
00126 {
00127   _self = 0;
00128   m_pTimer->stop();
00129   delete m_pTimer;
00130   delete m_pDirWatch;
00131 
00132   m_modules.setAutoDelete(true);
00133 }
00134 
00135 bool Kded::process(const QCString &obj, const QCString &fun,
00136                    const QByteArray &data,
00137                    QCString &replyType, QByteArray &replyData)
00138 {
00139   if (obj == "ksycoca") return false; // Ignore this one.
00140 
00141   if (m_dontLoad[obj])
00142      return false;
00143 
00144   KDEDModule *module = loadModule(obj, true);
00145   if (!module)
00146      return false;
00147 
00148   module->setCallingDcopClient(kapp->dcopClient());
00149   return module->process(fun, data, replyType, replyData);
00150 }
00151 
00152 void Kded::initModules()
00153 {
00154      m_dontLoad.clear();
00155      KConfig *config = kapp->config();
00156      bool kde_running = !( getenv( "KDE_FULL_SESSION" ) == NULL || getenv( "KDE_FULL_SESSION" )[ 0 ] == '\0' );
00157 
00158      // Preload kded modules.
00159      KService::List kdedModules = KServiceType::offers("KDEDModule");
00160      for(KService::List::ConstIterator it = kdedModules.begin(); it != kdedModules.end(); ++it)
00161      {
00162          KService::Ptr service = *it;
00163          bool autoload = service->property("X-KDE-Kded-autoload", QVariant::Bool).toBool();
00164          config->setGroup(QString("Module-%1").arg(service->desktopEntryName()));
00165          autoload = config->readBoolEntry("autoload", autoload);
00166          if( m_newStartup )
00167          {
00168             // see ksmserver's README for description of the phases
00169             QVariant phasev = service->property("X-KDE-Kded-phase", QVariant::Int );
00170             int phase = phasev.isValid() ? phasev.toInt() : 2;
00171             bool prevent_autoload = false;
00172             switch( phase )
00173             {
00174                 case 0: // always autoload
00175                     break;
00176                 case 1: // autoload only in KDE
00177                     if( !kde_running )
00178                         prevent_autoload = true;
00179                     break;
00180                 case 2: // autoload delayed, only in KDE
00181                 default:
00182                     prevent_autoload = true;
00183                     break;   
00184             }
00185             if (autoload && !prevent_autoload)
00186                loadModule(service, false);
00187          }
00188          else
00189          {
00190             if (autoload && kde_running)
00191                loadModule(service, false);
00192          }
00193          bool dontLoad = false;
00194          QVariant p = service->property("X-KDE-Kded-load-on-demand", QVariant::Bool);
00195          if (p.isValid() && (p.toBool() == false))
00196             dontLoad = true;
00197          if (dontLoad)
00198             noDemandLoad(service->desktopEntryName());
00199 
00200          if (dontLoad && !autoload)
00201             unloadModule(service->desktopEntryName().latin1());
00202      }
00203 }
00204 
00205 void Kded::loadSecondPhase()
00206 {
00207      kdDebug(7020) << "Loading second phase autoload" << endl;
00208      KConfig *config = kapp->config();
00209      KService::List kdedModules = KServiceType::offers("KDEDModule");
00210      for(KService::List::ConstIterator it = kdedModules.begin(); it != kdedModules.end(); ++it)
00211      {
00212          KService::Ptr service = *it;
00213          bool autoload = service->property("X-KDE-Kded-autoload", QVariant::Bool).toBool();
00214          config->setGroup(QString("Module-%1").arg(service->desktopEntryName()));
00215          autoload = config->readBoolEntry("autoload", autoload);
00216          QVariant phasev = service->property("X-KDE-Kded-phase", QVariant::Int );
00217          int phase = phasev.isValid() ? phasev.toInt() : 2;
00218          if( phase == 2 && autoload )
00219             loadModule(service, false);
00220      }
00221 }
00222 
00223 void Kded::noDemandLoad(const QString &obj)
00224 {
00225   m_dontLoad.insert(obj.latin1(), this);
00226 }
00227 
00228 KDEDModule *Kded::loadModule(const QCString &obj, bool onDemand)
00229 {
00230   KDEDModule *module = m_modules.find(obj);
00231   if (module)
00232      return module;
00233   KService::Ptr s = KService::serviceByDesktopPath("kded/"+obj+".desktop");
00234   return loadModule(s, onDemand);
00235 }
00236 
00237 KDEDModule *Kded::loadModule(const KService *s, bool onDemand)
00238 {
00239   KDEDModule *module = 0;
00240   if (s && !s->library().isEmpty())
00241   {
00242     QCString obj = s->desktopEntryName().latin1();
00243     KDEDModule *oldModule = m_modules.find(obj);
00244     if (oldModule)
00245        return oldModule;
00246 
00247     if (onDemand)
00248     {
00249       QVariant p = s->property("X-KDE-Kded-load-on-demand", QVariant::Bool);
00250       if (p.isValid() && (p.toBool() == false))
00251       {
00252          noDemandLoad(s->desktopEntryName());
00253          return 0;
00254       }
00255     }
00256     // get the library loader instance
00257 
00258     KLibLoader *loader = KLibLoader::self();
00259 
00260     QVariant v = s->property("X-KDE-FactoryName", QVariant::String);
00261     QString factory = v.isValid() ? v.toString() : QString::null;
00262     if (factory.isEmpty())
00263     {
00264        // Stay bugward compatible
00265        v = s->property("X-KDE-Factory", QVariant::String);
00266        factory = v.isValid() ? v.toString() : QString::null;
00267     }
00268     if (factory.isEmpty())
00269       factory = s->library();
00270 
00271     factory = "create_" + factory;
00272     QString libname = "kded_"+s->library();
00273 
00274     KLibrary *lib = loader->library(QFile::encodeName(libname));
00275     if (!lib)
00276     {
00277       kdWarning() << k_funcinfo << "Could not load library. [ "
00278           << loader->lastErrorMessage() << " ]" << endl;
00279       libname.prepend("lib");
00280       lib = loader->library(QFile::encodeName(libname));
00281     }
00282     if (lib)
00283     {
00284       // get the create_ function
00285       void *create = lib->symbol(QFile::encodeName(factory));
00286 
00287       if (create)
00288       {
00289         // create the module
00290         KDEDModule* (*func)(const QCString &);
00291         func = (KDEDModule* (*)(const QCString &)) create;
00292         module = func(obj);
00293         if (module)
00294         {
00295           m_modules.insert(obj, module);
00296           m_libs.insert(obj, lib);
00297           connect(module, SIGNAL(moduleDeleted(KDEDModule *)), SLOT(slotKDEDModuleRemoved(KDEDModule *)));
00298           kdDebug(7020) << "Successfully loaded module '" << obj << "'\n";
00299           return module;
00300         }
00301       }
00302       loader->unloadLibrary(QFile::encodeName(libname));
00303     }
00304     else
00305     {
00306     kdWarning() << k_funcinfo << "Could not load library. [ "
00307             << loader->lastErrorMessage() << " ]" << endl;
00308     }
00309     kdDebug(7020) << "Could not load module '" << obj << "'\n";
00310   }
00311   return 0;
00312 }
00313 
00314 bool Kded::unloadModule(const QCString &obj)
00315 {
00316   KDEDModule *module = m_modules.take(obj);
00317   if (!module)
00318      return false;
00319   kdDebug(7020) << "Unloading module '" << obj << "'\n";
00320   delete module;
00321   return true;
00322 }
00323 
00324 // DCOP
00325 QCStringList Kded::loadedModules()
00326 {
00327     QCStringList modules;
00328     QAsciiDictIterator<KDEDModule> it( m_modules );
00329     for ( ; it.current(); ++it)
00330         modules.append( it.currentKey() );
00331 
00332     return modules;
00333 }
00334 
00335 QCStringList Kded::functions()
00336 {
00337     QCStringList res = DCOPObject::functions();
00338     res += "ASYNC recreate()";
00339     return res;
00340 }
00341 
00342 void Kded::slotKDEDModuleRemoved(KDEDModule *module)
00343 {
00344   m_modules.remove(module->objId());
00345   KLibrary *lib = m_libs.take(module->objId());
00346   if (lib)
00347      lib->unload();
00348 }
00349 
00350 void Kded::slotApplicationRemoved(const QCString &appId)
00351 {
00352   for(QAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it)
00353   {
00354      it.current()->removeAll(appId);
00355   }
00356 
00357   QValueList<long> *windowIds = m_windowIdList.find(appId);
00358   if (windowIds)
00359   {
00360      for( QValueList<long>::ConstIterator it = windowIds->begin();
00361           it != windowIds->end(); ++it)
00362      {
00363         long windowId = *it;
00364         m_globalWindowIdList.remove(windowId);
00365         for(QAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it)
00366         {
00367             emit it.current()->windowUnregistered(windowId);
00368         }
00369      }
00370      m_windowIdList.remove(appId);
00371   }
00372 }
00373 
00374 void Kded::updateDirWatch()
00375 {
00376   if (!b_checkUpdates) return;
00377 
00378   delete m_pDirWatch;
00379   m_pDirWatch = new KDirWatch;
00380 
00381   QObject::connect( m_pDirWatch, SIGNAL(dirty(const QString&)),
00382            this, SLOT(update(const QString&)));
00383   QObject::connect( m_pDirWatch, SIGNAL(created(const QString&)),
00384            this, SLOT(update(const QString&)));
00385   QObject::connect( m_pDirWatch, SIGNAL(deleted(const QString&)),
00386            this, SLOT(dirDeleted(const QString&)));
00387 
00388   // For each resource
00389   for( QStringList::ConstIterator it = m_allResourceDirs.begin();
00390        it != m_allResourceDirs.end();
00391        ++it )
00392   {
00393      readDirectory( *it );
00394   }
00395 }
00396 
00397 void Kded::updateResourceList()
00398 {
00399   delete KSycoca::self();
00400 
00401   if (!b_checkUpdates) return;
00402 
00403   if (delayedCheck) return;
00404 
00405   QStringList dirs = KSycoca::self()->allResourceDirs();
00406   // For each resource
00407   for( QStringList::ConstIterator it = dirs.begin();
00408        it != dirs.end();
00409        ++it )
00410   {
00411      if (m_allResourceDirs.find(*it) == m_allResourceDirs.end())
00412      {
00413         m_allResourceDirs.append(*it);
00414         readDirectory(*it);
00415      }
00416   }
00417 }
00418 
00419 void Kded::crashHandler(int)
00420 {
00421    DCOPClient::emergencyClose();
00422    if (_self) // Don't restart if we were closing down
00423       system("kded");
00424 qWarning("Last DCOP call before KDED crash was from application '%s'\n"
00425          "to object '%s', function '%s'.",
00426          DCOPClient::postMortemSender(),
00427          DCOPClient::postMortemObject(),
00428          DCOPClient::postMortemFunction());
00429 }
00430 
00431 void Kded::installCrashHandler()
00432 {
00433    KCrash::setEmergencySaveFunction(crashHandler);
00434 }
00435 
00436 void Kded::recreate()
00437 {
00438    recreate(false);
00439 }
00440 
00441 void Kded::runDelayedCheck()
00442 {
00443    if( m_needDelayedCheck )
00444       recreate(false);
00445    m_needDelayedCheck = false;
00446 }
00447 
00448 void Kded::recreate(bool initial)
00449 {
00450    m_recreateBusy = true;
00451    // Using KLauncher here is difficult since we might not have a
00452    // database
00453 
00454    if (!initial)
00455    {
00456       updateDirWatch(); // Update tree first, to be sure to miss nothing.
00457       runBuildSycoca(this, SLOT(recreateDone()));
00458    }
00459    else
00460    {
00461       if(!delayedCheck)
00462          updateDirWatch(); // this would search all the directories
00463       runBuildSycoca();
00464       recreateDone();
00465       if(delayedCheck)
00466       {
00467          // do a proper ksycoca check after a delay
00468          QTimer::singleShot( 60000, this, SLOT( runDelayedCheck()));
00469          m_needDelayedCheck = true;
00470          delayedCheck = false;
00471       }
00472       else
00473          m_needDelayedCheck = false;
00474    }
00475 }
00476 
00477 void Kded::recreateDone()
00478 {
00479    updateResourceList();
00480 
00481    for(; m_recreateCount; m_recreateCount--)
00482    {
00483       QCString replyType = "void";
00484       QByteArray replyData;
00485       DCOPClientTransaction *transaction = m_recreateRequests.first();
00486       if (transaction)
00487          kapp->dcopClient()->endTransaction(transaction, replyType, replyData);
00488       m_recreateRequests.remove(m_recreateRequests.begin());
00489    }
00490    m_recreateBusy = false;
00491 
00492    // Did a new request come in while building?
00493    if (!m_recreateRequests.isEmpty())
00494    {
00495       m_pTimer->start(2000, true /* single shot */ );
00496       m_recreateCount = m_recreateRequests.count();
00497    }
00498 }
00499 
00500 void Kded::dirDeleted(const QString& path)
00501 {
00502   update(path);
00503 }
00504 
00505 void Kded::update(const QString& )
00506 {
00507   if (!m_recreateBusy)
00508   {
00509     m_pTimer->start( 2000, true /* single shot */ );
00510   }
00511   else
00512   {
00513     m_recreateRequests.append(0);
00514   }
00515 }
00516 
00517 bool Kded::process(const QCString &fun, const QByteArray &data,
00518                            QCString &replyType, QByteArray &replyData)
00519 {
00520   if (fun == "recreate()") {
00521     if (!m_recreateBusy)
00522     {
00523        if (m_recreateRequests.isEmpty())
00524        {
00525           m_pTimer->start(0, true /* single shot */ );
00526           m_recreateCount = 0;
00527        }
00528        m_recreateCount++;
00529     }
00530     m_recreateRequests.append(kapp->dcopClient()->beginTransaction());
00531     replyType = "void";
00532     return true;
00533   } else {
00534     return DCOPObject::process(fun, data, replyType, replyData);
00535   }
00536 }
00537 
00538 
00539 void Kded::readDirectory( const QString& _path )
00540 {
00541   QString path( _path );
00542   if ( path.right(1) != "/" )
00543     path += "/";
00544 
00545   if ( m_pDirWatch->contains( path ) ) // Already seen this one?
00546      return;
00547 
00548   QDir d( _path, QString::null, QDir::Unsorted, QDir::Readable | QDir::Executable | QDir::Dirs | QDir::Hidden );
00549   // set QDir ...
00550 
00551 
00552   //************************************************************************
00553   //                           Setting dirs
00554   //************************************************************************
00555 
00556   m_pDirWatch->addDir(path);          // add watch on this dir
00557 
00558   if ( !d.exists() )                            // exists&isdir?
00559   {
00560     kdDebug(7020) << QString("Does not exist! (%1)").arg(_path) << endl;
00561     return;                             // return false
00562   }
00563 
00564   // Note: If some directory is gone, dirwatch will delete it from the list.
00565 
00566   //************************************************************************
00567   //                               Reading
00568   //************************************************************************
00569   QString file;
00570   unsigned int i;                           // counter and string length.
00571   unsigned int count = d.count();
00572   for( i = 0; i < count; i++ )                        // check all entries
00573   {
00574      if (d[i] == "." || d[i] == ".." || d[i] == "magic")
00575        continue;                          // discard those ".", "..", "magic"...
00576 
00577      file = path;                           // set full path
00578      file += d[i];                          // and add the file name.
00579 
00580      readDirectory( file );      // yes, dive into it.
00581   }
00582 }
00583 
00584 bool Kded::isWindowRegistered(long windowId)
00585 {
00586   return m_globalWindowIdList.find(windowId) != 0;
00587 
00588 }
00589 
00590 // DCOP
00591 void Kded::registerWindowId(long windowId)
00592 {
00593   m_globalWindowIdList.replace(windowId, &windowId);
00594   QCString sender = callingDcopClient()->senderId();
00595   if( sender.isEmpty()) // local call
00596       sender = callingDcopClient()->appId();
00597   QValueList<long> *windowIds = m_windowIdList.find(sender);
00598   if (!windowIds)
00599   {
00600     windowIds = new QValueList<long>;
00601     m_windowIdList.insert(sender, windowIds);
00602   }
00603   windowIds->append(windowId);
00604 
00605 
00606   for(QAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it)
00607   {
00608      emit it.current()->windowRegistered(windowId);
00609   }
00610 }
00611 
00612 // DCOP
00613 void Kded::unregisterWindowId(long windowId)
00614 {
00615   m_globalWindowIdList.remove(windowId);
00616   QCString sender = callingDcopClient()->senderId();
00617   if( sender.isEmpty()) // local call
00618       sender = callingDcopClient()->appId();
00619   QValueList<long> *windowIds = m_windowIdList.find(sender);
00620   if (windowIds)
00621   {
00622      windowIds->remove(windowId);
00623      if (windowIds->isEmpty())
00624         m_windowIdList.remove(sender);
00625   }
00626 
00627   for(QAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it)
00628   {
00629     emit it.current()->windowUnregistered(windowId);
00630   }
00631 }
00632 
00633 
00634 static void sighandler(int /*sig*/)
00635 {
00636     if (kapp)
00637        kapp->quit();
00638 }
00639 
00640 KUpdateD::KUpdateD()
00641 {
00642     m_pDirWatch = new KDirWatch;
00643     m_pTimer = new QTimer;
00644     connect(m_pTimer, SIGNAL(timeout()), this, SLOT(runKonfUpdate()));
00645     QObject::connect( m_pDirWatch, SIGNAL(dirty(const QString&)),
00646            this, SLOT(slotNewUpdateFile()));
00647 
00648     QStringList dirs = KGlobal::dirs()->findDirs("data", "kconf_update");
00649     for( QStringList::ConstIterator it = dirs.begin();
00650          it != dirs.end();
00651          ++it )
00652     {
00653        QString path = *it;
00654        if (path[path.length()-1] != '/')
00655           path += "/";
00656 
00657        if (!m_pDirWatch->contains(path))
00658           m_pDirWatch->addDir(path);
00659     }
00660 }
00661 
00662 KUpdateD::~KUpdateD()
00663 {
00664     delete m_pDirWatch;
00665     delete m_pTimer;
00666 }
00667 
00668 void KUpdateD::runKonfUpdate()
00669 {
00670     ::runKonfUpdate();
00671 }
00672 
00673 void KUpdateD::slotNewUpdateFile()
00674 {
00675     m_pTimer->start( 500, true /* single shot */ );
00676 }
00677 
00678 KHostnameD::KHostnameD(int pollInterval)
00679 {
00680     m_Timer.start(pollInterval, false /* repetitive */ );
00681     connect(&m_Timer, SIGNAL(timeout()), this, SLOT(checkHostname()));
00682     checkHostname();
00683 }
00684 
00685 KHostnameD::~KHostnameD()
00686 {
00687     // Empty
00688 }
00689 
00690 void KHostnameD::checkHostname()
00691 {
00692     char buf[1024+1];
00693     if (gethostname(buf, 1024) != 0)
00694        return;
00695     buf[sizeof(buf)-1] = '\0';
00696 
00697     if (m_hostname.isEmpty())
00698     {
00699        m_hostname = buf;
00700        return;
00701     }
00702 
00703     if (m_hostname == buf)
00704        return;
00705 
00706     QCString newHostname = buf;
00707 
00708     runDontChangeHostname(m_hostname, newHostname);
00709     m_hostname = newHostname;
00710 }
00711 
00712 
00713 static KCmdLineOptions options[] =
00714 {
00715   { "check", I18N_NOOP("Check Sycoca database only once"), 0 },
00716   { "new-startup", "Internal", 0 },
00717   KCmdLineLastOption
00718 };
00719 
00720 class KDEDQtDCOPObject : public DCOPObject
00721 {
00722 public:
00723   KDEDQtDCOPObject() : DCOPObject("qt/kded") { }
00724 
00725   virtual bool process(const QCString &fun, const QByteArray &data,
00726                        QCString& replyType, QByteArray &replyData)
00727     {
00728       if ( kapp && (fun == "quit()") )
00729       {
00730         kapp->quit();
00731         replyType = "void";
00732         return true;
00733       }
00734       return DCOPObject::process(fun, data, replyType, replyData);
00735     }
00736 
00737   QCStringList functions()
00738     {
00739        QCStringList res = DCOPObject::functions();
00740        res += "void quit()";
00741        return res;
00742     }
00743 };
00744 
00745 class KDEDApplication : public KUniqueApplication
00746 {
00747 public:
00748   KDEDApplication() : KUniqueApplication( )
00749     {
00750        startup = true;
00751        dcopClient()->connectDCOPSignal( "DCOPServer", "", "terminateKDE()",
00752                                         objId(), "quit()", false );
00753     }
00754 
00755   int newInstance()
00756     {
00757        if (startup) {
00758           startup = false;
00759           if( Kded::self()->newStartup())
00760              Kded::self()->initModules();
00761           else
00762          QTimer::singleShot(500, Kded::self(), SLOT(initModules()));
00763        } else 
00764           runBuildSycoca();
00765 
00766        return 0;
00767     }
00768 
00769   QCStringList functions()
00770     {
00771        QCStringList res = KUniqueApplication::functions();
00772        res += "bool loadModule(QCString)";
00773        res += "bool unloadModule(QCString)";
00774        res += "void registerWindowId(long int)";
00775        res += "void unregisterWindowId(long int)";
00776        res += "QCStringList loadedModules()";
00777        res += "void reconfigure()";
00778        res += "void loadSecondPhase()";
00779        res += "void quit()";
00780        return res;
00781     }
00782 
00783   bool process(const QCString &fun, const QByteArray &data,
00784                QCString &replyType, QByteArray &replyData)
00785   {
00786     if (fun == "loadModule(QCString)") {
00787       QCString module;
00788       QDataStream arg( data, IO_ReadOnly );
00789       arg >> module;
00790       bool result = (Kded::self()->loadModule(module, false) != 0);
00791       replyType = "bool";
00792       QDataStream _replyStream( replyData, IO_WriteOnly );
00793       _replyStream << result;
00794       return true;
00795     }
00796     else if (fun == "unloadModule(QCString)") {
00797       QCString module;
00798       QDataStream arg( data, IO_ReadOnly );
00799       arg >> module;
00800       bool result = Kded::self()->unloadModule(module);
00801       replyType = "bool";
00802       QDataStream _replyStream( replyData, IO_WriteOnly );
00803       _replyStream << result;
00804       return true;
00805     }
00806     else if (fun == "registerWindowId(long int)") {
00807       long windowId;
00808       QDataStream arg( data, IO_ReadOnly );
00809       arg >> windowId;
00810       Kded::self()->setCallingDcopClient(callingDcopClient());
00811       Kded::self()->registerWindowId(windowId);
00812       replyType = "void";
00813       return true;
00814     }
00815      else if (fun == "unregisterWindowId(long int)") {
00816       long windowId;
00817       QDataStream arg( data, IO_ReadOnly );
00818       arg >> windowId;
00819       Kded::self()->setCallingDcopClient(callingDcopClient());
00820       Kded::self()->unregisterWindowId(windowId);
00821       replyType = "void";
00822       return true;
00823     }
00824     else if (fun == "loadedModules()") {
00825       replyType = "QCStringList";
00826       QDataStream _replyStream(replyData, IO_WriteOnly);
00827       _replyStream << Kded::self()->loadedModules();
00828       return true;
00829     }
00830     else if (fun == "reconfigure()") {
00831       config()->reparseConfiguration();
00832       Kded::self()->initModules();
00833       replyType = "void";
00834       return true;
00835     }
00836     else if (fun == "loadSecondPhase()") {
00837       Kded::self()->loadSecondPhase();
00838       replyType = "void";
00839       return true;
00840     }
00841     else if (fun == "quit()") {
00842       quit();
00843       replyType = "void";
00844       return true;
00845     }
00846     return KUniqueApplication::process(fun, data, replyType, replyData);
00847   }
00848 
00849   bool startup;
00850   KDEDQtDCOPObject kdedQtDcopObject;
00851 };
00852 
00853 extern "C" KDE_EXPORT int kdemain(int argc, char *argv[])
00854 {
00855      KAboutData aboutData( "kded", I18N_NOOP("KDE Daemon"),
00856         "$Id: kded.cpp 534738 2006-04-27 18:04:45Z lunakl $",
00857         I18N_NOOP("KDE Daemon - triggers Sycoca database updates when needed"));
00858 
00859      KApplication::installSigpipeHandler();
00860 
00861      KCmdLineArgs::init(argc, argv, &aboutData);
00862 
00863      KUniqueApplication::addCmdLineOptions();
00864 
00865      KCmdLineArgs::addCmdLineOptions( options );
00866 
00867      // this program is in kdelibs so it uses kdelibs as catalog
00868      KLocale::setMainCatalogue("kdelibs");
00869 
00870      // WABA: Make sure not to enable session management.
00871      putenv(strdup("SESSION_MANAGER="));
00872 
00873      // Parse command line before checking DCOP
00874      KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
00875 
00876      // Check DCOP communication.
00877      {
00878         DCOPClient testDCOP;
00879         QCString dcopName = testDCOP.registerAs("kded", false);
00880         if (dcopName.isEmpty())
00881         {
00882            kdFatal() << "DCOP communication problem!" << endl;
00883            return 1;
00884         }
00885      }
00886 
00887      KInstance *instance = new KInstance(&aboutData);
00888      KConfig *config = instance->config(); // Enable translations.
00889 
00890      if (args->isSet("check"))
00891      {
00892         config->setGroup("General");
00893         checkStamps = config->readBoolEntry("CheckFileStamps", true);
00894         runBuildSycoca();
00895         runKonfUpdate();
00896         exit(0);
00897      }
00898 
00899      if (!KUniqueApplication::start())
00900      {
00901         fprintf(stderr, "KDE Daemon (kded) already running.\n");
00902         exit(0);
00903      }
00904 
00905      KUniqueApplication::dcopClient()->setQtBridgeEnabled(false);
00906 
00907      config->setGroup("General");
00908      int HostnamePollInterval = config->readNumEntry("HostnamePollInterval", 5000);
00909      bool bCheckSycoca = config->readBoolEntry("CheckSycoca", true);
00910      bool bCheckUpdates = config->readBoolEntry("CheckUpdates", true);
00911      bool bCheckHostname = config->readBoolEntry("CheckHostname", true);
00912      checkStamps = config->readBoolEntry("CheckFileStamps", true);
00913      delayedCheck = config->readBoolEntry("DelayedCheck", false);
00914 
00915      Kded *kded = new Kded(bCheckSycoca, args->isSet("new-startup")); // Build data base
00916 
00917      signal(SIGTERM, sighandler);
00918      signal(SIGHUP, sighandler);
00919      KDEDApplication k;
00920 
00921      kded->recreate(true); // initial
00922 
00923      if (bCheckUpdates)
00924         (void) new KUpdateD; // Watch for updates
00925 
00926      runKonfUpdate(); // Run it once.
00927 
00928      if (bCheckHostname)
00929         (void) new KHostnameD(HostnamePollInterval); // Watch for hostname changes
00930 
00931      DCOPClient *client = kapp->dcopClient();
00932      QObject::connect(client, SIGNAL(applicationRemoved(const QCString&)),
00933              kded, SLOT(slotApplicationRemoved(const QCString&)));
00934      client->setNotifications(true);
00935      client->setDaemonMode( true );
00936 
00937      // During startup kdesktop waits for KDED to finish.
00938      // Send a notifyDatabaseChanged signal even if the database hasn't
00939      // changed.
00940      // If the database changed, kbuildsycoca's signal didn't go anywhere
00941      // anyway, because it was too early, so let's send this signal
00942      // unconditionnally (David)
00943      QByteArray data;
00944      client->send( "*", "ksycoca", "notifyDatabaseChanged()", data );
00945      client->send( "ksplash", "", "upAndRunning(QString)",  QString("kded"));
00946 #ifdef Q_WS_X11
00947      XEvent e;
00948      e.xclient.type = ClientMessage;
00949      e.xclient.message_type = XInternAtom( qt_xdisplay(), "_KDE_SPLASH_PROGRESS", False );
00950      e.xclient.display = qt_xdisplay();
00951      e.xclient.window = qt_xrootwin();
00952      e.xclient.format = 8;
00953      strcpy( e.xclient.data.b, "kded" );
00954      XSendEvent( qt_xdisplay(), qt_xrootwin(), False, SubstructureNotifyMask, &e );
00955 #endif
00956      int result = k.exec(); // keep running
00957 
00958      delete kded;
00959      delete instance; // Deletes config as well
00960 
00961      return result;
00962 }
00963 
00964 #include "kded.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys