1// vim: expandtab sw=4 ts=4
2/* This file is part of the KDE libraries
3 * Copyright (C) 1999 David Faure <faure@kde.org>
4 * Copyright (C) 2000 Waldo Bastian <bastian@kde.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License version 2 as published by the Free Software Foundation;
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 **/
20
21#include "kded.h"
22#include "kdedadaptor.h"
23#include "kdedmodule.h"
24
25#include <kcrash.h>
26#include <kdeversion.h>
27
28#include <unistd.h>
29#include <stdlib.h>
30#include <signal.h>
31#include <time.h>
32
33#include <QtCore/QDir>
34#include <QtCore/QFile>
35#include <QtCore/QTimer>
36
37#include <QtDBus/QtDBus>
38
39#include <kuniqueapplication.h>
40#include <kapplication.h>
41#include <kcmdlineargs.h>
42#include <kaboutdata.h>
43#ifndef KDE_NO_DEPRECATED
44#include <klibloader.h>
45#else
46#include <klibrary.h>
47#endif
48#include <klocale.h>
49#include <kglobal.h>
50#include <kconfig.h>
51#include <kconfiggroup.h>
52#include <kdebug.h>
53#include <kdirwatch.h>
54#include <kstandarddirs.h>
55#include <kservicetypetrader.h>
56#include <ktoolinvocation.h>
57#include <kde_file.h>
58#include "klauncher_iface.h"
59
60#ifdef Q_WS_X11
61#include <qx11info_x11.h>
62#include <X11/Xlib.h>
63#include <fixx11h.h>
64#endif
65
66#define KDED_EXENAME "kded4"
67
68#define MODULES_PATH "/modules/"
69
70Kded *Kded::_self = 0;
71
72static bool checkStamps = true;
73static bool delayedCheck = false;
74static int HostnamePollInterval;
75static bool bCheckSycoca;
76static bool bCheckUpdates;
77static bool bCheckHostname;
78
79#ifdef Q_DBUS_EXPORT
80extern Q_DBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage&));
81#else
82extern QDBUS_EXPORT void qDBusAddSpyHook(void (*)(const QDBusMessage&));
83#endif
84
85static void runBuildSycoca(QObject *callBackObj=0, const char *callBackSlot=0, const char *callBackErrorSlot=0)
86{
87 const QString exe = KStandardDirs::findExe(KBUILDSYCOCA_EXENAME);
88 Q_ASSERT(!exe.isEmpty());
89 QStringList args;
90 args.append("--incremental");
91 if(checkStamps)
92 args.append("--checkstamps");
93 if(delayedCheck)
94 args.append("--nocheckfiles");
95 else
96 checkStamps = false; // useful only during kded startup
97 if (callBackObj)
98 {
99 QVariantList argList;
100 argList << exe << args << QStringList() << QString();
101 KToolInvocation::klauncher()->callWithCallback("kdeinit_exec_wait", argList, callBackObj, callBackSlot, callBackErrorSlot);
102 }
103 else
104 {
105 KToolInvocation::kdeinitExecWait( exe, args );
106 }
107}
108
109static void runKonfUpdate()
110{
111 KToolInvocation::kdeinitExecWait( "kconf_update", QStringList(), 0, 0, "0" /*no startup notification*/ );
112}
113
114static void runDontChangeHostname(const QByteArray &oldName, const QByteArray &newName)
115{
116 QStringList args;
117 args.append(QFile::decodeName(oldName));
118 args.append(QFile::decodeName(newName));
119 KToolInvocation::kdeinitExecWait( "kdontchangethehostname", args );
120}
121
122Kded::Kded()
123 : m_needDelayedCheck(false)
124{
125 _self = this;
126
127 m_serviceWatcher = new QDBusServiceWatcher(this);
128 m_serviceWatcher->setConnection(QDBusConnection::sessionBus());
129 m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
130 QObject::connect(m_serviceWatcher, SIGNAL(serviceUnregistered(QString)),
131 this, SLOT(slotApplicationRemoved(QString)));
132
133 new KBuildsycocaAdaptor(this);
134 new KdedAdaptor(this);
135
136 QDBusConnection session = QDBusConnection::sessionBus();
137 session.registerObject("/kbuildsycoca", this);
138 session.registerObject("/kded", this);
139
140 qDBusAddSpyHook(messageFilter);
141
142 m_pTimer = new QTimer(this);
143 m_pTimer->setSingleShot( true );
144 connect(m_pTimer, SIGNAL(timeout()), this, SLOT(recreate()));
145
146 m_pDirWatch = 0;
147
148 m_recreateCount = 0;
149 m_recreateBusy = false;
150}
151
152Kded::~Kded()
153{
154 _self = 0;
155 m_pTimer->stop();
156 delete m_pTimer;
157 delete m_pDirWatch;
158
159 for (QHash<QByteArray,KDEDModule*>::iterator
160 it(m_modules.begin()), itEnd(m_modules.end());
161 it != itEnd; ++it)
162 {
163 KDEDModule* module(it.value());
164
165 // first disconnect otherwise slotKDEDModuleRemoved() is called
166 // and changes m_modules while we're iterating over it
167 disconnect(module, SIGNAL(moduleDeleted(KDEDModule*)),
168 this, SLOT(slotKDEDModuleRemoved(KDEDModule*)));
169
170 delete module;
171 }
172}
173
174// on-demand module loading
175// this function is called by the D-Bus message processing function before
176// calls are delivered to objects
177void Kded::messageFilter(const QDBusMessage &message)
178{
179 // This happens when kded goes down and some modules try to clean up.
180 if (!self())
181 return;
182
183 if (message.type() != QDBusMessage::MethodCallMessage)
184 return;
185
186 QString obj = message.path();
187 if (!obj.startsWith(MODULES_PATH))
188 return;
189
190 // Remove the <MODULES_PATH> part
191 obj = obj.mid(strlen(MODULES_PATH));
192 if (obj == "ksycoca")
193 return; // Ignore this one.
194
195 // Remove the part after the modules name
196 int index = obj.indexOf('/');
197 if (index!=-1) {
198 obj = obj.left(index);
199 }
200
201 if (self()->m_dontLoad.value(obj, 0))
202 return;
203
204 KDEDModule *module = self()->loadModule(obj, true);
205 if (!module) {
206 kDebug(7020) << "Failed to load module for " << obj;
207 }
208 Q_UNUSED(module);
209}
210
211static int phaseForModule(const KService::Ptr& service)
212{
213 const QVariant phasev = service->property("X-KDE-Kded-phase", QVariant::Int );
214 return phasev.isValid() ? phasev.toInt() : 2;
215}
216
217void Kded::initModules()
218{
219 m_dontLoad.clear();
220 bool kde_running = !qgetenv( "KDE_FULL_SESSION" ).isEmpty();
221 if (kde_running) {
222 // not the same user like the one running the session (most likely we're run via sudo or something)
223 const QByteArray sessionUID = qgetenv( "KDE_SESSION_UID" );
224 if( !sessionUID.isEmpty() && uid_t( sessionUID.toInt() ) != getuid())
225 kde_running = false;
226
227 // not the same kde version as the current desktop
228 const QByteArray kdeSession = qgetenv("KDE_SESSION_VERSION");
229 if (kdeSession.toInt() != KDE_VERSION_MAJOR)
230 kde_running = false;
231 }
232
233 // There will be a "phase 2" only if we're in the KDE startup.
234 // If kded is restarted by its crashhandled or by hand,
235 // then there will be no second phase autoload, so load
236 // these modules now, if in a KDE session.
237 const bool loadPhase2Now = (kde_running && qgetenv("KDED_STARTED_BY_KDEINIT").toInt() == 0);
238
239 // Preload kded modules.
240 const KService::List kdedModules = KServiceTypeTrader::self()->query("KDEDModule");
241 for(KService::List::ConstIterator it = kdedModules.begin(); it != kdedModules.end(); ++it)
242 {
243 KService::Ptr service = *it;
244 // Should the service load on startup?
245 const bool autoload = isModuleAutoloaded(service);
246
247 // see ksmserver's README for description of the phases
248 bool prevent_autoload = false;
249 switch( phaseForModule(service) )
250 {
251 case 0: // always autoload
252 break;
253 case 1: // autoload only in KDE
254 if (!kde_running) {
255 prevent_autoload = true;
256 }
257 break;
258 case 2: // autoload delayed, only in KDE
259 default:
260 if (!loadPhase2Now) {
261 prevent_autoload = true;
262 }
263 break;
264 }
265
266 // Load the module if necessary and allowed
267 if (autoload && !prevent_autoload) {
268 if (!loadModule(service, false)) {
269 continue;
270 }
271 }
272
273 // Remember if the module is allowed to load on demand
274 bool loadOnDemand = isModuleLoadedOnDemand(service);
275 if (!loadOnDemand)
276 noDemandLoad(service->desktopEntryName());
277
278 // In case of reloading the configuration it is possible for a module
279 // to run even if it is now allowed to. Stop it then.
280 if (!loadOnDemand && !autoload)
281 unloadModule(service->desktopEntryName().toLatin1());
282 }
283}
284
285void Kded::loadSecondPhase()
286{
287 kDebug(7020) << "Loading second phase autoload";
288 KSharedConfig::Ptr config = KGlobal::config();
289 KService::List kdedModules = KServiceTypeTrader::self()->query("KDEDModule");
290 for(KService::List::ConstIterator it = kdedModules.constBegin(); it != kdedModules.constEnd(); ++it) {
291 const KService::Ptr service = *it;
292 const bool autoload = isModuleAutoloaded(service);
293 if (autoload && phaseForModule(service) == 2) {
294 //kDebug(7020) << "2nd phase: loading" << service->desktopEntryName();
295 loadModule(service, false);
296 }
297 }
298}
299
300void Kded::noDemandLoad(const QString &obj)
301{
302 m_dontLoad.insert(obj.toLatin1(), this);
303}
304
305void Kded::setModuleAutoloading(const QString &obj, bool autoload)
306{
307 KSharedConfig::Ptr config = KGlobal::config();
308 // Ensure the service exists.
309 KService::Ptr service = KService::serviceByDesktopPath("kded/"+obj+".desktop");
310 if (!service)
311 return;
312 KConfigGroup cg(config, QString("Module-%1").arg(service->desktopEntryName()));
313 cg.writeEntry("autoload", autoload);
314 cg.sync();
315}
316
317bool Kded::isModuleAutoloaded(const QString &obj) const
318{
319 KService::Ptr s = KService::serviceByDesktopPath("kded/"+obj+".desktop");
320 if (!s)
321 return false;
322 return isModuleAutoloaded(s);
323}
324
325bool Kded::isModuleAutoloaded(const KService::Ptr &module) const
326{
327 KSharedConfig::Ptr config = KGlobal::config();
328 bool autoload = module->property("X-KDE-Kded-autoload", QVariant::Bool).toBool();
329 KConfigGroup cg(config, QString("Module-%1").arg(module->desktopEntryName()));
330 autoload = cg.readEntry("autoload", autoload);
331 return autoload;
332}
333
334bool Kded::isModuleLoadedOnDemand(const QString &obj) const
335{
336 KService::Ptr s = KService::serviceByDesktopPath("kded/"+obj+".desktop");
337 if (!s)
338 return false;
339 return isModuleLoadedOnDemand(s);
340}
341
342bool Kded::isModuleLoadedOnDemand(const KService::Ptr &module) const
343{
344 KSharedConfig::Ptr config = KGlobal::config();
345 bool loadOnDemand = true;
346 QVariant p = module->property("X-KDE-Kded-load-on-demand", QVariant::Bool);
347 if (p.isValid() && (p.toBool() == false))
348 loadOnDemand = false;
349 return loadOnDemand;
350}
351
352KDEDModule *Kded::loadModule(const QString &obj, bool onDemand)
353{
354 // Make sure this method is only called with valid module names.
355 Q_ASSERT(obj.indexOf('/')==-1);
356
357 KDEDModule *module = m_modules.value(obj, 0);
358 if (module)
359 return module;
360 KService::Ptr s = KService::serviceByDesktopPath("kded/"+obj+".desktop");
361 return loadModule(s, onDemand);
362}
363
364KDEDModule *Kded::loadModule(const KService::Ptr& s, bool onDemand)
365{
366 if (s && !s->library().isEmpty())
367 {
368 QString obj = s->desktopEntryName();
369 KDEDModule *oldModule = m_modules.value(obj, 0);
370 if (oldModule)
371 return oldModule;
372
373 if (onDemand)
374 {
375 QVariant p = s->property("X-KDE-Kded-load-on-demand", QVariant::Bool);
376 if (p.isValid() && (p.toBool() == false))
377 {
378 noDemandLoad(s->desktopEntryName());
379 return 0;
380 }
381 }
382
383 KDEDModule *module = 0;
384 QString libname = "kded_"+s->library();
385 KPluginLoader loader(libname);
386
387 KPluginFactory *factory = loader.factory();
388 if (!factory) {
389 // kde3 compat
390 QString factoryName = s->property("X-KDE-FactoryName", QVariant::String).toString();
391 if (factoryName.isEmpty())
392 factoryName = s->library();
393 factoryName = "create_" + factoryName;
394#ifndef KDE_NO_DEPRECATED
395 KLibrary* lib = KLibLoader::self()->library(libname);
396 KDEDModule* (*create)();
397 if (lib) {
398 create = (KDEDModule* (*)())lib->resolveFunction(QFile::encodeName(factoryName));
399 if (create)
400 module = create();
401 }
402#endif
403 if (!module) {
404 kWarning() << "Could not load library" << libname << ". ["
405 << loader.errorString() << "]";
406 }
407 } else {
408 // create the module
409 module = factory->create<KDEDModule>(this);
410 }
411 if (module) {
412 module->setModuleName(obj);
413 m_modules.insert(obj, module);
414 //m_libs.insert(obj, lib);
415 connect(module, SIGNAL(moduleDeleted(KDEDModule*)), SLOT(slotKDEDModuleRemoved(KDEDModule*)));
416 kDebug(7020) << "Successfully loaded module" << obj;
417 return module;
418 } else {
419 kDebug(7020) << "Could not load module" << obj;
420 //loader.unload();
421 }
422 }
423 return 0;
424}
425
426bool Kded::unloadModule(const QString &obj)
427{
428 KDEDModule *module = m_modules.value(obj, 0);
429 if (!module)
430 return false;
431 kDebug(7020) << "Unloading module" << obj;
432 m_modules.remove(obj);
433 delete module;
434 return true;
435}
436
437QStringList Kded::loadedModules()
438{
439 return m_modules.keys();
440}
441
442void Kded::slotKDEDModuleRemoved(KDEDModule *module)
443{
444 m_modules.remove(module->moduleName());
445 //KLibrary *lib = m_libs.take(module->moduleName());
446 //if (lib)
447 // lib->unload();
448}
449
450void Kded::slotApplicationRemoved(const QString &name)
451{
452#if 0 // see kdedmodule.cpp (KDED_OBJECTS)
453 foreach( KDEDModule* module, m_modules )
454 {
455 module->removeAll(appId);
456 }
457#endif
458 m_serviceWatcher->removeWatchedService(name);
459 const QList<qlonglong> windowIds = m_windowIdList.value(name);
460 for( QList<qlonglong>::ConstIterator it = windowIds.begin();
461 it != windowIds.end(); ++it)
462 {
463 qlonglong windowId = *it;
464 m_globalWindowIdList.remove(windowId);
465 foreach( KDEDModule* module, m_modules )
466 {
467 emit module->windowUnregistered(windowId);
468 }
469 }
470 m_windowIdList.remove(name);
471}
472
473void Kded::updateDirWatch()
474{
475 if (!bCheckUpdates) return;
476
477 delete m_pDirWatch;
478 m_pDirWatch = new KDirWatch;
479
480 QObject::connect( m_pDirWatch, SIGNAL(dirty(QString)),
481 this, SLOT(update(QString)));
482 QObject::connect( m_pDirWatch, SIGNAL(created(QString)),
483 this, SLOT(update(QString)));
484 QObject::connect( m_pDirWatch, SIGNAL(deleted(QString)),
485 this, SLOT(dirDeleted(QString)));
486
487 // For each resource
488 for( QStringList::ConstIterator it = m_allResourceDirs.constBegin();
489 it != m_allResourceDirs.constEnd();
490 ++it )
491 {
492 readDirectory( *it );
493 }
494}
495
496void Kded::updateResourceList()
497{
498 KSycoca::clearCaches();
499
500 if (!bCheckUpdates) return;
501
502 if (delayedCheck) return;
503
504 const QStringList dirs = KSycoca::self()->allResourceDirs();
505 // For each resource
506 for( QStringList::ConstIterator it = dirs.begin();
507 it != dirs.end();
508 ++it )
509 {
510 if (!m_allResourceDirs.contains(*it))
511 {
512 m_allResourceDirs.append(*it);
513 readDirectory(*it);
514 }
515 }
516}
517
518void Kded::recreate()
519{
520 recreate(false);
521}
522
523void Kded::runDelayedCheck()
524{
525 if( m_needDelayedCheck )
526 recreate(false);
527 m_needDelayedCheck = false;
528}
529
530void Kded::recreate(bool initial)
531{
532 m_recreateBusy = true;
533 // Using KLauncher here is difficult since we might not have a
534 // database
535
536 if (!initial)
537 {
538 updateDirWatch(); // Update tree first, to be sure to miss nothing.
539 runBuildSycoca(this, SLOT(recreateDone()), SLOT(recreateFailed(QDBusError)));
540 }
541 else
542 {
543 if(!delayedCheck)
544 updateDirWatch(); // this would search all the directories
545 if (bCheckSycoca)
546 runBuildSycoca();
547 recreateDone();
548 if(delayedCheck)
549 {
550 // do a proper ksycoca check after a delay
551 QTimer::singleShot( 60000, this, SLOT(runDelayedCheck()));
552 m_needDelayedCheck = true;
553 delayedCheck = false;
554 }
555 else
556 m_needDelayedCheck = false;
557 }
558}
559
560void Kded::recreateFailed(const QDBusError &error)
561{
562 kWarning() << error;
563 for(; m_recreateCount; m_recreateCount--)
564 {
565 QDBusMessage msg = m_recreateRequests.takeFirst();
566 QDBusConnection::sessionBus().send(msg.createErrorReply(error));
567 }
568 afterRecreateFinished();
569}
570
571void Kded::recreateDone()
572{
573 updateResourceList();
574
575 for(; m_recreateCount; m_recreateCount--)
576 {
577 QDBusMessage msg = m_recreateRequests.takeFirst();
578 QDBusConnection::sessionBus().send(msg.createReply());
579 }
580 afterRecreateFinished();
581}
582
583void Kded::afterRecreateFinished()
584{
585 m_recreateBusy = false;
586
587 // Did a new request come in while building?
588 if (!m_recreateRequests.isEmpty())
589 {
590 m_pTimer->start(2000);
591 m_recreateCount = m_recreateRequests.count();
592 } else {
593 initModules();
594 }
595}
596
597void Kded::dirDeleted(const QString& path)
598{
599 update(path);
600}
601
602void Kded::update(const QString& )
603{
604 if (!m_recreateBusy)
605 {
606 m_pTimer->start( 10000 );
607 }
608}
609
610void Kded::recreate(const QDBusMessage &msg)
611{
612 if (!m_recreateBusy)
613 {
614 if (m_recreateRequests.isEmpty())
615 {
616 m_pTimer->start(0);
617 m_recreateCount = 0;
618 }
619 m_recreateCount++;
620 }
621 msg.setDelayedReply(true);
622 m_recreateRequests.append(msg);
623 return;
624}
625
626
627void Kded::readDirectory( const QString& _path )
628{
629 QString path( _path );
630 if ( !path.endsWith( '/' ) )
631 path += '/';
632
633 if ( m_pDirWatch->contains( path ) ) // Already seen this one?
634 return;
635
636 m_pDirWatch->addDir(path,KDirWatch::WatchFiles|KDirWatch::WatchSubDirs); // add watch on this dir
637 return; // KDirWatch now claims to also support recursive watching
638#if 0
639 QDir d( _path, QString(), QDir::Unsorted, QDir::Readable | QDir::Executable | QDir::Dirs | QDir::Hidden );
640 // set QDir ...
641
642
643 //************************************************************************
644 // Setting dirs
645 //************************************************************************
646
647 if ( !d.exists() ) // exists&isdir?
648 {
649 kDebug(7020) << "Does not exist:" << _path;
650 return; // return false
651 }
652
653 // Note: If some directory is gone, dirwatch will delete it from the list.
654
655 //************************************************************************
656 // Reading
657 //************************************************************************
658 QString file;
659 unsigned int i; // counter and string length.
660 unsigned int count = d.count();
661 for( i = 0; i < count; i++ ) // check all entries
662 {
663 if (d[i] == "." || d[i] == ".." || d[i] == "magic")
664 continue; // discard those ".", "..", "magic"...
665
666 file = path; // set full path
667 file += d[i]; // and add the file name.
668
669 readDirectory( file ); // yes, dive into it.
670 }
671#endif
672}
673
674/*
675bool Kded::isWindowRegistered(long windowId) const
676{
677 return m_globalWindowIdList.contains(windowId);
678
679}
680*/
681
682void Kded::registerWindowId(qlonglong windowId, const QString &sender)
683{
684 if (!m_windowIdList.contains(sender)) {
685 m_serviceWatcher->addWatchedService(sender);
686 }
687
688 m_globalWindowIdList.insert(windowId);
689 QList<qlonglong> windowIds = m_windowIdList.value(sender);
690 windowIds.append(windowId);
691 m_windowIdList.insert(sender, windowIds);
692
693 foreach( KDEDModule* module, m_modules )
694 {
695 //kDebug() << module->moduleName();
696 emit module->windowRegistered(windowId);
697 }
698}
699
700void Kded::unregisterWindowId(qlonglong windowId, const QString &sender)
701{
702 m_globalWindowIdList.remove(windowId);
703 QList<qlonglong> windowIds = m_windowIdList.value(sender);
704 if (!windowIds.isEmpty())
705 {
706 windowIds.removeAll(windowId);
707 if (windowIds.isEmpty()) {
708 m_serviceWatcher->removeWatchedService(sender);
709 m_windowIdList.remove(sender);
710 } else {
711 m_windowIdList.insert(sender, windowIds);
712 }
713 }
714
715 foreach( KDEDModule* module, m_modules )
716 {
717 //kDebug() << module->moduleName();
718 emit module->windowUnregistered(windowId);
719 }
720}
721
722
723static void sighandler(int /*sig*/)
724{
725 if (qApp)
726 qApp->quit();
727}
728
729KUpdateD::KUpdateD()
730{
731 m_pDirWatch = new KDirWatch;
732 m_pTimer = new QTimer;
733 m_pTimer->setSingleShot( true );
734 connect(m_pTimer, SIGNAL(timeout()), this, SLOT(runKonfUpdate()));
735 QObject::connect( m_pDirWatch, SIGNAL(dirty(QString)),
736 this, SLOT(slotNewUpdateFile()));
737
738 const QStringList dirs = KGlobal::dirs()->findDirs("data", "kconf_update");
739 for( QStringList::ConstIterator it = dirs.begin();
740 it != dirs.end();
741 ++it )
742 {
743 QString path = *it;
744 if (path[path.length()-1] != '/')
745 path += '/';
746
747 if (!m_pDirWatch->contains(path))
748 m_pDirWatch->addDir(path,KDirWatch::WatchFiles|KDirWatch::WatchSubDirs);
749 }
750}
751
752KUpdateD::~KUpdateD()
753{
754 delete m_pDirWatch;
755 delete m_pTimer;
756}
757
758void KUpdateD::runKonfUpdate()
759{
760 ::runKonfUpdate();
761}
762
763void KUpdateD::slotNewUpdateFile()
764{
765 m_pTimer->start( 500 );
766}
767
768KHostnameD::KHostnameD(int pollInterval)
769{
770 m_Timer.start(pollInterval); // repetitive timer (not single-shot)
771 connect(&m_Timer, SIGNAL(timeout()), this, SLOT(checkHostname()));
772 checkHostname();
773}
774
775KHostnameD::~KHostnameD()
776{
777 // Empty
778}
779
780void KHostnameD::checkHostname()
781{
782 char buf[1024+1];
783 if (gethostname(buf, 1024) != 0)
784 return;
785 buf[sizeof(buf)-1] = '\0';
786
787 if (m_hostname.isEmpty())
788 {
789 m_hostname = buf;
790 return;
791 }
792
793 if (m_hostname == buf)
794 return;
795
796 QByteArray newHostname = buf;
797
798 runDontChangeHostname(m_hostname, newHostname);
799 m_hostname = newHostname;
800}
801
802
803KBuildsycocaAdaptor::KBuildsycocaAdaptor(QObject *parent)
804 : QDBusAbstractAdaptor(parent)
805{
806}
807
808void KBuildsycocaAdaptor::recreate(const QDBusMessage &msg)
809{
810 Kded::self()->recreate(msg);
811}
812
813class KDEDApplication : public KUniqueApplication
814{
815public:
816 KDEDApplication() : KUniqueApplication( )
817 {
818 startup = true;
819 }
820
821 int newInstance()
822 {
823 if (startup) {
824 startup = false;
825
826 // This long initialization has to be here, not in kdemain.
827 // If it was in main, it would cause a dbus timeout when
828 // our parent from KUniqueApplication tries to call our
829 // newInstance method.
830
831 Kded *kded = Kded::self();
832
833 kded->recreate(true); // initial
834
835 if (bCheckUpdates)
836 (void) new KUpdateD; // Watch for updates
837
838#ifdef Q_WS_X11
839 XEvent e;
840 e.xclient.type = ClientMessage;
841 e.xclient.message_type = XInternAtom( QX11Info::display(), "_KDE_SPLASH_PROGRESS", False );
842 e.xclient.display = QX11Info::display();
843 e.xclient.window = QX11Info::appRootWindow();
844 e.xclient.format = 8;
845 strcpy( e.xclient.data.b, "kded" );
846 XSendEvent( QX11Info::display(), QX11Info::appRootWindow(), False, SubstructureNotifyMask, &e );
847#endif
848
849 runKonfUpdate(); // Run it once.
850
851#ifdef Q_WS_X11
852 e.xclient.type = ClientMessage;
853 e.xclient.message_type = XInternAtom( QX11Info::display(), "_KDE_SPLASH_PROGRESS", False );
854 e.xclient.display = QX11Info::display();
855 e.xclient.window = QX11Info::appRootWindow();
856 e.xclient.format = 8;
857 strcpy( e.xclient.data.b, "confupdate" );
858 XSendEvent( QX11Info::display(), QX11Info::appRootWindow(), False, SubstructureNotifyMask, &e );
859#endif
860
861// if (bCheckHostname)
862// (void) new KHostnameD(HostnamePollInterval); // Watch for hostname changes
863 } else
864 runBuildSycoca();
865
866 return 0;
867 }
868
869 bool startup;
870};
871
872extern "C" KDE_EXPORT int kdemain(int argc, char *argv[])
873{
874 KAboutData aboutData( "kded" /*don't change this one to kded4! dbus registration should be org.kde.kded etc.*/,
875 "kdelibs4", ki18n("KDE Daemon"),
876 KDE_VERSION_STRING,
877 ki18n("KDE Daemon - triggers Sycoca database updates when needed"));
878
879 KCmdLineOptions options;
880 options.add("check", ki18n("Check Sycoca database only once"));
881
882 KCmdLineArgs::init(argc, argv, &aboutData);
883
884 KUniqueApplication::addCmdLineOptions();
885
886 KCmdLineArgs::addCmdLineOptions( options );
887
888 // WABA: Make sure not to enable session management.
889 putenv(qstrdup("SESSION_MANAGER="));
890
891 // Parse command line before checking DCOP
892 KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
893
894 KComponentData componentData(&aboutData);
895 KSharedConfig::Ptr config = componentData.config(); // Enable translations.
896
897 KConfigGroup cg(config, "General");
898 if (args->isSet("check"))
899 {
900 // KUniqueApplication not wanted here.
901 KApplication app;
902 checkStamps = cg.readEntry("CheckFileStamps", true);
903 runBuildSycoca();
904 runKonfUpdate();
905 return 0;
906 }
907
908 if (!KUniqueApplication::start())
909 {
910 fprintf(stderr, "KDE Daemon (kded) already running.\n");
911 return 0;
912 }
913
914 // Thiago: reenable if such a thing exists in QtDBus in the future
915 //KUniqueApplication::dcopClient()->setQtBridgeEnabled(false);
916
917 HostnamePollInterval = cg.readEntry("HostnamePollInterval", 5000);
918 bCheckSycoca = cg.readEntry("CheckSycoca", true);
919 bCheckUpdates = cg.readEntry("CheckUpdates", true);
920 bCheckHostname = cg.readEntry("CheckHostname", true);
921 checkStamps = cg.readEntry("CheckFileStamps", true);
922 delayedCheck = cg.readEntry("DelayedCheck", false);
923
924 Kded *kded = new Kded(); // Build data base
925
926#ifndef _WIN32_WCE
927 KDE_signal(SIGTERM, sighandler);
928#endif
929 KDE_signal(SIGHUP, sighandler);
930 KDEDApplication k;
931 k.setQuitOnLastWindowClosed(false);
932
933 KCrash::setFlags(KCrash::AutoRestart);
934
935 // Not sure why kded is created before KDEDApplication
936 // but if it has to be, then it needs to be moved to the main thread
937 // before it can use timers (DF)
938 kded->moveToThread( k.thread() );
939
940 int result = k.exec(); // keep running
941
942 delete kded;
943
944 return result;
945}
946
947#include "kded.moc"
948