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