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