23 #include "kdedmodule.h"
25 #include <kresourcelist.h>
36 #include <dcopclient.h>
38 #include <tdeuniqueapplication.h>
39 #include <tdecmdlineargs.h>
40 #include <tdeaboutdata.h>
41 #include <tdelocale.h>
42 #include <tdeglobal.h>
43 #include <tdeprocess.h>
45 #include <kdirwatch.h>
46 #include <kstandarddirs.h>
47 #include <kdatastream.h>
48 #include <tdeio/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(
"tdebuildsycoca") << args;
76 TQCString _launcher = TDEApplication::launcher();
78 kapp->dcopClient()->callAsync(_launcher, _launcher,
"tdeinit_exec_wait(TQString,TQStringList)", data, callBackObj, callBackSlot);
82 TDEApplication::tdeinitExecWait(
"tdebuildsycoca", args );
86 static void runKonfUpdate()
88 TDEApplication::tdeinitExecWait(
"tdeconf_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 TDEApplication::tdeinitExecWait(
"kdontchangethehostname", args );
99 Kded::Kded(
bool checkUpdates,
bool new_startup)
100 : DCOPObject(
"tdebuildsycoca"), DCOPObjectProxy(),
101 b_checkUpdates(checkUpdates),
102 m_needDelayedCheck(false),
103 m_newStartup( new_startup )
107 TQCString tdesycoca_env = getenv(
"TDESYCOCA");
108 if (tdesycoca_env.isEmpty())
109 cPath = TQFile::encodeName(TDEGlobal::dirs()->saveLocation(
"tmp")+
"tdesycoca");
111 cPath = tdesycoca_env;
112 m_pTimer =
new TQTimer(
this);
113 connect(m_pTimer, TQ_SIGNAL(timeout()),
this, TQ_SLOT(recreate()));
115 TQTimer::singleShot(100,
this, TQ_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 ==
"tdesycoca")
return false;
151 module->setCallingDcopClient(kapp->dcopClient());
152 return module->process(fun, data, replyType, replyData);
155 void Kded::initModules()
158 TDEConfig *config = kapp->config();
159 bool tde_running = !( getenv(
"TDE_FULL_SESSION" ) == NULL || getenv(
"TDE_FULL_SESSION" )[ 0 ] ==
'\0' );
161 if( getenv(
"TDE_SESSION_UID" ) != NULL && uid_t( atoi( getenv(
"TDE_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-TDE-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-TDE-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-TDE-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 TDEConfig *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-TDE-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-TDE-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-TDE-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-TDE-FactoryName", TQVariant::String);
283 TQString factory = v.isValid() ? v.toString() : TQString::null;
284 if (factory.isEmpty())
287 v = s->property(
"X-TDE-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, TQ_SIGNAL(moduleDeleted(
KDEDModule *)), TQ_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, TQ_SIGNAL(dirty(
const TQString&)),
404 this, TQ_SLOT(update(
const TQString&)));
405 TQObject::connect( m_pDirWatch, TQ_SIGNAL(created(
const TQString&)),
406 this, TQ_SLOT(update(
const TQString&)));
407 TQObject::connect( m_pDirWatch, TQ_SIGNAL(deleted(
const TQString&)),
408 this, TQ_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();
445 tqWarning(
"Last DCOP call before KDED crash was from application '%s'\n"
446 "to object '%s', function '%s'.",
447 DCOPClient::postMortemSender(),
448 DCOPClient::postMortemObject(),
449 DCOPClient::postMortemFunction());
450 tqWarning(
"Restarting KDED...\n");
451 if (system(
"kded") < 0) {
452 tqWarning(
"Unable to restart KDED!\n");
457 void Kded::installCrashHandler()
459 TDECrash::setEmergencySaveFunction(crashHandler);
462 void Kded::recreate()
467 void Kded::runDelayedCheck()
469 if( m_needDelayedCheck )
471 m_needDelayedCheck =
false;
474 void Kded::recreate(
bool initial)
476 m_recreateBusy =
true;
483 runBuildSycoca(
this, TQ_SLOT(recreateDone()));
494 TQTimer::singleShot( 60000,
this, TQ_SLOT( runDelayedCheck()));
495 m_needDelayedCheck =
true;
496 delayedCheck =
false;
499 m_needDelayedCheck =
false;
503 void Kded::recreateDone()
505 updateResourceList();
507 for(; m_recreateCount; m_recreateCount--)
509 TQCString replyType =
"void";
510 TQByteArray replyData;
511 DCOPClientTransaction *transaction = m_recreateRequests.first();
513 kapp->dcopClient()->endTransaction(transaction, replyType, replyData);
514 m_recreateRequests.remove(m_recreateRequests.begin());
516 m_recreateBusy =
false;
519 if (!m_recreateRequests.isEmpty())
521 m_pTimer->start(2000,
true );
522 m_recreateCount = m_recreateRequests.count();
526 void Kded::dirDeleted(
const TQString& path)
531 void Kded::update(
const TQString& )
535 m_pTimer->start( 2000,
true );
539 m_recreateRequests.append(0);
543 bool Kded::process(
const TQCString &fun,
const TQByteArray &data,
544 TQCString &replyType, TQByteArray &replyData)
546 if (fun ==
"recreate()") {
549 if (m_recreateRequests.isEmpty())
551 m_pTimer->start(0,
true );
556 m_recreateRequests.append(kapp->dcopClient()->beginTransaction());
560 return DCOPObject::process(fun, data, replyType, replyData);
565 void Kded::readDirectory(
const TQString& _path )
567 TQString path( _path );
568 if ( path.right(1) !=
"/" )
571 if ( m_pDirWatch->contains( path ) )
574 TQDir d( _path, TQString::null, TQDir::Unsorted, TQDir::Readable | TQDir::Executable | TQDir::Dirs | TQDir::Hidden );
582 m_pDirWatch->addDir(path);
586 kdDebug(7020) << TQString(TQString(
"Does not exist! (%1)").arg(_path)) << endl;
597 unsigned int count = d.count();
598 for( i = 0; i < count; i++ )
600 if (d[i] ==
"." || d[i] ==
".." || d[i] ==
"magic")
606 readDirectory( file );
610 bool Kded::isWindowRegistered(
long windowId)
612 return m_globalWindowIdList.find(windowId) != 0;
617 void Kded::registerWindowId(
long windowId)
619 m_globalWindowIdList.replace(windowId, &windowId);
620 TQCString sender = callingDcopClient()->senderId();
621 if( sender.isEmpty())
622 sender = callingDcopClient()->appId();
623 TQValueList<long> *windowIds = m_windowIdList.find(sender);
626 windowIds =
new TQValueList<long>;
627 m_windowIdList.insert(sender, windowIds);
629 windowIds->append(windowId);
632 for(TQAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it)
634 emit it.current()->windowRegistered(windowId);
639 void Kded::unregisterWindowId(
long windowId)
641 m_globalWindowIdList.remove(windowId);
642 TQCString sender = callingDcopClient()->senderId();
643 if( sender.isEmpty())
644 sender = callingDcopClient()->appId();
645 TQValueList<long> *windowIds = m_windowIdList.find(sender);
648 windowIds->remove(windowId);
649 if (windowIds->isEmpty())
650 m_windowIdList.remove(sender);
653 for(TQAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it)
655 emit it.current()->windowUnregistered(windowId);
660 static void sighandler(
int )
668 m_pDirWatch =
new KDirWatch;
669 m_pTimer =
new TQTimer;
670 connect(m_pTimer, TQ_SIGNAL(timeout()),
this, TQ_SLOT(runKonfUpdate()));
671 TQObject::connect( m_pDirWatch, TQ_SIGNAL(dirty(
const TQString&)),
672 this, TQ_SLOT(slotNewUpdateFile()));
674 TQStringList dirs = TDEGlobal::dirs()->findDirs(
"data",
"tdeconf_update");
675 for( TQStringList::ConstIterator it = dirs.begin();
680 if (path[path.length()-1] !=
'/')
683 if (!m_pDirWatch->contains(path))
684 m_pDirWatch->addDir(path);
688 KUpdateD::~KUpdateD()
694 void KUpdateD::runKonfUpdate()
699 void KUpdateD::slotNewUpdateFile()
701 m_pTimer->start( 500,
true );
704 KHostnameD::KHostnameD(
int pollInterval)
706 m_Timer.start(pollInterval,
false );
707 connect(&m_Timer, TQ_SIGNAL(timeout()),
this, TQ_SLOT(checkHostname()));
711 KHostnameD::~KHostnameD()
716 void KHostnameD::checkHostname()
719 if (gethostname(buf, 1024) != 0)
721 buf[
sizeof(buf)-1] =
'\0';
723 if (m_hostname.isEmpty())
729 if (m_hostname == buf)
732 TQCString newHostname = buf;
734 runDontChangeHostname(m_hostname, newHostname);
735 m_hostname = newHostname;
739 static TDECmdLineOptions options[] =
741 {
"check", I18N_NOOP(
"Check Sycoca database only once"), 0 },
742 {
"new-startup",
"Internal", 0 },
746 class KDEDQtDCOPObject :
public DCOPObject
749 KDEDQtDCOPObject() : DCOPObject(
"qt/kded") { }
751 virtual bool process(
const TQCString &fun,
const TQByteArray &data,
752 TQCString& replyType, TQByteArray &replyData)
754 if ( kapp && (fun ==
"quit()") )
760 return DCOPObject::process(fun, data, replyType, replyData);
763 QCStringList functions()
765 QCStringList res = DCOPObject::functions();
766 res +=
"void quit()";
771 class KDEDApplication :
public TDEUniqueApplication
774 KDEDApplication() : TDEUniqueApplication( )
777 dcopClient()->connectDCOPSignal(
"DCOPServer",
"",
"terminateTDE()",
778 objId(),
"quit()",
false );
785 if( Kded::self()->newStartup())
786 Kded::self()->initModules();
788 TQTimer::singleShot(500, Kded::self(), TQ_SLOT(initModules()));
795 QCStringList functions()
797 QCStringList res = TDEUniqueApplication::functions();
798 res +=
"bool loadModule(TQCString)";
799 res +=
"bool unloadModule(TQCString)";
800 res +=
"void registerWindowId(long int)";
801 res +=
"void unregisterWindowId(long int)";
802 res +=
"QCStringList loadedModules()";
803 res +=
"void reconfigure()";
804 res +=
"void loadSecondPhase()";
805 res +=
"void quit()";
809 bool process(
const TQCString &fun,
const TQByteArray &data,
810 TQCString &replyType, TQByteArray &replyData)
812 if (fun ==
"loadModule(TQCString)") {
814 TQDataStream arg( data, IO_ReadOnly );
816 bool result = (Kded::self()->loadModule(module,
false) != 0);
818 TQDataStream _replyStream( replyData, IO_WriteOnly );
819 _replyStream << result;
822 else if (fun ==
"unloadModule(TQCString)") {
824 TQDataStream arg( data, IO_ReadOnly );
826 bool result = Kded::self()->unloadModule(module);
828 TQDataStream _replyStream( replyData, IO_WriteOnly );
829 _replyStream << result;
832 else if (fun ==
"registerWindowId(long int)") {
834 TQDataStream arg( data, IO_ReadOnly );
836 Kded::self()->setCallingDcopClient(callingDcopClient());
837 Kded::self()->registerWindowId(windowId);
841 else if (fun ==
"unregisterWindowId(long int)") {
843 TQDataStream arg( data, IO_ReadOnly );
845 Kded::self()->setCallingDcopClient(callingDcopClient());
846 Kded::self()->unregisterWindowId(windowId);
850 else if (fun ==
"loadedModules()") {
851 replyType =
"QCStringList";
852 TQDataStream _replyStream(replyData, IO_WriteOnly);
853 _replyStream << Kded::self()->loadedModules();
856 else if (fun ==
"reconfigure()") {
857 config()->reparseConfiguration();
858 Kded::self()->initModules();
862 else if (fun ==
"loadSecondPhase()") {
863 Kded::self()->loadSecondPhase();
867 else if (fun ==
"quit()") {
872 return TDEUniqueApplication::process(fun, data, replyType, replyData);
876 KDEDQtDCOPObject kdedQtDcopObject;
879 extern "C" TDE_EXPORT
int kdemain(
int argc,
char *argv[])
881 TDEAboutData aboutData(
"kded", I18N_NOOP(
"TDE Daemon"),
883 I18N_NOOP(
"TDE Daemon - triggers Sycoca database updates when needed"));
885 TDEApplication::installSigpipeHandler();
887 TDECmdLineArgs::init(argc, argv, &aboutData);
889 TDEUniqueApplication::addCmdLineOptions();
891 TDECmdLineArgs::addCmdLineOptions( options );
894 TDELocale::setMainCatalogue(
"tdelibs");
897 putenv(strdup(
"SESSION_MANAGER="));
900 TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
905 TQCString dcopName = testDCOP.registerAs(
"kded",
false);
906 if (dcopName.isEmpty())
908 kdFatal() <<
"DCOP communication problem!" << endl;
913 TDEInstance *instance =
new TDEInstance(&aboutData);
914 TDEConfig *config = instance->config();
916 if (args->isSet(
"check"))
918 config->setGroup(
"General");
919 checkStamps = config->readBoolEntry(
"CheckFileStamps",
true);
925 if (!TDEUniqueApplication::start())
927 fprintf(stderr,
"[kded] Daemon (kded) is already running.\n");
931 TDEUniqueApplication::dcopClient()->setQtBridgeEnabled(
false);
933 config->setGroup(
"General");
934 int HostnamePollInterval = config->readNumEntry(
"HostnamePollInterval", 5000);
935 bool bCheckSycoca = config->readBoolEntry(
"CheckSycoca",
true);
936 bool bCheckUpdates = config->readBoolEntry(
"CheckUpdates",
true);
937 bool bCheckHostname = config->readBoolEntry(
"CheckHostname",
true);
938 checkStamps = config->readBoolEntry(
"CheckFileStamps",
true);
939 delayedCheck = config->readBoolEntry(
"DelayedCheck",
false);
941 Kded *kded =
new Kded(bCheckSycoca, args->isSet(
"new-startup"));
943 signal(SIGTERM, sighandler);
944 signal(SIGHUP, sighandler);
947 kded->recreate(
true);
955 (void)
new KHostnameD(HostnamePollInterval);
957 DCOPClient *client = kapp->dcopClient();
958 TQObject::connect(client, TQ_SIGNAL(applicationRemoved(
const TQCString&)),
959 kded, TQ_SLOT(slotApplicationRemoved(
const TQCString&)));
960 client->setNotifications(
true);
961 client->setDaemonMode(
true );
970 client->send(
"*",
"tdesycoca",
"notifyDatabaseChanged()", data );
971 client->send(
"ksplash",
"",
"upAndRunning(TQString)", TQString(
"kded"));
974 e.xclient.type = ClientMessage;
975 e.xclient.message_type = XInternAtom( tqt_xdisplay(),
"_KDE_SPLASH_PROGRESS", False );
976 e.xclient.display = tqt_xdisplay();
977 e.xclient.window = tqt_xrootwin();
978 e.xclient.format = 8;
979 strcpy( e.xclient.data.b,
"kded" );
980 XSendEvent( tqt_xdisplay(), tqt_xrootwin(), False, SubstructureNotifyMask, &e );
982 int result = k.exec();
The base class for KDED modules.
TDEShared * find(const TQCString &app, const TQCString &key)
Lookup object indexed with app and key.