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