23 #include "kdedmodule.h"
25 #include <kresourcelist.h>
36 #include <dcopclient.h>
38 #include <kuniqueapplication.h>
39 #include <kcmdlineargs.h>
40 #include <kaboutdata.h>
45 #include <kdirwatch.h>
46 #include <kstandarddirs.h>
47 #include <kdatastream.h>
48 #include <kio/global.h>
49 #include <kservicetype.h>
56 Kded *Kded::_self = 0;
58 static bool checkStamps =
true;
59 static bool delayedCheck =
false;
61 static void runBuildSycoca(TQObject *callBackObj=0,
const char *callBackSlot=0)
64 args.append(
"--incremental");
66 args.append(
"--checkstamps");
68 args.append(
"--nocheckfiles");
74 TQDataStream dataStream( data, IO_WriteOnly );
75 dataStream << TQString(
"kbuildsycoca") << args;
76 TQCString _launcher = KApplication::launcher();
78 kapp->dcopClient()->callAsync(_launcher, _launcher,
"kdeinit_exec_wait(TQString,TQStringList)", data, callBackObj, callBackSlot);
82 KApplication::kdeinitExecWait(
"kbuildsycoca", args );
86 static void runKonfUpdate()
88 KApplication::kdeinitExecWait(
"kconf_update", TQStringList(), 0, 0,
"0" );
91 static void runDontChangeHostname(
const TQCString &oldName,
const TQCString &newName)
94 args.append(TQFile::decodeName(oldName));
95 args.append(TQFile::decodeName(newName));
96 KApplication::kdeinitExecWait(
"kdontchangethehostname", args );
99 Kded::Kded(
bool checkUpdates,
bool new_startup)
100 : DCOPObject(
"kbuildsycoca"), DCOPObjectProxy(),
101 b_checkUpdates(checkUpdates),
102 m_needDelayedCheck(false),
103 m_newStartup( new_startup )
107 TQCString ksycoca_env = getenv(
"KDESYCOCA");
108 if (ksycoca_env.isEmpty())
109 cPath = TQFile::encodeName(KGlobal::dirs()->saveLocation(
"tmp")+
"ksycoca");
112 m_pTimer =
new TQTimer(
this);
113 connect(m_pTimer, TQT_SIGNAL(timeout()),
this, TQT_SLOT(recreate()));
115 TQTimer::singleShot(100,
this, TQT_SLOT(installCrashHandler()));
119 m_windowIdList.setAutoDelete(
true);
122 m_recreateBusy =
false;
133 TQAsciiDictIterator<KDEDModule> it(m_modules);
134 while (!it.isEmpty())
138 bool Kded::process(
const TQCString &obj,
const TQCString &fun,
139 const TQByteArray &data,
140 TQCString &replyType, TQByteArray &replyData)
142 if (obj ==
"ksycoca")
return false;
151 module->setCallingDcopClient(kapp->dcopClient());
152 return module->process(fun, data, replyType, replyData);
155 void Kded::initModules()
158 KConfig *config = kapp->config();
159 bool tde_running = !( getenv(
"TDE_FULL_SESSION" ) == NULL || getenv(
"TDE_FULL_SESSION" )[ 0 ] ==
'\0' );
161 if( getenv(
"KDE_SESSION_UID" ) != NULL && uid_t( atoi( getenv(
"KDE_SESSION_UID" ))) != getuid())
164 KService::List kdedModules = KServiceType::offers(
"KDEDModule");
165 TQString version = getenv(
"KDE_SESSION_VERSION" );
166 TQStringList blacklist;
167 if ( !(version == NULL) && version >=
"4" )
169 kdDebug(7020) <<
"KDE4 is running:" << endl;
170 kdDebug(7020) <<
" KDE_SESSION_VERSION: " << version << endl;
171 kdDebug(7020) <<
" Blacklisting mediamanager, medianotifier, kmilod, kwrited." << endl;
172 blacklist <<
"mediamanager" <<
"medianotifier" <<
"kmilod" <<
"kwrited";
174 for(KService::List::ConstIterator it = kdedModules.begin(); it != kdedModules.end(); ++it)
176 KService::Ptr service = *it;
177 bool autoload = service->property(
"X-KDE-Kded-autoload", TQVariant::Bool).toBool();
178 config->setGroup(TQString(
"Module-%1").arg(service->desktopEntryName()));
179 autoload = config->readBoolEntry(
"autoload", autoload);
180 for (TQStringList::Iterator module = blacklist.begin(); module != blacklist.end(); ++module)
182 if (service->desktopEntryName() == *module)
191 TQVariant phasev = service->property(
"X-KDE-Kded-phase", TQVariant::Int );
192 int phase = phasev.isValid() ? phasev.toInt() : 2;
193 bool prevent_autoload =
false;
200 prevent_autoload =
true;
204 prevent_autoload =
true;
207 if (autoload && !prevent_autoload)
208 loadModule(service,
false);
212 if (autoload && tde_running)
213 loadModule(service,
false);
215 bool dontLoad =
false;
216 TQVariant p = service->property(
"X-KDE-Kded-load-on-demand", TQVariant::Bool);
217 if (p.isValid() && (p.toBool() ==
false))
220 noDemandLoad(service->desktopEntryName());
222 if (dontLoad && !autoload)
223 unloadModule(service->desktopEntryName().latin1());
227 void Kded::loadSecondPhase()
229 kdDebug(7020) <<
"Loading second phase autoload" << endl;
230 KConfig *config = kapp->config();
231 KService::List kdedModules = KServiceType::offers(
"KDEDModule");
232 for(KService::List::ConstIterator it = kdedModules.begin(); it != kdedModules.end(); ++it)
234 KService::Ptr service = *it;
235 bool autoload = service->property(
"X-KDE-Kded-autoload", TQVariant::Bool).toBool();
236 config->setGroup(TQString(
"Module-%1").arg(service->desktopEntryName()));
237 autoload = config->readBoolEntry(
"autoload", autoload);
238 TQVariant phasev = service->property(
"X-KDE-Kded-phase", TQVariant::Int );
239 int phase = phasev.isValid() ? phasev.toInt() : 2;
240 if( phase == 2 && autoload )
241 loadModule(service,
false);
245 void Kded::noDemandLoad(
const TQString &obj)
247 m_dontLoad.insert(obj.latin1(),
this);
250 KDEDModule *Kded::loadModule(
const TQCString &obj,
bool onDemand)
255 KService::Ptr s = KService::serviceByDesktopPath(
"kded/"+obj+
".desktop");
256 return loadModule(s, onDemand);
259 KDEDModule *Kded::loadModule(
const KService *s,
bool onDemand)
262 if (s && !s->library().isEmpty())
264 TQCString obj = s->desktopEntryName().latin1();
271 TQVariant p = s->property(
"X-KDE-Kded-load-on-demand", TQVariant::Bool);
272 if (p.isValid() && (p.toBool() ==
false))
274 noDemandLoad(s->desktopEntryName());
280 KLibLoader *loader = KLibLoader::self();
282 TQVariant v = s->property(
"X-KDE-FactoryName", TQVariant::String);
283 TQString factory = v.isValid() ? v.toString() : TQString::null;
284 if (factory.isEmpty())
287 v = s->property(
"X-KDE-Factory", TQVariant::String);
288 factory = v.isValid() ? v.toString() : TQString::null;
290 if (factory.isEmpty())
291 factory = s->library();
293 factory =
"create_" + factory;
294 TQString libname =
"kded_"+s->library();
296 KLibrary *lib = loader->library(TQFile::encodeName(libname));
299 kdWarning() << k_funcinfo <<
"Could not load library. [ "
300 << loader->lastErrorMessage() <<
" ]" << endl;
301 libname.prepend(
"lib");
302 lib = loader->library(TQFile::encodeName(libname));
307 void *create = lib->symbol(TQFile::encodeName(factory));
313 func = (
KDEDModule* (*)(
const TQCString &)) create;
317 m_modules.insert(obj, module);
318 m_libs.insert(obj, lib);
319 connect(module, TQT_SIGNAL(moduleDeleted(
KDEDModule *)), TQT_SLOT(slotKDEDModuleRemoved(
KDEDModule *)));
320 kdDebug(7020) <<
"Successfully loaded module '" << obj <<
"'\n";
324 loader->unloadLibrary(TQFile::encodeName(libname));
328 kdWarning() << k_funcinfo <<
"Could not load library. [ "
329 << loader->lastErrorMessage() <<
" ]" << endl;
331 kdDebug(7020) <<
"Could not load module '" << obj <<
"'\n";
336 bool Kded::unloadModule(
const TQCString &obj)
341 kdDebug(7020) <<
"Unloading module '" << obj <<
"'\n";
347 QCStringList Kded::loadedModules()
349 QCStringList modules;
350 TQAsciiDictIterator<KDEDModule> it( m_modules );
351 for ( ; it.current(); ++it)
352 modules.append( it.currentKey() );
357 QCStringList Kded::functions()
359 QCStringList res = DCOPObject::functions();
360 res +=
"ASYNC recreate()";
364 void Kded::slotKDEDModuleRemoved(
KDEDModule *module)
366 m_modules.remove(module->objId());
367 KLibrary *lib = m_libs.take(module->objId());
372 void Kded::slotApplicationRemoved(
const TQCString &appId)
374 for(TQAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it)
376 it.current()->removeAll(appId);
379 TQValueList<long> *windowIds = m_windowIdList.find(appId);
382 for( TQValueList<long>::ConstIterator it = windowIds->begin();
383 it != windowIds->end(); ++it)
386 m_globalWindowIdList.remove(windowId);
387 for(TQAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it)
389 emit it.current()->windowUnregistered(windowId);
392 m_windowIdList.remove(appId);
396 void Kded::updateDirWatch()
398 if (!b_checkUpdates)
return;
401 m_pDirWatch =
new KDirWatch;
403 TQObject::connect( m_pDirWatch, TQT_SIGNAL(dirty(
const TQString&)),
404 this, TQT_SLOT(update(
const TQString&)));
405 TQObject::connect( m_pDirWatch, TQT_SIGNAL(created(
const TQString&)),
406 this, TQT_SLOT(update(
const TQString&)));
407 TQObject::connect( m_pDirWatch, TQT_SIGNAL(deleted(
const TQString&)),
408 this, TQT_SLOT(dirDeleted(
const TQString&)));
411 for( TQStringList::ConstIterator it = m_allResourceDirs.begin();
412 it != m_allResourceDirs.end();
415 readDirectory( *it );
419 void Kded::updateResourceList()
421 delete KSycoca::self();
423 if (!b_checkUpdates)
return;
425 if (delayedCheck)
return;
427 TQStringList dirs = KSycoca::self()->allResourceDirs();
429 for( TQStringList::ConstIterator it = dirs.begin();
433 if (m_allResourceDirs.find(*it) == m_allResourceDirs.end())
435 m_allResourceDirs.append(*it);
441 void Kded::crashHandler(
int)
443 DCOPClient::emergencyClose();
446 qWarning(
"Last DCOP call before KDED crash was from application '%s'\n"
447 "to object '%s', function '%s'.",
448 DCOPClient::postMortemSender(),
449 DCOPClient::postMortemObject(),
450 DCOPClient::postMortemFunction());
453 void Kded::installCrashHandler()
455 KCrash::setEmergencySaveFunction(crashHandler);
458 void Kded::recreate()
463 void Kded::runDelayedCheck()
465 if( m_needDelayedCheck )
467 m_needDelayedCheck =
false;
470 void Kded::recreate(
bool initial)
472 m_recreateBusy =
true;
479 runBuildSycoca(
this, TQT_SLOT(recreateDone()));
490 TQTimer::singleShot( 60000,
this, TQT_SLOT( runDelayedCheck()));
491 m_needDelayedCheck =
true;
492 delayedCheck =
false;
495 m_needDelayedCheck =
false;
499 void Kded::recreateDone()
501 updateResourceList();
503 for(; m_recreateCount; m_recreateCount--)
505 TQCString replyType =
"void";
506 TQByteArray replyData;
507 DCOPClientTransaction *transaction = m_recreateRequests.first();
509 kapp->dcopClient()->endTransaction(transaction, replyType, replyData);
510 m_recreateRequests.remove(m_recreateRequests.begin());
512 m_recreateBusy =
false;
515 if (!m_recreateRequests.isEmpty())
517 m_pTimer->start(2000,
true );
518 m_recreateCount = m_recreateRequests.count();
522 void Kded::dirDeleted(
const TQString& path)
527 void Kded::update(
const TQString& )
531 m_pTimer->start( 2000,
true );
535 m_recreateRequests.append(0);
539 bool Kded::process(
const TQCString &fun,
const TQByteArray &data,
540 TQCString &replyType, TQByteArray &replyData)
542 if (fun ==
"recreate()") {
545 if (m_recreateRequests.isEmpty())
547 m_pTimer->start(0,
true );
552 m_recreateRequests.append(kapp->dcopClient()->beginTransaction());
556 return DCOPObject::process(fun, data, replyType, replyData);
561 void Kded::readDirectory(
const TQString& _path )
563 TQString path( _path );
564 if ( path.right(1) !=
"/" )
567 if ( m_pDirWatch->contains( path ) )
570 TQDir d( _path, TQString::null, TQDir::Unsorted, TQDir::Readable | TQDir::Executable | TQDir::Dirs | TQDir::Hidden );
578 m_pDirWatch->addDir(path);
582 kdDebug(7020) << TQString(TQString(
"Does not exist! (%1)").arg(_path)) << endl;
593 unsigned int count = d.count();
594 for( i = 0; i < count; i++ )
596 if (d[i] ==
"." || d[i] ==
".." || d[i] ==
"magic")
602 readDirectory( file );
606 bool Kded::isWindowRegistered(
long windowId)
608 return m_globalWindowIdList.find(windowId) != 0;
613 void Kded::registerWindowId(
long windowId)
615 m_globalWindowIdList.replace(windowId, &windowId);
616 TQCString sender = callingDcopClient()->senderId();
617 if( sender.isEmpty())
618 sender = callingDcopClient()->appId();
619 TQValueList<long> *windowIds = m_windowIdList.find(sender);
622 windowIds =
new TQValueList<long>;
623 m_windowIdList.insert(sender, windowIds);
625 windowIds->append(windowId);
628 for(TQAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it)
630 emit it.current()->windowRegistered(windowId);
635 void Kded::unregisterWindowId(
long windowId)
637 m_globalWindowIdList.remove(windowId);
638 TQCString sender = callingDcopClient()->senderId();
639 if( sender.isEmpty())
640 sender = callingDcopClient()->appId();
641 TQValueList<long> *windowIds = m_windowIdList.find(sender);
644 windowIds->remove(windowId);
645 if (windowIds->isEmpty())
646 m_windowIdList.remove(sender);
649 for(TQAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it)
651 emit it.current()->windowUnregistered(windowId);
656 static void sighandler(
int )
664 m_pDirWatch =
new KDirWatch;
665 m_pTimer =
new TQTimer;
666 connect(m_pTimer, TQT_SIGNAL(timeout()),
this, TQT_SLOT(runKonfUpdate()));
667 TQObject::connect( m_pDirWatch, TQT_SIGNAL(dirty(
const TQString&)),
668 this, TQT_SLOT(slotNewUpdateFile()));
670 TQStringList dirs = KGlobal::dirs()->findDirs(
"data",
"kconf_update");
671 for( TQStringList::ConstIterator it = dirs.begin();
676 if (path[path.length()-1] !=
'/')
679 if (!m_pDirWatch->contains(path))
680 m_pDirWatch->addDir(path);
684 KUpdateD::~KUpdateD()
690 void KUpdateD::runKonfUpdate()
695 void KUpdateD::slotNewUpdateFile()
697 m_pTimer->start( 500,
true );
700 KHostnameD::KHostnameD(
int pollInterval)
702 m_Timer.start(pollInterval,
false );
703 connect(&m_Timer, TQT_SIGNAL(timeout()),
this, TQT_SLOT(checkHostname()));
707 KHostnameD::~KHostnameD()
712 void KHostnameD::checkHostname()
715 if (gethostname(buf, 1024) != 0)
717 buf[
sizeof(buf)-1] =
'\0';
719 if (m_hostname.isEmpty())
725 if (m_hostname == buf)
728 TQCString newHostname = buf;
730 runDontChangeHostname(m_hostname, newHostname);
731 m_hostname = newHostname;
735 static KCmdLineOptions options[] =
737 {
"check", I18N_NOOP(
"Check Sycoca database only once"), 0 },
738 {
"new-startup",
"Internal", 0 },
742 class KDEDQtDCOPObject :
public DCOPObject
745 KDEDQtDCOPObject() : DCOPObject(
"qt/kded") { }
747 virtual bool process(
const TQCString &fun,
const TQByteArray &data,
748 TQCString& replyType, TQByteArray &replyData)
750 if ( kapp && (fun ==
"quit()") )
756 return DCOPObject::process(fun, data, replyType, replyData);
759 QCStringList functions()
761 QCStringList res = DCOPObject::functions();
762 res +=
"void quit()";
767 class KDEDApplication :
public KUniqueApplication
770 KDEDApplication() : KUniqueApplication( )
773 dcopClient()->connectDCOPSignal(
"DCOPServer",
"",
"terminateKDE()",
774 objId(),
"quit()",
false );
781 if( Kded::self()->newStartup())
782 Kded::self()->initModules();
784 TQTimer::singleShot(500, Kded::self(), TQT_SLOT(initModules()));
791 QCStringList functions()
793 QCStringList res = KUniqueApplication::functions();
794 res +=
"bool loadModule(TQCString)";
795 res +=
"bool unloadModule(TQCString)";
796 res +=
"void registerWindowId(long int)";
797 res +=
"void unregisterWindowId(long int)";
798 res +=
"QCStringList loadedModules()";
799 res +=
"void reconfigure()";
800 res +=
"void loadSecondPhase()";
801 res +=
"void quit()";
805 bool process(
const TQCString &fun,
const TQByteArray &data,
806 TQCString &replyType, TQByteArray &replyData)
808 if (fun ==
"loadModule(TQCString)") {
810 TQDataStream arg( data, IO_ReadOnly );
812 bool result = (Kded::self()->loadModule(module,
false) != 0);
814 TQDataStream _replyStream( replyData, IO_WriteOnly );
815 _replyStream << result;
818 else if (fun ==
"unloadModule(TQCString)") {
820 TQDataStream arg( data, IO_ReadOnly );
822 bool result = Kded::self()->unloadModule(module);
824 TQDataStream _replyStream( replyData, IO_WriteOnly );
825 _replyStream << result;
828 else if (fun ==
"registerWindowId(long int)") {
830 TQDataStream arg( data, IO_ReadOnly );
832 Kded::self()->setCallingDcopClient(callingDcopClient());
833 Kded::self()->registerWindowId(windowId);
837 else if (fun ==
"unregisterWindowId(long int)") {
839 TQDataStream arg( data, IO_ReadOnly );
841 Kded::self()->setCallingDcopClient(callingDcopClient());
842 Kded::self()->unregisterWindowId(windowId);
846 else if (fun ==
"loadedModules()") {
847 replyType =
"QCStringList";
848 TQDataStream _replyStream(replyData, IO_WriteOnly);
849 _replyStream << Kded::self()->loadedModules();
852 else if (fun ==
"reconfigure()") {
853 config()->reparseConfiguration();
854 Kded::self()->initModules();
858 else if (fun ==
"loadSecondPhase()") {
859 Kded::self()->loadSecondPhase();
863 else if (fun ==
"quit()") {
868 return KUniqueApplication::process(fun, data, replyType, replyData);
872 KDEDQtDCOPObject kdedQtDcopObject;
875 extern "C" KDE_EXPORT
int kdemain(
int argc,
char *argv[])
877 KAboutData aboutData(
"kded", I18N_NOOP(
"KDE Daemon"),
879 I18N_NOOP(
"KDE Daemon - triggers Sycoca database updates when needed"));
881 KApplication::installSigpipeHandler();
883 KCmdLineArgs::init(argc, argv, &aboutData);
885 KUniqueApplication::addCmdLineOptions();
887 KCmdLineArgs::addCmdLineOptions( options );
890 KLocale::setMainCatalogue(
"kdelibs");
893 putenv(strdup(
"SESSION_MANAGER="));
896 KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
901 TQCString dcopName = testDCOP.registerAs(
"kded",
false);
902 if (dcopName.isEmpty())
904 kdFatal() <<
"DCOP communication problem!" << endl;
909 KInstance *instance =
new KInstance(&aboutData);
910 KConfig *config = instance->config();
912 if (args->isSet(
"check"))
914 config->setGroup(
"General");
915 checkStamps = config->readBoolEntry(
"CheckFileStamps",
true);
921 if (!KUniqueApplication::start())
923 fprintf(stderr,
"[kded] Daemon (kded) is already running.\n");
927 KUniqueApplication::dcopClient()->setQtBridgeEnabled(
false);
929 config->setGroup(
"General");
930 int HostnamePollInterval = config->readNumEntry(
"HostnamePollInterval", 5000);
931 bool bCheckSycoca = config->readBoolEntry(
"CheckSycoca",
true);
932 bool bCheckUpdates = config->readBoolEntry(
"CheckUpdates",
true);
933 bool bCheckHostname = config->readBoolEntry(
"CheckHostname",
true);
934 checkStamps = config->readBoolEntry(
"CheckFileStamps",
true);
935 delayedCheck = config->readBoolEntry(
"DelayedCheck",
false);
937 Kded *kded =
new Kded(bCheckSycoca, args->isSet(
"new-startup"));
939 signal(SIGTERM, sighandler);
940 signal(SIGHUP, sighandler);
943 kded->recreate(
true);
951 (void)
new KHostnameD(HostnamePollInterval);
953 DCOPClient *client = kapp->dcopClient();
954 TQObject::connect(client, TQT_SIGNAL(applicationRemoved(
const TQCString&)),
955 kded, TQT_SLOT(slotApplicationRemoved(
const TQCString&)));
956 client->setNotifications(
true);
957 client->setDaemonMode(
true );
966 client->send(
"*",
"ksycoca",
"notifyDatabaseChanged()", data );
967 client->send(
"ksplash",
"",
"upAndRunning(TQString)", TQString(
"kded"));
970 e.xclient.type = ClientMessage;
971 e.xclient.message_type = XInternAtom( qt_xdisplay(),
"_KDE_SPLASH_PROGRESS", False );
972 e.xclient.display = qt_xdisplay();
973 e.xclient.window = qt_xrootwin();
974 e.xclient.format = 8;
975 strcpy( e.xclient.data.b,
"kded" );
976 XSendEvent( qt_xdisplay(), qt_xrootwin(), False, SubstructureNotifyMask, &e );
978 int result = k.exec();