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