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