TDE core libraries
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

kded.cpp 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990
  1. /* This file is part of the KDE libraries
  2. * Copyright (C) 1999 David Faure <faure@kde.org>
  3. * Copyright (C) 2000 Waldo Bastian <bastian@kde.org>
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Library General Public
  7. * License version 2 as published by the Free Software Foundation;
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public License
  15. * along with this library; see the file COPYING.LIB. If not, write to
  16. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  17. * Boston, MA 02110-1301, USA.
  18. **/
  19. #include <tqdir.h>
  20. #include "kded.h"
  21. #include "kdedmodule.h"
  22. #include <kresourcelist.h>
  23. #include <kcrash.h>
  24. #include <unistd.h>
  25. #include <stdlib.h>
  26. #include <signal.h>
  27. #include <time.h>
  28. #include <tqfile.h>
  29. #include <tqtimer.h>
  30. #include <dcopclient.h>
  31. #include <kuniqueapplication.h>
  32. #include <tdecmdlineargs.h>
  33. #include <tdeaboutdata.h>
  34. #include <tdelocale.h>
  35. #include <tdeglobal.h>
  36. #include <kprocess.h>
  37. #include <kdebug.h>
  38. #include <kdirwatch.h>
  39. #include <kstandarddirs.h>
  40. #include <kdatastream.h>
  41. #include <tdeio/global.h>
  42. #include <kservicetype.h>
  43. #ifdef Q_WS_X11
  44. #include <X11/Xlib.h>
  45. #include <fixx11h.h>
  46. #endif
  47. Kded *Kded::_self = 0;
  48. static bool checkStamps = true;
  49. static bool delayedCheck = false;
  50. static void runBuildSycoca(TQObject *callBackObj=0, const char *callBackSlot=0)
  51. {
  52. TQStringList args;
  53. args.append("--incremental");
  54. if(checkStamps)
  55. args.append("--checkstamps");
  56. if(delayedCheck)
  57. args.append("--nocheckfiles");
  58. else
  59. checkStamps = false; // useful only during kded startup
  60. if (callBackObj)
  61. {
  62. TQByteArray data;
  63. TQDataStream dataStream( data, IO_WriteOnly );
  64. dataStream << TQString("tdebuildsycoca") << args;
  65. TQCString _launcher = TDEApplication::launcher();
  66. kapp->dcopClient()->callAsync(_launcher, _launcher, "tdeinit_exec_wait(TQString,TQStringList)", data, callBackObj, callBackSlot);
  67. }
  68. else
  69. {
  70. TDEApplication::tdeinitExecWait( "tdebuildsycoca", args );
  71. }
  72. }
  73. static void runKonfUpdate()
  74. {
  75. TDEApplication::tdeinitExecWait( "tdeconf_update", TQStringList(), 0, 0, "0" /*no startup notification*/ );
  76. }
  77. static void runDontChangeHostname(const TQCString &oldName, const TQCString &newName)
  78. {
  79. TQStringList args;
  80. args.append(TQFile::decodeName(oldName));
  81. args.append(TQFile::decodeName(newName));
  82. TDEApplication::tdeinitExecWait( "kdontchangethehostname", args );
  83. }
  84. Kded::Kded(bool checkUpdates, bool new_startup)
  85. : DCOPObject("tdebuildsycoca"), DCOPObjectProxy(),
  86. b_checkUpdates(checkUpdates),
  87. m_needDelayedCheck(false),
  88. m_newStartup( new_startup )
  89. {
  90. _self = this;
  91. TQCString cPath;
  92. TQCString tdesycoca_env = getenv("TDESYCOCA");
  93. if (tdesycoca_env.isEmpty())
  94. cPath = TQFile::encodeName(TDEGlobal::dirs()->saveLocation("tmp")+"tdesycoca");
  95. else
  96. cPath = tdesycoca_env;
  97. m_pTimer = new TQTimer(this);
  98. connect(m_pTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(recreate()));
  99. TQTimer::singleShot(100, this, TQT_SLOT(installCrashHandler()));
  100. m_pDirWatch = 0;
  101. m_windowIdList.setAutoDelete(true);
  102. m_recreateCount = 0;
  103. m_recreateBusy = false;
  104. }
  105. Kded::~Kded()
  106. {
  107. _self = 0;
  108. m_pTimer->stop();
  109. delete m_pTimer;
  110. delete m_pDirWatch;
  111. // We have to delete the modules while we're still able to process incoming
  112. // DCOP messages, since modules might make DCOP calls in their destructors.
  113. TQAsciiDictIterator<KDEDModule> it(m_modules);
  114. while (!it.isEmpty())
  115. delete it.toFirst();
  116. }
  117. bool Kded::process(const TQCString &obj, const TQCString &fun,
  118. const TQByteArray &data,
  119. TQCString &replyType, TQByteArray &replyData)
  120. {
  121. if (obj == "tdesycoca") return false; // Ignore this one.
  122. if (m_dontLoad[obj])
  123. return false;
  124. KDEDModule *module = loadModule(obj, true);
  125. if (!module)
  126. return false;
  127. module->setCallingDcopClient(kapp->dcopClient());
  128. return module->process(fun, data, replyType, replyData);
  129. }
  130. void Kded::initModules()
  131. {
  132. m_dontLoad.clear();
  133. TDEConfig *config = kapp->config();
  134. bool tde_running = !( getenv( "TDE_FULL_SESSION" ) == NULL || getenv( "TDE_FULL_SESSION" )[ 0 ] == '\0' );
  135. // not the same user like the one running the session (most likely we're run via sudo or something)
  136. if( getenv( "TDE_SESSION_UID" ) != NULL && uid_t( atoi( getenv( "TDE_SESSION_UID" ))) != getuid())
  137. tde_running = false;
  138. // Preload kded modules.
  139. KService::List kdedModules = KServiceType::offers("KDEDModule");
  140. TQString version = getenv( "KDE_SESSION_VERSION" );
  141. TQStringList blacklist;
  142. if ( !(version == NULL) && version >= "4" )
  143. {
  144. kdDebug(7020) << "KDE4 is running:" << endl;
  145. kdDebug(7020) << " KDE_SESSION_VERSION: " << version << endl;
  146. kdDebug(7020) << " Blacklisting mediamanager, medianotifier, kmilod, kwrited." << endl;
  147. blacklist << "mediamanager" << "medianotifier" << "kmilod" << "kwrited";
  148. }
  149. for(KService::List::ConstIterator it = kdedModules.begin(); it != kdedModules.end(); ++it)
  150. {
  151. KService::Ptr service = *it;
  152. bool autoload = service->property("X-TDE-Kded-autoload", TQVariant::Bool).toBool();
  153. config->setGroup(TQString("Module-%1").arg(service->desktopEntryName()));
  154. autoload = config->readBoolEntry("autoload", autoload);
  155. for (TQStringList::Iterator module = blacklist.begin(); module != blacklist.end(); ++module)
  156. {
  157. if (service->desktopEntryName() == *module)
  158. {
  159. autoload = false;
  160. break;
  161. }
  162. }
  163. if( m_newStartup )
  164. {
  165. // see ksmserver's README for description of the phases
  166. TQVariant phasev = service->property("X-TDE-Kded-phase", TQVariant::Int );
  167. int phase = phasev.isValid() ? phasev.toInt() : 2;
  168. bool prevent_autoload = false;
  169. switch( phase )
  170. {
  171. case 0: // always autoload
  172. break;
  173. case 1: // autoload only in TDE
  174. if( !tde_running )
  175. prevent_autoload = true;
  176. break;
  177. case 2: // autoload delayed, only in TDE
  178. default:
  179. prevent_autoload = true;
  180. break;
  181. }
  182. if (autoload && !prevent_autoload)
  183. loadModule(service, false);
  184. }
  185. else
  186. {
  187. if (autoload && tde_running)
  188. loadModule(service, false);
  189. }
  190. bool dontLoad = false;
  191. TQVariant p = service->property("X-TDE-Kded-load-on-demand", TQVariant::Bool);
  192. if (p.isValid() && (p.toBool() == false))
  193. dontLoad = true;
  194. if (dontLoad)
  195. noDemandLoad(service->desktopEntryName());
  196. if (dontLoad && !autoload)
  197. unloadModule(service->desktopEntryName().latin1());
  198. }
  199. }
  200. void Kded::loadSecondPhase()
  201. {
  202. kdDebug(7020) << "Loading second phase autoload" << endl;
  203. TDEConfig *config = kapp->config();
  204. KService::List kdedModules = KServiceType::offers("KDEDModule");
  205. for(KService::List::ConstIterator it = kdedModules.begin(); it != kdedModules.end(); ++it)
  206. {
  207. KService::Ptr service = *it;
  208. bool autoload = service->property("X-TDE-Kded-autoload", TQVariant::Bool).toBool();
  209. config->setGroup(TQString("Module-%1").arg(service->desktopEntryName()));
  210. autoload = config->readBoolEntry("autoload", autoload);
  211. TQVariant phasev = service->property("X-TDE-Kded-phase", TQVariant::Int );
  212. int phase = phasev.isValid() ? phasev.toInt() : 2;
  213. if( phase == 2 && autoload )
  214. loadModule(service, false);
  215. }
  216. }
  217. void Kded::noDemandLoad(const TQString &obj)
  218. {
  219. m_dontLoad.insert(obj.latin1(), this);
  220. }
  221. KDEDModule *Kded::loadModule(const TQCString &obj, bool onDemand)
  222. {
  223. KDEDModule *module = m_modules.find(obj);
  224. if (module)
  225. return module;
  226. KService::Ptr s = KService::serviceByDesktopPath("kded/"+obj+".desktop");
  227. return loadModule(s, onDemand);
  228. }
  229. KDEDModule *Kded::loadModule(const KService *s, bool onDemand)
  230. {
  231. KDEDModule *module = 0;
  232. if (s && !s->library().isEmpty())
  233. {
  234. TQCString obj = s->desktopEntryName().latin1();
  235. KDEDModule *oldModule = m_modules.find(obj);
  236. if (oldModule)
  237. return oldModule;
  238. if (onDemand)
  239. {
  240. TQVariant p = s->property("X-TDE-Kded-load-on-demand", TQVariant::Bool);
  241. if (p.isValid() && (p.toBool() == false))
  242. {
  243. noDemandLoad(s->desktopEntryName());
  244. return 0;
  245. }
  246. }
  247. // get the library loader instance
  248. KLibLoader *loader = KLibLoader::self();
  249. TQVariant v = s->property("X-TDE-FactoryName", TQVariant::String);
  250. TQString factory = v.isValid() ? v.toString() : TQString::null;
  251. if (factory.isEmpty())
  252. {
  253. // Stay bugward compatible
  254. v = s->property("X-TDE-Factory", TQVariant::String);
  255. factory = v.isValid() ? v.toString() : TQString::null;
  256. }
  257. if (factory.isEmpty())
  258. factory = s->library();
  259. factory = "create_" + factory;
  260. TQString libname = "kded_"+s->library();
  261. KLibrary *lib = loader->library(TQFile::encodeName(libname));
  262. if (!lib)
  263. {
  264. kdWarning() << k_funcinfo << "Could not load library. [ "
  265. << loader->lastErrorMessage() << " ]" << endl;
  266. libname.prepend("lib");
  267. lib = loader->library(TQFile::encodeName(libname));
  268. }
  269. if (lib)
  270. {
  271. // get the create_ function
  272. void *create = lib->symbol(TQFile::encodeName(factory));
  273. if (create)
  274. {
  275. // create the module
  276. KDEDModule* (*func)(const TQCString &);
  277. func = (KDEDModule* (*)(const TQCString &)) create;
  278. module = func(obj);
  279. if (module)
  280. {
  281. m_modules.insert(obj, module);
  282. m_libs.insert(obj, lib);
  283. connect(module, TQT_SIGNAL(moduleDeleted(KDEDModule *)), TQT_SLOT(slotKDEDModuleRemoved(KDEDModule *)));
  284. kdDebug(7020) << "Successfully loaded module '" << obj << "'\n";
  285. return module;
  286. }
  287. }
  288. loader->unloadLibrary(TQFile::encodeName(libname));
  289. }
  290. else
  291. {
  292. kdWarning() << k_funcinfo << "Could not load library. [ "
  293. << loader->lastErrorMessage() << " ]" << endl;
  294. }
  295. kdDebug(7020) << "Could not load module '" << obj << "'\n";
  296. }
  297. return 0;
  298. }
  299. bool Kded::unloadModule(const TQCString &obj)
  300. {
  301. KDEDModule *module = m_modules.take(obj);
  302. if (!module)
  303. return false;
  304. kdDebug(7020) << "Unloading module '" << obj << "'\n";
  305. delete module;
  306. return true;
  307. }
  308. // DCOP
  309. QCStringList Kded::loadedModules()
  310. {
  311. QCStringList modules;
  312. TQAsciiDictIterator<KDEDModule> it( m_modules );
  313. for ( ; it.current(); ++it)
  314. modules.append( it.currentKey() );
  315. return modules;
  316. }
  317. QCStringList Kded::functions()
  318. {
  319. QCStringList res = DCOPObject::functions();
  320. res += "ASYNC recreate()";
  321. return res;
  322. }
  323. void Kded::slotKDEDModuleRemoved(KDEDModule *module)
  324. {
  325. m_modules.remove(module->objId());
  326. KLibrary *lib = m_libs.take(module->objId());
  327. if (lib)
  328. lib->unload();
  329. }
  330. void Kded::slotApplicationRemoved(const TQCString &appId)
  331. {
  332. for(TQAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it)
  333. {
  334. it.current()->removeAll(appId);
  335. }
  336. TQValueList<long> *windowIds = m_windowIdList.find(appId);
  337. if (windowIds)
  338. {
  339. for( TQValueList<long>::ConstIterator it = windowIds->begin();
  340. it != windowIds->end(); ++it)
  341. {
  342. long windowId = *it;
  343. m_globalWindowIdList.remove(windowId);
  344. for(TQAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it)
  345. {
  346. emit it.current()->windowUnregistered(windowId);
  347. }
  348. }
  349. m_windowIdList.remove(appId);
  350. }
  351. }
  352. void Kded::updateDirWatch()
  353. {
  354. if (!b_checkUpdates) return;
  355. delete m_pDirWatch;
  356. m_pDirWatch = new KDirWatch;
  357. TQObject::connect( m_pDirWatch, TQT_SIGNAL(dirty(const TQString&)),
  358. this, TQT_SLOT(update(const TQString&)));
  359. TQObject::connect( m_pDirWatch, TQT_SIGNAL(created(const TQString&)),
  360. this, TQT_SLOT(update(const TQString&)));
  361. TQObject::connect( m_pDirWatch, TQT_SIGNAL(deleted(const TQString&)),
  362. this, TQT_SLOT(dirDeleted(const TQString&)));
  363. // For each resource
  364. for( TQStringList::ConstIterator it = m_allResourceDirs.begin();
  365. it != m_allResourceDirs.end();
  366. ++it )
  367. {
  368. readDirectory( *it );
  369. }
  370. }
  371. void Kded::updateResourceList()
  372. {
  373. delete KSycoca::self();
  374. if (!b_checkUpdates) return;
  375. if (delayedCheck) return;
  376. TQStringList dirs = KSycoca::self()->allResourceDirs();
  377. // For each resource
  378. for( TQStringList::ConstIterator it = dirs.begin();
  379. it != dirs.end();
  380. ++it )
  381. {
  382. if (m_allResourceDirs.find(*it) == m_allResourceDirs.end())
  383. {
  384. m_allResourceDirs.append(*it);
  385. readDirectory(*it);
  386. }
  387. }
  388. }
  389. void Kded::crashHandler(int)
  390. {
  391. DCOPClient::emergencyClose();
  392. if (_self) { // Don't restart if we were closing down
  393. tqWarning("Last DCOP call before KDED crash was from application '%s'\n"
  394. "to object '%s', function '%s'.",
  395. DCOPClient::postMortemSender(),
  396. DCOPClient::postMortemObject(),
  397. DCOPClient::postMortemFunction());
  398. tqWarning("Restarting KDED...\n");
  399. if (system("kded") < 0) {
  400. tqWarning("Unable to restart KDED!\n");
  401. }
  402. }
  403. }
  404. void Kded::installCrashHandler()
  405. {
  406. TDECrash::setEmergencySaveFunction(crashHandler);
  407. }
  408. void Kded::recreate()
  409. {
  410. recreate(false);
  411. }
  412. void Kded::runDelayedCheck()
  413. {
  414. if( m_needDelayedCheck )
  415. recreate(false);
  416. m_needDelayedCheck = false;
  417. }
  418. void Kded::recreate(bool initial)
  419. {
  420. m_recreateBusy = true;
  421. // Using TDELauncher here is difficult since we might not have a
  422. // database
  423. if (!initial)
  424. {
  425. updateDirWatch(); // Update tree first, to be sure to miss nothing.
  426. runBuildSycoca(this, TQT_SLOT(recreateDone()));
  427. }
  428. else
  429. {
  430. if(!delayedCheck)
  431. updateDirWatch(); // this would search all the directories
  432. runBuildSycoca();
  433. recreateDone();
  434. if(delayedCheck)
  435. {
  436. // do a proper tdesycoca check after a delay
  437. TQTimer::singleShot( 60000, this, TQT_SLOT( runDelayedCheck()));
  438. m_needDelayedCheck = true;
  439. delayedCheck = false;
  440. }
  441. else
  442. m_needDelayedCheck = false;
  443. }
  444. }
  445. void Kded::recreateDone()
  446. {
  447. updateResourceList();
  448. for(; m_recreateCount; m_recreateCount--)
  449. {
  450. TQCString replyType = "void";
  451. TQByteArray replyData;
  452. DCOPClientTransaction *transaction = m_recreateRequests.first();
  453. if (transaction)
  454. kapp->dcopClient()->endTransaction(transaction, replyType, replyData);
  455. m_recreateRequests.remove(m_recreateRequests.begin());
  456. }
  457. m_recreateBusy = false;
  458. // Did a new request come in while building?
  459. if (!m_recreateRequests.isEmpty())
  460. {
  461. m_pTimer->start(2000, true /* single shot */ );
  462. m_recreateCount = m_recreateRequests.count();
  463. }
  464. }
  465. void Kded::dirDeleted(const TQString& path)
  466. {
  467. update(path);
  468. }
  469. void Kded::update(const TQString& )
  470. {
  471. if (!m_recreateBusy)
  472. {
  473. m_pTimer->start( 2000, true /* single shot */ );
  474. }
  475. else
  476. {
  477. m_recreateRequests.append(0);
  478. }
  479. }
  480. bool Kded::process(const TQCString &fun, const TQByteArray &data,
  481. TQCString &replyType, TQByteArray &replyData)
  482. {
  483. if (fun == "recreate()") {
  484. if (!m_recreateBusy)
  485. {
  486. if (m_recreateRequests.isEmpty())
  487. {
  488. m_pTimer->start(0, true /* single shot */ );
  489. m_recreateCount = 0;
  490. }
  491. m_recreateCount++;
  492. }
  493. m_recreateRequests.append(kapp->dcopClient()->beginTransaction());
  494. replyType = "void";
  495. return true;
  496. } else {
  497. return DCOPObject::process(fun, data, replyType, replyData);
  498. }
  499. }
  500. void Kded::readDirectory( const TQString& _path )
  501. {
  502. TQString path( _path );
  503. if ( path.right(1) != "/" )
  504. path += "/";
  505. if ( m_pDirWatch->contains( path ) ) // Already seen this one?
  506. return;
  507. TQDir d( _path, TQString::null, TQDir::Unsorted, TQDir::Readable | TQDir::Executable | TQDir::Dirs | TQDir::Hidden );
  508. // set TQDir ...
  509. //************************************************************************
  510. // Setting dirs
  511. //************************************************************************
  512. m_pDirWatch->addDir(path); // add watch on this dir
  513. if ( !d.exists() ) // exists&isdir?
  514. {
  515. kdDebug(7020) << TQString(TQString("Does not exist! (%1)").arg(_path)) << endl;
  516. return; // return false
  517. }
  518. // Note: If some directory is gone, dirwatch will delete it from the list.
  519. //************************************************************************
  520. // Reading
  521. //************************************************************************
  522. TQString file;
  523. unsigned int i; // counter and string length.
  524. unsigned int count = d.count();
  525. for( i = 0; i < count; i++ ) // check all entries
  526. {
  527. if (d[i] == "." || d[i] == ".." || d[i] == "magic")
  528. continue; // discard those ".", "..", "magic"...
  529. file = path; // set full path
  530. file += d[i]; // and add the file name.
  531. readDirectory( file ); // yes, dive into it.
  532. }
  533. }
  534. bool Kded::isWindowRegistered(long windowId)
  535. {
  536. return m_globalWindowIdList.find(windowId) != 0;
  537. }
  538. // DCOP
  539. void Kded::registerWindowId(long windowId)
  540. {
  541. m_globalWindowIdList.replace(windowId, &windowId);
  542. TQCString sender = callingDcopClient()->senderId();
  543. if( sender.isEmpty()) // local call
  544. sender = callingDcopClient()->appId();
  545. TQValueList<long> *windowIds = m_windowIdList.find(sender);
  546. if (!windowIds)
  547. {
  548. windowIds = new TQValueList<long>;
  549. m_windowIdList.insert(sender, windowIds);
  550. }
  551. windowIds->append(windowId);
  552. for(TQAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it)
  553. {
  554. emit it.current()->windowRegistered(windowId);
  555. }
  556. }
  557. // DCOP
  558. void Kded::unregisterWindowId(long windowId)
  559. {
  560. m_globalWindowIdList.remove(windowId);
  561. TQCString sender = callingDcopClient()->senderId();
  562. if( sender.isEmpty()) // local call
  563. sender = callingDcopClient()->appId();
  564. TQValueList<long> *windowIds = m_windowIdList.find(sender);
  565. if (windowIds)
  566. {
  567. windowIds->remove(windowId);
  568. if (windowIds->isEmpty())
  569. m_windowIdList.remove(sender);
  570. }
  571. for(TQAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it)
  572. {
  573. emit it.current()->windowUnregistered(windowId);
  574. }
  575. }
  576. static void sighandler(int /*sig*/)
  577. {
  578. if (kapp)
  579. kapp->quit();
  580. }
  581. KUpdateD::KUpdateD()
  582. {
  583. m_pDirWatch = new KDirWatch;
  584. m_pTimer = new TQTimer;
  585. connect(m_pTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(runKonfUpdate()));
  586. TQObject::connect( m_pDirWatch, TQT_SIGNAL(dirty(const TQString&)),
  587. this, TQT_SLOT(slotNewUpdateFile()));
  588. TQStringList dirs = TDEGlobal::dirs()->findDirs("data", "tdeconf_update");
  589. for( TQStringList::ConstIterator it = dirs.begin();
  590. it != dirs.end();
  591. ++it )
  592. {
  593. TQString path = *it;
  594. if (path[path.length()-1] != '/')
  595. path += "/";
  596. if (!m_pDirWatch->contains(path))
  597. m_pDirWatch->addDir(path);
  598. }
  599. }
  600. KUpdateD::~KUpdateD()
  601. {
  602. delete m_pDirWatch;
  603. delete m_pTimer;
  604. }
  605. void KUpdateD::runKonfUpdate()
  606. {
  607. ::runKonfUpdate();
  608. }
  609. void KUpdateD::slotNewUpdateFile()
  610. {
  611. m_pTimer->start( 500, true /* single shot */ );
  612. }
  613. KHostnameD::KHostnameD(int pollInterval)
  614. {
  615. m_Timer.start(pollInterval, false /* repetitive */ );
  616. connect(&m_Timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(checkHostname()));
  617. checkHostname();
  618. }
  619. KHostnameD::~KHostnameD()
  620. {
  621. // Empty
  622. }
  623. void KHostnameD::checkHostname()
  624. {
  625. char buf[1024+1];
  626. if (gethostname(buf, 1024) != 0)
  627. return;
  628. buf[sizeof(buf)-1] = '\0';
  629. if (m_hostname.isEmpty())
  630. {
  631. m_hostname = buf;
  632. return;
  633. }
  634. if (m_hostname == buf)
  635. return;
  636. TQCString newHostname = buf;
  637. runDontChangeHostname(m_hostname, newHostname);
  638. m_hostname = newHostname;
  639. }
  640. static TDECmdLineOptions options[] =
  641. {
  642. { "check", I18N_NOOP("Check Sycoca database only once"), 0 },
  643. { "new-startup", "Internal", 0 },
  644. TDECmdLineLastOption
  645. };
  646. class KDEDQtDCOPObject : public DCOPObject
  647. {
  648. public:
  649. KDEDQtDCOPObject() : DCOPObject("qt/kded") { }
  650. virtual bool process(const TQCString &fun, const TQByteArray &data,
  651. TQCString& replyType, TQByteArray &replyData)
  652. {
  653. if ( kapp && (fun == "quit()") )
  654. {
  655. kapp->quit();
  656. replyType = "void";
  657. return true;
  658. }
  659. return DCOPObject::process(fun, data, replyType, replyData);
  660. }
  661. QCStringList functions()
  662. {
  663. QCStringList res = DCOPObject::functions();
  664. res += "void quit()";
  665. return res;
  666. }
  667. };
  668. class KDEDApplication : public KUniqueApplication
  669. {
  670. public:
  671. KDEDApplication() : KUniqueApplication( )
  672. {
  673. startup = true;
  674. dcopClient()->connectDCOPSignal( "DCOPServer", "", "terminateTDE()",
  675. objId(), "quit()", false );
  676. }
  677. int newInstance()
  678. {
  679. if (startup) {
  680. startup = false;
  681. if( Kded::self()->newStartup())
  682. Kded::self()->initModules();
  683. else
  684. TQTimer::singleShot(500, Kded::self(), TQT_SLOT(initModules()));
  685. } else
  686. runBuildSycoca();
  687. return 0;
  688. }
  689. QCStringList functions()
  690. {
  691. QCStringList res = KUniqueApplication::functions();
  692. res += "bool loadModule(TQCString)";
  693. res += "bool unloadModule(TQCString)";
  694. res += "void registerWindowId(long int)";
  695. res += "void unregisterWindowId(long int)";
  696. res += "QCStringList loadedModules()";
  697. res += "void reconfigure()";
  698. res += "void loadSecondPhase()";
  699. res += "void quit()";
  700. return res;
  701. }
  702. bool process(const TQCString &fun, const TQByteArray &data,
  703. TQCString &replyType, TQByteArray &replyData)
  704. {
  705. if (fun == "loadModule(TQCString)") {
  706. TQCString module;
  707. TQDataStream arg( data, IO_ReadOnly );
  708. arg >> module;
  709. bool result = (Kded::self()->loadModule(module, false) != 0);
  710. replyType = "bool";
  711. TQDataStream _replyStream( replyData, IO_WriteOnly );
  712. _replyStream << result;
  713. return true;
  714. }
  715. else if (fun == "unloadModule(TQCString)") {
  716. TQCString module;
  717. TQDataStream arg( data, IO_ReadOnly );
  718. arg >> module;
  719. bool result = Kded::self()->unloadModule(module);
  720. replyType = "bool";
  721. TQDataStream _replyStream( replyData, IO_WriteOnly );
  722. _replyStream << result;
  723. return true;
  724. }
  725. else if (fun == "registerWindowId(long int)") {
  726. long windowId;
  727. TQDataStream arg( data, IO_ReadOnly );
  728. arg >> windowId;
  729. Kded::self()->setCallingDcopClient(callingDcopClient());
  730. Kded::self()->registerWindowId(windowId);
  731. replyType = "void";
  732. return true;
  733. }
  734. else if (fun == "unregisterWindowId(long int)") {
  735. long windowId;
  736. TQDataStream arg( data, IO_ReadOnly );
  737. arg >> windowId;
  738. Kded::self()->setCallingDcopClient(callingDcopClient());
  739. Kded::self()->unregisterWindowId(windowId);
  740. replyType = "void";
  741. return true;
  742. }
  743. else if (fun == "loadedModules()") {
  744. replyType = "QCStringList";
  745. TQDataStream _replyStream(replyData, IO_WriteOnly);
  746. _replyStream << Kded::self()->loadedModules();
  747. return true;
  748. }
  749. else if (fun == "reconfigure()") {
  750. config()->reparseConfiguration();
  751. Kded::self()->initModules();
  752. replyType = "void";
  753. return true;
  754. }
  755. else if (fun == "loadSecondPhase()") {
  756. Kded::self()->loadSecondPhase();
  757. replyType = "void";
  758. return true;
  759. }
  760. else if (fun == "quit()") {
  761. quit();
  762. replyType = "void";
  763. return true;
  764. }
  765. return KUniqueApplication::process(fun, data, replyType, replyData);
  766. }
  767. bool startup;
  768. KDEDQtDCOPObject kdedQtDcopObject;
  769. };
  770. extern "C" KDE_EXPORT int kdemain(int argc, char *argv[])
  771. {
  772. TDEAboutData aboutData( "kded", I18N_NOOP("TDE Daemon"),
  773. "$Id$",
  774. I18N_NOOP("TDE Daemon - triggers Sycoca database updates when needed"));
  775. TDEApplication::installSigpipeHandler();
  776. TDECmdLineArgs::init(argc, argv, &aboutData);
  777. KUniqueApplication::addCmdLineOptions();
  778. TDECmdLineArgs::addCmdLineOptions( options );
  779. // this program is in tdelibs so it uses tdelibs as catalog
  780. TDELocale::setMainCatalogue("tdelibs");
  781. // WABA: Make sure not to enable session management.
  782. putenv(strdup("SESSION_MANAGER="));
  783. // Parse command line before checking DCOP
  784. TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
  785. // Check DCOP communication.
  786. {
  787. DCOPClient testDCOP;
  788. TQCString dcopName = testDCOP.registerAs("kded", false);
  789. if (dcopName.isEmpty())
  790. {
  791. kdFatal() << "DCOP communication problem!" << endl;
  792. return 1;
  793. }
  794. }
  795. TDEInstance *instance = new TDEInstance(&aboutData);
  796. TDEConfig *config = instance->config(); // Enable translations.
  797. if (args->isSet("check"))
  798. {
  799. config->setGroup("General");
  800. checkStamps = config->readBoolEntry("CheckFileStamps", true);
  801. runBuildSycoca();
  802. runKonfUpdate();
  803. exit(0);
  804. }
  805. if (!KUniqueApplication::start())
  806. {
  807. fprintf(stderr, "[kded] Daemon (kded) is already running.\n");
  808. exit(0);
  809. }
  810. KUniqueApplication::dcopClient()->setQtBridgeEnabled(false);
  811. config->setGroup("General");
  812. int HostnamePollInterval = config->readNumEntry("HostnamePollInterval", 5000);
  813. bool bCheckSycoca = config->readBoolEntry("CheckSycoca", true);
  814. bool bCheckUpdates = config->readBoolEntry("CheckUpdates", true);
  815. bool bCheckHostname = config->readBoolEntry("CheckHostname", true);
  816. checkStamps = config->readBoolEntry("CheckFileStamps", true);
  817. delayedCheck = config->readBoolEntry("DelayedCheck", false);
  818. Kded *kded = new Kded(bCheckSycoca, args->isSet("new-startup")); // Build data base
  819. signal(SIGTERM, sighandler);
  820. signal(SIGHUP, sighandler);
  821. KDEDApplication k;
  822. kded->recreate(true); // initial
  823. if (bCheckUpdates)
  824. (void) new KUpdateD; // Watch for updates
  825. runKonfUpdate(); // Run it once.
  826. if (bCheckHostname)
  827. (void) new KHostnameD(HostnamePollInterval); // Watch for hostname changes
  828. DCOPClient *client = kapp->dcopClient();
  829. TQObject::connect(client, TQT_SIGNAL(applicationRemoved(const TQCString&)),
  830. kded, TQT_SLOT(slotApplicationRemoved(const TQCString&)));
  831. client->setNotifications(true);
  832. client->setDaemonMode( true );
  833. // During startup kdesktop waits for KDED to finish.
  834. // Send a notifyDatabaseChanged signal even if the database hasn't
  835. // changed.
  836. // If the database changed, tdebuildsycoca's signal didn't go anywhere
  837. // anyway, because it was too early, so let's send this signal
  838. // unconditionnally (David)
  839. TQByteArray data;
  840. client->send( "*", "tdesycoca", "notifyDatabaseChanged()", data );
  841. client->send( "ksplash", "", "upAndRunning(TQString)", TQString("kded"));
  842. #ifdef Q_WS_X11
  843. XEvent e;
  844. e.xclient.type = ClientMessage;
  845. e.xclient.message_type = XInternAtom( tqt_xdisplay(), "_KDE_SPLASH_PROGRESS", False );
  846. e.xclient.display = tqt_xdisplay();
  847. e.xclient.window = tqt_xrootwin();
  848. e.xclient.format = 8;
  849. strcpy( e.xclient.data.b, "kded" );
  850. XSendEvent( tqt_xdisplay(), tqt_xrootwin(), False, SubstructureNotifyMask, &e );
  851. #endif
  852. int result = k.exec(); // keep running
  853. delete kded;
  854. delete instance; // Deletes config as well
  855. return result;
  856. }
  857. #include "kded.moc"