KDED
kded.cpp
Go to the documentation of this file.
00001 // vim: expandtab sw=4 ts=4 00002 /* This file is part of the KDE libraries 00003 * Copyright (C) 1999 David Faure <faure@kde.org> 00004 * Copyright (C) 2000 Waldo Bastian <bastian@kde.org> 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Library General Public 00008 * License version 2 as published by the Free Software Foundation; 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Library General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Library General Public License 00016 * along with this library; see the file COPYING.LIB. If not, write to 00017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 * Boston, MA 02110-1301, USA. 00019 **/ 00020 00021 #include "kded.h" 00022 #include "kdedadaptor.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 <QtCore/QDir> 00034 #include <QtCore/QFile> 00035 #include <QtCore/QTimer> 00036 00037 #include <QtDBus/QtDBus> 00038 00039 #include <kuniqueapplication.h> 00040 #include <kapplication.h> 00041 #include <kcmdlineargs.h> 00042 #include <kaboutdata.h> 00043 #ifndef KDE_NO_DEPRECATED 00044 #include <klibloader.h> 00045 #else 00046 #include <klibrary.h> 00047 #endif 00048 #include <klocale.h> 00049 #include <kglobal.h> 00050 #include <kconfig.h> 00051 #include <kconfiggroup.h> 00052 #include <kdebug.h> 00053 #include <kdirwatch.h> 00054 #include <kstandarddirs.h> 00055 #include <kservicetypetrader.h> 00056 #include <ktoolinvocation.h> 00057 #include <kde_file.h> 00058 #include "klauncher_iface.h" 00059 00060 #ifdef Q_WS_X11 00061 #include <qx11info_x11.h> 00062 #include <X11/Xlib.h> 00063 #include <fixx11h.h> 00064 #endif 00065 00066 #define KDED_EXENAME "kded4" 00067 00068 #define MODULES_PATH "/modules/" 00069 00070 Kded *Kded::_self = 0; 00071 00072 static bool checkStamps = true; 00073 static bool delayedCheck = false; 00074 static int HostnamePollInterval; 00075 static bool bCheckSycoca; 00076 static bool bCheckUpdates; 00077 static bool bCheckHostname; 00078 00079 #ifdef Q_DBUS_EXPORT 00080 extern Q_DBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage&)); 00081 #else 00082 extern QDBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage&)); 00083 #endif 00084 00085 static void runBuildSycoca(QObject *callBackObj=0, const char *callBackSlot=0) 00086 { 00087 const QString exe = KStandardDirs::findExe(KBUILDSYCOCA_EXENAME); 00088 Q_ASSERT(!exe.isEmpty()); 00089 QStringList args; 00090 args.append("--incremental"); 00091 if(checkStamps) 00092 args.append("--checkstamps"); 00093 if(delayedCheck) 00094 args.append("--nocheckfiles"); 00095 else 00096 checkStamps = false; // useful only during kded startup 00097 if (callBackObj) 00098 { 00099 QVariantList argList; 00100 argList << exe << args << QStringList() << QString(); 00101 KToolInvocation::klauncher()->callWithCallback("kdeinit_exec_wait", argList, callBackObj, 00102 callBackSlot); 00103 } 00104 else 00105 { 00106 KToolInvocation::kdeinitExecWait( exe, args ); 00107 } 00108 } 00109 00110 static void runKonfUpdate() 00111 { 00112 KToolInvocation::kdeinitExecWait( "kconf_update", QStringList(), 0, 0, "0" /*no startup notification*/ ); 00113 } 00114 00115 static void runDontChangeHostname(const QByteArray &oldName, const QByteArray &newName) 00116 { 00117 QStringList args; 00118 args.append(QFile::decodeName(oldName)); 00119 args.append(QFile::decodeName(newName)); 00120 KToolInvocation::kdeinitExecWait( "kdontchangethehostname", args ); 00121 } 00122 00123 Kded::Kded() 00124 : m_needDelayedCheck(false) 00125 { 00126 _self = this; 00127 00128 m_serviceWatcher = new QDBusServiceWatcher(this); 00129 m_serviceWatcher->setConnection(QDBusConnection::sessionBus()); 00130 m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration); 00131 QObject::connect(m_serviceWatcher, SIGNAL(serviceUnregistered(QString)), 00132 this, SLOT(slotApplicationRemoved(QString))); 00133 00134 new KBuildsycocaAdaptor(this); 00135 new KdedAdaptor(this); 00136 00137 QDBusConnection session = QDBusConnection::sessionBus(); 00138 session.registerObject("/kbuildsycoca", this); 00139 session.registerObject("/kded", this); 00140 00141 qDBusAddSpyHook(messageFilter); 00142 00143 m_pTimer = new QTimer(this); 00144 m_pTimer->setSingleShot( true ); 00145 connect(m_pTimer, SIGNAL(timeout()), this, SLOT(recreate())); 00146 00147 m_pDirWatch = 0; 00148 00149 m_recreateCount = 0; 00150 m_recreateBusy = false; 00151 } 00152 00153 Kded::~Kded() 00154 { 00155 _self = 0; 00156 m_pTimer->stop(); 00157 delete m_pTimer; 00158 delete m_pDirWatch; 00159 00160 for (QHash<QByteArray,KDEDModule*>::iterator 00161 it(m_modules.begin()), itEnd(m_modules.end()); 00162 it != itEnd; ++it) 00163 { 00164 KDEDModule* module(it.value()); 00165 00166 // first disconnect otherwise slotKDEDModuleRemoved() is called 00167 // and changes m_modules while we're iterating over it 00168 disconnect(module, SIGNAL(moduleDeleted(KDEDModule*)), 00169 this, SLOT(slotKDEDModuleRemoved(KDEDModule*))); 00170 00171 delete module; 00172 } 00173 } 00174 00175 // on-demand module loading 00176 // this function is called by the D-Bus message processing function before 00177 // calls are delivered to objects 00178 void Kded::messageFilter(const QDBusMessage &message) 00179 { 00180 // This happens when kded goes down and some modules try to clean up. 00181 if (!self()) 00182 return; 00183 00184 if (message.type() != QDBusMessage::MethodCallMessage) 00185 return; 00186 00187 QString obj = message.path(); 00188 if (!obj.startsWith(MODULES_PATH)) 00189 return; 00190 00191 // Remove the <MODULES_PATH> part 00192 obj = obj.mid(strlen(MODULES_PATH)); 00193 if (obj == "ksycoca") 00194 return; // Ignore this one. 00195 00196 // Remove the part after the modules name 00197 int index = obj.indexOf('/'); 00198 if (index!=-1) { 00199 obj = obj.left(index); 00200 } 00201 00202 if (self()->m_dontLoad.value(obj, 0)) 00203 return; 00204 00205 KDEDModule *module = self()->loadModule(obj, true); 00206 if (!module) { 00207 kDebug(7020) << "Failed to load module for " << obj; 00208 } 00209 Q_UNUSED(module); 00210 } 00211 00212 static int phaseForModule(const KService::Ptr& service) 00213 { 00214 const QVariant phasev = service->property("X-KDE-Kded-phase", QVariant::Int ); 00215 return phasev.isValid() ? phasev.toInt() : 2; 00216 } 00217 00218 void Kded::initModules() 00219 { 00220 m_dontLoad.clear(); 00221 bool kde_running = !qgetenv( "KDE_FULL_SESSION" ).isEmpty(); 00222 if (kde_running) { 00223 // not the same user like the one running the session (most likely we're run via sudo or something) 00224 const QByteArray sessionUID = qgetenv( "KDE_SESSION_UID" ); 00225 if( !sessionUID.isEmpty() && uid_t( sessionUID.toInt() ) != getuid()) 00226 kde_running = false; 00227 00228 // not the same kde version as the current desktop 00229 const QByteArray kdeSession = qgetenv("KDE_SESSION_VERSION"); 00230 if (kdeSession.toInt() != KDE_VERSION_MAJOR) 00231 kde_running = false; 00232 } 00233 00234 // There will be a "phase 2" only if we're in the KDE startup. 00235 // If kded is restarted by its crashhandled or by hand, 00236 // then there will be no second phase autoload, so load 00237 // these modules now, if in a KDE session. 00238 const bool loadPhase2Now = (kde_running && qgetenv("KDED_STARTED_BY_KDEINIT").toInt() == 0); 00239 00240 // Preload kded modules. 00241 const KService::List kdedModules = KServiceTypeTrader::self()->query("KDEDModule"); 00242 for(KService::List::ConstIterator it = kdedModules.begin(); it != kdedModules.end(); ++it) 00243 { 00244 KService::Ptr service = *it; 00245 // Should the service load on startup? 00246 const bool autoload = isModuleAutoloaded(service); 00247 00248 // see ksmserver's README for description of the phases 00249 bool prevent_autoload = false; 00250 switch( phaseForModule(service) ) 00251 { 00252 case 0: // always autoload 00253 break; 00254 case 1: // autoload only in KDE 00255 if (!kde_running) { 00256 prevent_autoload = true; 00257 } 00258 break; 00259 case 2: // autoload delayed, only in KDE 00260 default: 00261 if (!loadPhase2Now) { 00262 prevent_autoload = true; 00263 } 00264 break; 00265 } 00266 00267 // Load the module if necessary and allowed 00268 if (autoload && !prevent_autoload) { 00269 if (!loadModule(service, false)) { 00270 continue; 00271 } 00272 } 00273 00274 // Remember if the module is allowed to load on demand 00275 bool loadOnDemand = isModuleLoadedOnDemand(service); 00276 if (!loadOnDemand) 00277 noDemandLoad(service->desktopEntryName()); 00278 00279 // In case of reloading the configuration it is possible for a module 00280 // to run even if it is now allowed to. Stop it then. 00281 if (!loadOnDemand && !autoload) 00282 unloadModule(service->desktopEntryName().toLatin1()); 00283 } 00284 } 00285 00286 void Kded::loadSecondPhase() 00287 { 00288 kDebug(7020) << "Loading second phase autoload"; 00289 KSharedConfig::Ptr config = KGlobal::config(); 00290 KService::List kdedModules = KServiceTypeTrader::self()->query("KDEDModule"); 00291 for(KService::List::ConstIterator it = kdedModules.constBegin(); it != kdedModules.constEnd(); ++it) { 00292 const KService::Ptr service = *it; 00293 const bool autoload = isModuleAutoloaded(service); 00294 if (autoload && phaseForModule(service) == 2) { 00295 //kDebug(7020) << "2nd phase: loading" << service->desktopEntryName(); 00296 loadModule(service, false); 00297 } 00298 } 00299 } 00300 00301 void Kded::noDemandLoad(const QString &obj) 00302 { 00303 m_dontLoad.insert(obj.toLatin1(), this); 00304 } 00305 00306 void Kded::setModuleAutoloading(const QString &obj, bool autoload) 00307 { 00308 KSharedConfig::Ptr config = KGlobal::config(); 00309 // Ensure the service exists. 00310 KService::Ptr service = KService::serviceByDesktopPath("kded/"+obj+".desktop"); 00311 if (!service) 00312 return; 00313 KConfigGroup cg(config, QString("Module-%1").arg(service->desktopEntryName())); 00314 cg.writeEntry("autoload", autoload); 00315 cg.sync(); 00316 } 00317 00318 bool Kded::isModuleAutoloaded(const QString &obj) const 00319 { 00320 KService::Ptr s = KService::serviceByDesktopPath("kded/"+obj+".desktop"); 00321 if (!s) 00322 return false; 00323 return isModuleAutoloaded(s); 00324 } 00325 00326 bool Kded::isModuleAutoloaded(const KService::Ptr &module) const 00327 { 00328 KSharedConfig::Ptr config = KGlobal::config(); 00329 bool autoload = module->property("X-KDE-Kded-autoload", QVariant::Bool).toBool(); 00330 KConfigGroup cg(config, QString("Module-%1").arg(module->desktopEntryName())); 00331 autoload = cg.readEntry("autoload", autoload); 00332 return autoload; 00333 } 00334 00335 bool Kded::isModuleLoadedOnDemand(const QString &obj) const 00336 { 00337 KService::Ptr s = KService::serviceByDesktopPath("kded/"+obj+".desktop"); 00338 if (!s) 00339 return false; 00340 return isModuleLoadedOnDemand(s); 00341 } 00342 00343 bool Kded::isModuleLoadedOnDemand(const KService::Ptr &module) const 00344 { 00345 KSharedConfig::Ptr config = KGlobal::config(); 00346 bool loadOnDemand = true; 00347 QVariant p = module->property("X-KDE-Kded-load-on-demand", QVariant::Bool); 00348 if (p.isValid() && (p.toBool() == false)) 00349 loadOnDemand = false; 00350 return loadOnDemand; 00351 } 00352 00353 KDEDModule *Kded::loadModule(const QString &obj, bool onDemand) 00354 { 00355 // Make sure this method is only called with valid module names. 00356 Q_ASSERT(obj.indexOf('/')==-1); 00357 00358 KDEDModule *module = m_modules.value(obj, 0); 00359 if (module) 00360 return module; 00361 KService::Ptr s = KService::serviceByDesktopPath("kded/"+obj+".desktop"); 00362 return loadModule(s, onDemand); 00363 } 00364 00365 KDEDModule *Kded::loadModule(const KService::Ptr& s, bool onDemand) 00366 { 00367 if (s && !s->library().isEmpty()) 00368 { 00369 QString obj = s->desktopEntryName(); 00370 KDEDModule *oldModule = m_modules.value(obj, 0); 00371 if (oldModule) 00372 return oldModule; 00373 00374 if (onDemand) 00375 { 00376 QVariant p = s->property("X-KDE-Kded-load-on-demand", QVariant::Bool); 00377 if (p.isValid() && (p.toBool() == false)) 00378 { 00379 noDemandLoad(s->desktopEntryName()); 00380 return 0; 00381 } 00382 } 00383 00384 KDEDModule *module = 0; 00385 QString libname = "kded_"+s->library(); 00386 KPluginLoader loader(libname); 00387 00388 KPluginFactory *factory = loader.factory(); 00389 if (!factory) { 00390 // kde3 compat 00391 QString factoryName = s->property("X-KDE-FactoryName", QVariant::String).toString(); 00392 if (factoryName.isEmpty()) 00393 factoryName = s->library(); 00394 factoryName = "create_" + factoryName; 00395 #ifndef KDE_NO_DEPRECATED 00396 KLibrary* lib = KLibLoader::self()->library(libname); 00397 KDEDModule* (*create)(); 00398 if (lib) { 00399 create = (KDEDModule* (*)())lib->resolveFunction(QFile::encodeName(factoryName)); 00400 if (create) 00401 module = create(); 00402 } 00403 #endif 00404 if (!module) { 00405 kWarning() << "Could not load library" << libname << ". [" 00406 << loader.errorString() << "]"; 00407 } 00408 } else { 00409 // create the module 00410 module = factory->create<KDEDModule>(this); 00411 } 00412 if (module) { 00413 module->setModuleName(obj); 00414 m_modules.insert(obj, module); 00415 //m_libs.insert(obj, lib); 00416 connect(module, SIGNAL(moduleDeleted(KDEDModule *)), SLOT(slotKDEDModuleRemoved(KDEDModule *))); 00417 kDebug(7020) << "Successfully loaded module" << obj; 00418 return module; 00419 } else { 00420 kDebug(7020) << "Could not load module" << obj; 00421 //loader.unload(); 00422 } 00423 } 00424 return 0; 00425 } 00426 00427 bool Kded::unloadModule(const QString &obj) 00428 { 00429 KDEDModule *module = m_modules.value(obj, 0); 00430 if (!module) 00431 return false; 00432 kDebug(7020) << "Unloading module" << obj; 00433 m_modules.remove(obj); 00434 delete module; 00435 return true; 00436 } 00437 00438 QStringList Kded::loadedModules() 00439 { 00440 return m_modules.keys(); 00441 } 00442 00443 void Kded::slotKDEDModuleRemoved(KDEDModule *module) 00444 { 00445 m_modules.remove(module->moduleName()); 00446 //KLibrary *lib = m_libs.take(module->moduleName()); 00447 //if (lib) 00448 // lib->unload(); 00449 } 00450 00451 void Kded::slotApplicationRemoved(const QString &name) 00452 { 00453 #if 0 // see kdedmodule.cpp (KDED_OBJECTS) 00454 foreach( KDEDModule* module, m_modules ) 00455 { 00456 module->removeAll(appId); 00457 } 00458 #endif 00459 m_serviceWatcher->removeWatchedService(name); 00460 const QList<qlonglong> windowIds = m_windowIdList.value(name); 00461 for( QList<qlonglong>::ConstIterator it = windowIds.begin(); 00462 it != windowIds.end(); ++it) 00463 { 00464 qlonglong windowId = *it; 00465 m_globalWindowIdList.remove(windowId); 00466 foreach( KDEDModule* module, m_modules ) 00467 { 00468 emit module->windowUnregistered(windowId); 00469 } 00470 } 00471 m_windowIdList.remove(name); 00472 } 00473 00474 void Kded::updateDirWatch() 00475 { 00476 if (!bCheckUpdates) return; 00477 00478 delete m_pDirWatch; 00479 m_pDirWatch = new KDirWatch; 00480 00481 QObject::connect( m_pDirWatch, SIGNAL(dirty(const QString&)), 00482 this, SLOT(update(const QString&))); 00483 QObject::connect( m_pDirWatch, SIGNAL(created(const QString&)), 00484 this, SLOT(update(const QString&))); 00485 QObject::connect( m_pDirWatch, SIGNAL(deleted(const QString&)), 00486 this, SLOT(dirDeleted(const QString&))); 00487 00488 // For each resource 00489 for( QStringList::ConstIterator it = m_allResourceDirs.constBegin(); 00490 it != m_allResourceDirs.constEnd(); 00491 ++it ) 00492 { 00493 readDirectory( *it ); 00494 } 00495 } 00496 00497 void Kded::updateResourceList() 00498 { 00499 KSycoca::clearCaches(); 00500 00501 if (!bCheckUpdates) return; 00502 00503 if (delayedCheck) return; 00504 00505 const QStringList dirs = KSycoca::self()->allResourceDirs(); 00506 // For each resource 00507 for( QStringList::ConstIterator it = dirs.begin(); 00508 it != dirs.end(); 00509 ++it ) 00510 { 00511 if (!m_allResourceDirs.contains(*it)) 00512 { 00513 m_allResourceDirs.append(*it); 00514 readDirectory(*it); 00515 } 00516 } 00517 } 00518 00519 void Kded::recreate() 00520 { 00521 recreate(false); 00522 } 00523 00524 void Kded::runDelayedCheck() 00525 { 00526 if( m_needDelayedCheck ) 00527 recreate(false); 00528 m_needDelayedCheck = false; 00529 } 00530 00531 void Kded::recreate(bool initial) 00532 { 00533 m_recreateBusy = true; 00534 // Using KLauncher here is difficult since we might not have a 00535 // database 00536 00537 if (!initial) 00538 { 00539 updateDirWatch(); // Update tree first, to be sure to miss nothing. 00540 runBuildSycoca(this, SLOT(recreateDone())); 00541 } 00542 else 00543 { 00544 if(!delayedCheck) 00545 updateDirWatch(); // this would search all the directories 00546 if (bCheckSycoca) 00547 runBuildSycoca(); 00548 recreateDone(); 00549 if(delayedCheck) 00550 { 00551 // do a proper ksycoca check after a delay 00552 QTimer::singleShot( 60000, this, SLOT(runDelayedCheck())); 00553 m_needDelayedCheck = true; 00554 delayedCheck = false; 00555 } 00556 else 00557 m_needDelayedCheck = false; 00558 } 00559 } 00560 00561 void Kded::recreateDone() 00562 { 00563 updateResourceList(); 00564 00565 for(; m_recreateCount; m_recreateCount--) 00566 { 00567 QDBusMessage msg = m_recreateRequests.takeFirst(); 00568 QDBusConnection::sessionBus().send(msg.createReply()); 00569 } 00570 m_recreateBusy = false; 00571 00572 // Did a new request come in while building? 00573 if (!m_recreateRequests.isEmpty()) 00574 { 00575 m_pTimer->start(2000); 00576 m_recreateCount = m_recreateRequests.count(); 00577 } 00578 } 00579 00580 void Kded::dirDeleted(const QString& path) 00581 { 00582 update(path); 00583 } 00584 00585 void Kded::update(const QString& ) 00586 { 00587 if (!m_recreateBusy) 00588 { 00589 m_pTimer->start( 10000 ); 00590 } 00591 } 00592 00593 void Kded::recreate(const QDBusMessage &msg) 00594 { 00595 if (!m_recreateBusy) 00596 { 00597 if (m_recreateRequests.isEmpty()) 00598 { 00599 m_pTimer->start(0); 00600 m_recreateCount = 0; 00601 } 00602 m_recreateCount++; 00603 } 00604 msg.setDelayedReply(true); 00605 m_recreateRequests.append(msg); 00606 return; 00607 } 00608 00609 00610 void Kded::readDirectory( const QString& _path ) 00611 { 00612 QString path( _path ); 00613 if ( !path.endsWith( '/' ) ) 00614 path += '/'; 00615 00616 if ( m_pDirWatch->contains( path ) ) // Already seen this one? 00617 return; 00618 00619 m_pDirWatch->addDir(path,KDirWatch::WatchFiles|KDirWatch::WatchSubDirs); // add watch on this dir 00620 return; // KDirWatch now claims to also support recursive watching 00621 #if 0 00622 QDir d( _path, QString(), QDir::Unsorted, QDir::Readable | QDir::Executable | QDir::Dirs | QDir::Hidden ); 00623 // set QDir ... 00624 00625 00626 //************************************************************************ 00627 // Setting dirs 00628 //************************************************************************ 00629 00630 if ( !d.exists() ) // exists&isdir? 00631 { 00632 kDebug(7020) << "Does not exist:" << _path; 00633 return; // return false 00634 } 00635 00636 // Note: If some directory is gone, dirwatch will delete it from the list. 00637 00638 //************************************************************************ 00639 // Reading 00640 //************************************************************************ 00641 QString file; 00642 unsigned int i; // counter and string length. 00643 unsigned int count = d.count(); 00644 for( i = 0; i < count; i++ ) // check all entries 00645 { 00646 if (d[i] == "." || d[i] == ".." || d[i] == "magic") 00647 continue; // discard those ".", "..", "magic"... 00648 00649 file = path; // set full path 00650 file += d[i]; // and add the file name. 00651 00652 readDirectory( file ); // yes, dive into it. 00653 } 00654 #endif 00655 } 00656 00657 /* 00658 bool Kded::isWindowRegistered(long windowId) const 00659 { 00660 return m_globalWindowIdList.contains(windowId); 00661 00662 } 00663 */ 00664 00665 void Kded::registerWindowId(qlonglong windowId, const QString &sender) 00666 { 00667 if (!m_windowIdList.contains(sender)) { 00668 m_serviceWatcher->addWatchedService(sender); 00669 } 00670 00671 m_globalWindowIdList.insert(windowId); 00672 QList<qlonglong> windowIds = m_windowIdList.value(sender); 00673 windowIds.append(windowId); 00674 m_windowIdList.insert(sender, windowIds); 00675 00676 foreach( KDEDModule* module, m_modules ) 00677 { 00678 //kDebug() << module->moduleName(); 00679 emit module->windowRegistered(windowId); 00680 } 00681 } 00682 00683 void Kded::unregisterWindowId(qlonglong windowId, const QString &sender) 00684 { 00685 m_globalWindowIdList.remove(windowId); 00686 QList<qlonglong> windowIds = m_windowIdList.value(sender); 00687 if (!windowIds.isEmpty()) 00688 { 00689 windowIds.removeAll(windowId); 00690 if (windowIds.isEmpty()) { 00691 m_serviceWatcher->removeWatchedService(sender); 00692 m_windowIdList.remove(sender); 00693 } else { 00694 m_windowIdList.insert(sender, windowIds); 00695 } 00696 } 00697 00698 foreach( KDEDModule* module, m_modules ) 00699 { 00700 //kDebug() << module->moduleName(); 00701 emit module->windowUnregistered(windowId); 00702 } 00703 } 00704 00705 00706 static void sighandler(int /*sig*/) 00707 { 00708 if (qApp) 00709 qApp->quit(); 00710 } 00711 00712 KUpdateD::KUpdateD() 00713 { 00714 m_pDirWatch = new KDirWatch; 00715 m_pTimer = new QTimer; 00716 m_pTimer->setSingleShot( true ); 00717 connect(m_pTimer, SIGNAL(timeout()), this, SLOT(runKonfUpdate())); 00718 QObject::connect( m_pDirWatch, SIGNAL(dirty(const QString&)), 00719 this, SLOT(slotNewUpdateFile())); 00720 00721 const QStringList dirs = KGlobal::dirs()->findDirs("data", "kconf_update"); 00722 for( QStringList::ConstIterator it = dirs.begin(); 00723 it != dirs.end(); 00724 ++it ) 00725 { 00726 QString path = *it; 00727 if (path[path.length()-1] != '/') 00728 path += '/'; 00729 00730 if (!m_pDirWatch->contains(path)) 00731 m_pDirWatch->addDir(path,KDirWatch::WatchFiles|KDirWatch::WatchSubDirs); 00732 } 00733 } 00734 00735 KUpdateD::~KUpdateD() 00736 { 00737 delete m_pDirWatch; 00738 delete m_pTimer; 00739 } 00740 00741 void KUpdateD::runKonfUpdate() 00742 { 00743 ::runKonfUpdate(); 00744 } 00745 00746 void KUpdateD::slotNewUpdateFile() 00747 { 00748 m_pTimer->start( 500 ); 00749 } 00750 00751 KHostnameD::KHostnameD(int pollInterval) 00752 { 00753 m_Timer.start(pollInterval); // repetitive timer (not single-shot) 00754 connect(&m_Timer, SIGNAL(timeout()), this, SLOT(checkHostname())); 00755 checkHostname(); 00756 } 00757 00758 KHostnameD::~KHostnameD() 00759 { 00760 // Empty 00761 } 00762 00763 void KHostnameD::checkHostname() 00764 { 00765 char buf[1024+1]; 00766 if (gethostname(buf, 1024) != 0) 00767 return; 00768 buf[sizeof(buf)-1] = '\0'; 00769 00770 if (m_hostname.isEmpty()) 00771 { 00772 m_hostname = buf; 00773 return; 00774 } 00775 00776 if (m_hostname == buf) 00777 return; 00778 00779 QByteArray newHostname = buf; 00780 00781 runDontChangeHostname(m_hostname, newHostname); 00782 m_hostname = newHostname; 00783 } 00784 00785 00786 KBuildsycocaAdaptor::KBuildsycocaAdaptor(QObject *parent) 00787 : QDBusAbstractAdaptor(parent) 00788 { 00789 } 00790 00791 void KBuildsycocaAdaptor::recreate(const QDBusMessage &msg) 00792 { 00793 Kded::self()->recreate(msg); 00794 } 00795 00796 class KDEDApplication : public KUniqueApplication 00797 { 00798 public: 00799 KDEDApplication() : KUniqueApplication( ) 00800 { 00801 startup = true; 00802 } 00803 00804 int newInstance() 00805 { 00806 if (startup) { 00807 startup = false; 00808 00809 // This long initialization has to be here, not in kdemain. 00810 // If it was in main, it would cause a dbus timeout when 00811 // our parent from KUniqueApplication tries to call our 00812 // newInstance method. 00813 00814 Kded *kded = Kded::self(); 00815 00816 kded->recreate(true); // initial 00817 00818 if (bCheckUpdates) 00819 (void) new KUpdateD; // Watch for updates 00820 00821 #ifdef Q_WS_X11 00822 XEvent e; 00823 e.xclient.type = ClientMessage; 00824 e.xclient.message_type = XInternAtom( QX11Info::display(), "_KDE_SPLASH_PROGRESS", False ); 00825 e.xclient.display = QX11Info::display(); 00826 e.xclient.window = QX11Info::appRootWindow(); 00827 e.xclient.format = 8; 00828 strcpy( e.xclient.data.b, "kded" ); 00829 XSendEvent( QX11Info::display(), QX11Info::appRootWindow(), False, SubstructureNotifyMask, &e ); 00830 #endif 00831 00832 runKonfUpdate(); // Run it once. 00833 00834 #ifdef Q_WS_X11 00835 e.xclient.type = ClientMessage; 00836 e.xclient.message_type = XInternAtom( QX11Info::display(), "_KDE_SPLASH_PROGRESS", False ); 00837 e.xclient.display = QX11Info::display(); 00838 e.xclient.window = QX11Info::appRootWindow(); 00839 e.xclient.format = 8; 00840 strcpy( e.xclient.data.b, "confupdate" ); 00841 XSendEvent( QX11Info::display(), QX11Info::appRootWindow(), False, SubstructureNotifyMask, &e ); 00842 #endif 00843 00844 if (bCheckHostname) 00845 (void) new KHostnameD(HostnamePollInterval); // Watch for hostname changes 00846 00847 kded->initModules(); 00848 } else 00849 runBuildSycoca(); 00850 00851 return 0; 00852 } 00853 00854 bool startup; 00855 }; 00856 00857 extern "C" KDE_EXPORT int kdemain(int argc, char *argv[]) 00858 { 00859 KAboutData aboutData( "kded" /*don't change this one to kded4! dbus registration should be org.kde.kded etc.*/, 00860 "kdelibs4", ki18n("KDE Daemon"), 00861 "$Id$", 00862 ki18n("KDE Daemon - triggers Sycoca database updates when needed")); 00863 00864 KCmdLineOptions options; 00865 options.add("check", ki18n("Check Sycoca database only once")); 00866 00867 KCmdLineArgs::init(argc, argv, &aboutData); 00868 00869 KUniqueApplication::addCmdLineOptions(); 00870 00871 KCmdLineArgs::addCmdLineOptions( options ); 00872 00873 // WABA: Make sure not to enable session management. 00874 putenv(qstrdup("SESSION_MANAGER=")); 00875 00876 // Parse command line before checking DCOP 00877 KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); 00878 00879 KComponentData componentData(&aboutData); 00880 KSharedConfig::Ptr config = componentData.config(); // Enable translations. 00881 00882 KConfigGroup cg(config, "General"); 00883 if (args->isSet("check")) 00884 { 00885 // KUniqueApplication not wanted here. 00886 KApplication app; 00887 checkStamps = cg.readEntry("CheckFileStamps", true); 00888 runBuildSycoca(); 00889 runKonfUpdate(); 00890 return 0; 00891 } 00892 00893 if (!KUniqueApplication::start()) 00894 { 00895 fprintf(stderr, "KDE Daemon (kded) already running.\n"); 00896 return 0; 00897 } 00898 00899 // Thiago: reenable if such a thing exists in QtDBus in the future 00900 //KUniqueApplication::dcopClient()->setQtBridgeEnabled(false); 00901 00902 HostnamePollInterval = cg.readEntry("HostnamePollInterval", 5000); 00903 bCheckSycoca = cg.readEntry("CheckSycoca", true); 00904 bCheckUpdates = cg.readEntry("CheckUpdates", true); 00905 bCheckHostname = cg.readEntry("CheckHostname", true); 00906 checkStamps = cg.readEntry("CheckFileStamps", true); 00907 delayedCheck = cg.readEntry("DelayedCheck", false); 00908 00909 Kded *kded = new Kded(); // Build data base 00910 00911 #ifndef _WIN32_WCE 00912 KDE_signal(SIGTERM, sighandler); 00913 #endif 00914 KDE_signal(SIGHUP, sighandler); 00915 KDEDApplication k; 00916 k.setQuitOnLastWindowClosed(false); 00917 00918 KCrash::setFlags(KCrash::AutoRestart); 00919 00920 // Not sure why kded is created before KDEDApplication 00921 // but if it has to be, then it needs to be moved to the main thread 00922 // before it can use timers (DF) 00923 kded->moveToThread( k.thread() ); 00924 00925 int result = k.exec(); // keep running 00926 00927 delete kded; 00928 00929 return result; 00930 } 00931 00932 #include "kded.moc"
KDE 4.6 API Reference