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

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