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.
tdelibs/kded/kded.cpp

991 lines
28 KiB

/* This file is part of the KDE libraries
* Copyright (C) 1999 David Faure <faure@kde.org>
* Copyright (C) 2000 Waldo Bastian <bastian@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License version 2 as published by the Free Software Foundation;
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
**/
#include <tqdir.h>
#include "kded.h"
#include "kdedmodule.h"
#include <kresourcelist.h>
#include <kcrash.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <tqfile.h>
#include <tqtimer.h>
#include <dcopclient.h>
#include <kuniqueapplication.h>
#include <tdecmdlineargs.h>
#include <tdeaboutdata.h>
#include <tdelocale.h>
#include <tdeglobal.h>
#include <kprocess.h>
#include <kdebug.h>
#include <kdirwatch.h>
#include <kstandarddirs.h>
#include <kdatastream.h>
#include <tdeio/global.h>
#include <kservicetype.h>
#ifdef Q_WS_X11
#include <X11/Xlib.h>
#include <fixx11h.h>
#endif
Kded *Kded::_self = 0;
static bool checkStamps = true;
static bool delayedCheck = false;
static void runBuildSycoca(TQObject *callBackObj=0, const char *callBackSlot=0)
{
TQStringList args;
args.append("--incremental");
if(checkStamps)
args.append("--checkstamps");
if(delayedCheck)
args.append("--nocheckfiles");
else
checkStamps = false; // useful only during kded startup
if (callBackObj)
{
TQByteArray data;
TQDataStream dataStream( data, IO_WriteOnly );
dataStream << TQString("tdebuildsycoca") << args;
TQCString _launcher = TDEApplication::launcher();
kapp->dcopClient()->callAsync(_launcher, _launcher, "tdeinit_exec_wait(TQString,TQStringList)", data, callBackObj, callBackSlot);
}
else
{
TDEApplication::tdeinitExecWait( "tdebuildsycoca", args );
}
}
static void runKonfUpdate()
{
TDEApplication::tdeinitExecWait( "tdeconf_update", TQStringList(), 0, 0, "0" /*no startup notification*/ );
}
static void runDontChangeHostname(const TQCString &oldName, const TQCString &newName)
{
TQStringList args;
args.append(TQFile::decodeName(oldName));
args.append(TQFile::decodeName(newName));
TDEApplication::tdeinitExecWait( "kdontchangethehostname", args );
}
Kded::Kded(bool checkUpdates, bool new_startup)
: DCOPObject("tdebuildsycoca"), DCOPObjectProxy(),
b_checkUpdates(checkUpdates),
m_needDelayedCheck(false),
m_newStartup( new_startup )
{
_self = this;
TQCString cPath;
TQCString tdesycoca_env = getenv("TDESYCOCA");
if (tdesycoca_env.isEmpty())
cPath = TQFile::encodeName(TDEGlobal::dirs()->saveLocation("tmp")+"tdesycoca");
else
cPath = tdesycoca_env;
m_pTimer = new TQTimer(this);
connect(m_pTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(recreate()));
TQTimer::singleShot(100, this, TQT_SLOT(installCrashHandler()));
m_pDirWatch = 0;
m_windowIdList.setAutoDelete(true);
m_recreateCount = 0;
m_recreateBusy = false;
}
Kded::~Kded()
{
_self = 0;
m_pTimer->stop();
delete m_pTimer;
delete m_pDirWatch;
// We have to delete the modules while we're still able to process incoming
// DCOP messages, since modules might make DCOP calls in their destructors.
TQAsciiDictIterator<KDEDModule> it(m_modules);
while (!it.isEmpty())
delete it.toFirst();
}
bool Kded::process(const TQCString &obj, const TQCString &fun,
const TQByteArray &data,
TQCString &replyType, TQByteArray &replyData)
{
if (obj == "tdesycoca") return false; // Ignore this one.
if (m_dontLoad[obj])
return false;
KDEDModule *module = loadModule(obj, true);
if (!module)
return false;
module->setCallingDcopClient(kapp->dcopClient());
return module->process(fun, data, replyType, replyData);
}
void Kded::initModules()
{
m_dontLoad.clear();
TDEConfig *config = kapp->config();
bool tde_running = !( getenv( "TDE_FULL_SESSION" ) == NULL || getenv( "TDE_FULL_SESSION" )[ 0 ] == '\0' );
// not the same user like the one running the session (most likely we're run via sudo or something)
if( getenv( "TDE_SESSION_UID" ) != NULL && uid_t( atoi( getenv( "TDE_SESSION_UID" ))) != getuid())
tde_running = false;
// Preload kded modules.
KService::List kdedModules = KServiceType::offers("KDEDModule");
TQString version = getenv( "KDE_SESSION_VERSION" );
TQStringList blacklist;
if ( !(version == NULL) && version >= "4" )
{
kdDebug(7020) << "KDE4 is running:" << endl;
kdDebug(7020) << " KDE_SESSION_VERSION: " << version << endl;
kdDebug(7020) << " Blacklisting mediamanager, medianotifier, kmilod, kwrited." << endl;
blacklist << "mediamanager" << "medianotifier" << "kmilod" << "kwrited";
}
for(KService::List::ConstIterator it = kdedModules.begin(); it != kdedModules.end(); ++it)
{
KService::Ptr service = *it;
bool autoload = service->property("X-TDE-Kded-autoload", TQVariant::Bool).toBool();
config->setGroup(TQString("Module-%1").arg(service->desktopEntryName()));
autoload = config->readBoolEntry("autoload", autoload);
for (TQStringList::Iterator module = blacklist.begin(); module != blacklist.end(); ++module)
{
if (service->desktopEntryName() == *module)
{
autoload = false;
break;
}
}
if( m_newStartup )
{
// see ksmserver's README for description of the phases
TQVariant phasev = service->property("X-TDE-Kded-phase", TQVariant::Int );
int phase = phasev.isValid() ? phasev.toInt() : 2;
bool prevent_autoload = false;
switch( phase )
{
case 0: // always autoload
break;
case 1: // autoload only in TDE
if( !tde_running )
prevent_autoload = true;
break;
case 2: // autoload delayed, only in TDE
default:
prevent_autoload = true;
break;
}
if (autoload && !prevent_autoload)
loadModule(service, false);
}
else
{
if (autoload && tde_running)
loadModule(service, false);
}
bool dontLoad = false;
TQVariant p = service->property("X-TDE-Kded-load-on-demand", TQVariant::Bool);
if (p.isValid() && (p.toBool() == false))
dontLoad = true;
if (dontLoad)
noDemandLoad(service->desktopEntryName());
if (dontLoad && !autoload)
unloadModule(service->desktopEntryName().latin1());
}
}
void Kded::loadSecondPhase()
{
kdDebug(7020) << "Loading second phase autoload" << endl;
TDEConfig *config = kapp->config();
KService::List kdedModules = KServiceType::offers("KDEDModule");
for(KService::List::ConstIterator it = kdedModules.begin(); it != kdedModules.end(); ++it)
{
KService::Ptr service = *it;
bool autoload = service->property("X-TDE-Kded-autoload", TQVariant::Bool).toBool();
config->setGroup(TQString("Module-%1").arg(service->desktopEntryName()));
autoload = config->readBoolEntry("autoload", autoload);
TQVariant phasev = service->property("X-TDE-Kded-phase", TQVariant::Int );
int phase = phasev.isValid() ? phasev.toInt() : 2;
if( phase == 2 && autoload )
loadModule(service, false);
}
}
void Kded::noDemandLoad(const TQString &obj)
{
m_dontLoad.insert(obj.latin1(), this);
}
KDEDModule *Kded::loadModule(const TQCString &obj, bool onDemand)
{
KDEDModule *module = m_modules.find(obj);
if (module)
return module;
KService::Ptr s = KService::serviceByDesktopPath("kded/"+obj+".desktop");
return loadModule(s, onDemand);
}
KDEDModule *Kded::loadModule(const KService *s, bool onDemand)
{
KDEDModule *module = 0;
if (s && !s->library().isEmpty())
{
TQCString obj = s->desktopEntryName().latin1();
KDEDModule *oldModule = m_modules.find(obj);
if (oldModule)
return oldModule;
if (onDemand)
{
TQVariant p = s->property("X-TDE-Kded-load-on-demand", TQVariant::Bool);
if (p.isValid() && (p.toBool() == false))
{
noDemandLoad(s->desktopEntryName());
return 0;
}
}
// get the library loader instance
KLibLoader *loader = KLibLoader::self();
TQVariant v = s->property("X-TDE-FactoryName", TQVariant::String);
TQString factory = v.isValid() ? v.toString() : TQString::null;
if (factory.isEmpty())
{
// Stay bugward compatible
v = s->property("X-TDE-Factory", TQVariant::String);
factory = v.isValid() ? v.toString() : TQString::null;
}
if (factory.isEmpty())
factory = s->library();
factory = "create_" + factory;
TQString libname = "kded_"+s->library();
KLibrary *lib = loader->library(TQFile::encodeName(libname));
if (!lib)
{
kdWarning() << k_funcinfo << "Could not load library. [ "
<< loader->lastErrorMessage() << " ]" << endl;
libname.prepend("lib");
lib = loader->library(TQFile::encodeName(libname));
}
if (lib)
{
// get the create_ function
void *create = lib->symbol(TQFile::encodeName(factory));
if (create)
{
// create the module
KDEDModule* (*func)(const TQCString &);
func = (KDEDModule* (*)(const TQCString &)) create;
module = func(obj);
if (module)
{
m_modules.insert(obj, module);
m_libs.insert(obj, lib);
connect(module, TQT_SIGNAL(moduleDeleted(KDEDModule *)), TQT_SLOT(slotKDEDModuleRemoved(KDEDModule *)));
kdDebug(7020) << "Successfully loaded module '" << obj << "'\n";
return module;
}
}
loader->unloadLibrary(TQFile::encodeName(libname));
}
else
{
kdWarning() << k_funcinfo << "Could not load library. [ "
<< loader->lastErrorMessage() << " ]" << endl;
}
kdDebug(7020) << "Could not load module '" << obj << "'\n";
}
return 0;
}
bool Kded::unloadModule(const TQCString &obj)
{
KDEDModule *module = m_modules.take(obj);
if (!module)
return false;
kdDebug(7020) << "Unloading module '" << obj << "'\n";
delete module;
return true;
}
// DCOP
QCStringList Kded::loadedModules()
{
QCStringList modules;
TQAsciiDictIterator<KDEDModule> it( m_modules );
for ( ; it.current(); ++it)
modules.append( it.currentKey() );
return modules;
}
QCStringList Kded::functions()
{
QCStringList res = DCOPObject::functions();
res += "ASYNC recreate()";
return res;
}
void Kded::slotKDEDModuleRemoved(KDEDModule *module)
{
m_modules.remove(module->objId());
KLibrary *lib = m_libs.take(module->objId());
if (lib)
lib->unload();
}
void Kded::slotApplicationRemoved(const TQCString &appId)
{
for(TQAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it)
{
it.current()->removeAll(appId);
}
TQValueList<long> *windowIds = m_windowIdList.find(appId);
if (windowIds)
{
for( TQValueList<long>::ConstIterator it = windowIds->begin();
it != windowIds->end(); ++it)
{
long windowId = *it;
m_globalWindowIdList.remove(windowId);
for(TQAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it)
{
emit it.current()->windowUnregistered(windowId);
}
}
m_windowIdList.remove(appId);
}
}
void Kded::updateDirWatch()
{
if (!b_checkUpdates) return;
delete m_pDirWatch;
m_pDirWatch = new KDirWatch;
TQObject::connect( m_pDirWatch, TQT_SIGNAL(dirty(const TQString&)),
this, TQT_SLOT(update(const TQString&)));
TQObject::connect( m_pDirWatch, TQT_SIGNAL(created(const TQString&)),
this, TQT_SLOT(update(const TQString&)));
TQObject::connect( m_pDirWatch, TQT_SIGNAL(deleted(const TQString&)),
this, TQT_SLOT(dirDeleted(const TQString&)));
// For each resource
for( TQStringList::ConstIterator it = m_allResourceDirs.begin();
it != m_allResourceDirs.end();
++it )
{
readDirectory( *it );
}
}
void Kded::updateResourceList()
{
delete KSycoca::self();
if (!b_checkUpdates) return;
if (delayedCheck) return;
TQStringList dirs = KSycoca::self()->allResourceDirs();
// For each resource
for( TQStringList::ConstIterator it = dirs.begin();
it != dirs.end();
++it )
{
if (m_allResourceDirs.find(*it) == m_allResourceDirs.end())
{
m_allResourceDirs.append(*it);
readDirectory(*it);
}
}
}
void Kded::crashHandler(int)
{
DCOPClient::emergencyClose();
if (_self) { // Don't restart if we were closing down
tqWarning("Last DCOP call before KDED crash was from application '%s'\n"
"to object '%s', function '%s'.",
DCOPClient::postMortemSender(),
DCOPClient::postMortemObject(),
DCOPClient::postMortemFunction());
tqWarning("Restarting KDED...\n");
if (system("kded") < 0) {
tqWarning("Unable to restart KDED!\n");
}
}
}
void Kded::installCrashHandler()
{
TDECrash::setEmergencySaveFunction(crashHandler);
}
void Kded::recreate()
{
recreate(false);
}
void Kded::runDelayedCheck()
{
if( m_needDelayedCheck )
recreate(false);
m_needDelayedCheck = false;
}
void Kded::recreate(bool initial)
{
m_recreateBusy = true;
// Using TDELauncher here is difficult since we might not have a
// database
if (!initial)
{
updateDirWatch(); // Update tree first, to be sure to miss nothing.
runBuildSycoca(this, TQT_SLOT(recreateDone()));
}
else
{
if(!delayedCheck)
updateDirWatch(); // this would search all the directories
runBuildSycoca();
recreateDone();
if(delayedCheck)
{
// do a proper tdesycoca check after a delay
TQTimer::singleShot( 60000, this, TQT_SLOT( runDelayedCheck()));
m_needDelayedCheck = true;
delayedCheck = false;
}
else
m_needDelayedCheck = false;
}
}
void Kded::recreateDone()
{
updateResourceList();
for(; m_recreateCount; m_recreateCount--)
{
TQCString replyType = "void";
TQByteArray replyData;
DCOPClientTransaction *transaction = m_recreateRequests.first();
if (transaction)
kapp->dcopClient()->endTransaction(transaction, replyType, replyData);
m_recreateRequests.remove(m_recreateRequests.begin());
}
m_recreateBusy = false;
// Did a new request come in while building?
if (!m_recreateRequests.isEmpty())
{
m_pTimer->start(2000, true /* single shot */ );
m_recreateCount = m_recreateRequests.count();
}
}
void Kded::dirDeleted(const TQString& path)
{
update(path);
}
void Kded::update(const TQString& )
{
if (!m_recreateBusy)
{
m_pTimer->start( 2000, true /* single shot */ );
}
else
{
m_recreateRequests.append(0);
}
}
bool Kded::process(const TQCString &fun, const TQByteArray &data,
TQCString &replyType, TQByteArray &replyData)
{
if (fun == "recreate()") {
if (!m_recreateBusy)
{
if (m_recreateRequests.isEmpty())
{
m_pTimer->start(0, true /* single shot */ );
m_recreateCount = 0;
}
m_recreateCount++;
}
m_recreateRequests.append(kapp->dcopClient()->beginTransaction());
replyType = "void";
return true;
} else {
return DCOPObject::process(fun, data, replyType, replyData);
}
}
void Kded::readDirectory( const TQString& _path )
{
TQString path( _path );
if ( path.right(1) != "/" )
path += "/";
if ( m_pDirWatch->contains( path ) ) // Already seen this one?
return;
TQDir d( _path, TQString::null, TQDir::Unsorted, TQDir::Readable | TQDir::Executable | TQDir::Dirs | TQDir::Hidden );
// set TQDir ...
//************************************************************************
// Setting dirs
//************************************************************************
m_pDirWatch->addDir(path); // add watch on this dir
if ( !d.exists() ) // exists&isdir?
{
kdDebug(7020) << TQString(TQString("Does not exist! (%1)").arg(_path)) << endl;
return; // return false
}
// Note: If some directory is gone, dirwatch will delete it from the list.
//************************************************************************
// Reading
//************************************************************************
TQString file;
unsigned int i; // counter and string length.
unsigned int count = d.count();
for( i = 0; i < count; i++ ) // check all entries
{
if (d[i] == "." || d[i] == ".." || d[i] == "magic")
continue; // discard those ".", "..", "magic"...
file = path; // set full path
file += d[i]; // and add the file name.
readDirectory( file ); // yes, dive into it.
}
}
bool Kded::isWindowRegistered(long windowId)
{
return m_globalWindowIdList.find(windowId) != 0;
}
// DCOP
void Kded::registerWindowId(long windowId)
{
m_globalWindowIdList.replace(windowId, &windowId);
TQCString sender = callingDcopClient()->senderId();
if( sender.isEmpty()) // local call
sender = callingDcopClient()->appId();
TQValueList<long> *windowIds = m_windowIdList.find(sender);
if (!windowIds)
{
windowIds = new TQValueList<long>;
m_windowIdList.insert(sender, windowIds);
}
windowIds->append(windowId);
for(TQAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it)
{
emit it.current()->windowRegistered(windowId);
}
}
// DCOP
void Kded::unregisterWindowId(long windowId)
{
m_globalWindowIdList.remove(windowId);
TQCString sender = callingDcopClient()->senderId();
if( sender.isEmpty()) // local call
sender = callingDcopClient()->appId();
TQValueList<long> *windowIds = m_windowIdList.find(sender);
if (windowIds)
{
windowIds->remove(windowId);
if (windowIds->isEmpty())
m_windowIdList.remove(sender);
}
for(TQAsciiDictIterator<KDEDModule> it(m_modules); it.current(); ++it)
{
emit it.current()->windowUnregistered(windowId);
}
}
static void sighandler(int /*sig*/)
{
if (kapp)
kapp->quit();
}
KUpdateD::KUpdateD()
{
m_pDirWatch = new KDirWatch;
m_pTimer = new TQTimer;
connect(m_pTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(runKonfUpdate()));
TQObject::connect( m_pDirWatch, TQT_SIGNAL(dirty(const TQString&)),
this, TQT_SLOT(slotNewUpdateFile()));
TQStringList dirs = TDEGlobal::dirs()->findDirs("data", "tdeconf_update");
for( TQStringList::ConstIterator it = dirs.begin();
it != dirs.end();
++it )
{
TQString path = *it;
if (path[path.length()-1] != '/')
path += "/";
if (!m_pDirWatch->contains(path))
m_pDirWatch->addDir(path);
}
}
KUpdateD::~KUpdateD()
{
delete m_pDirWatch;
delete m_pTimer;
}
void KUpdateD::runKonfUpdate()
{
::runKonfUpdate();
}
void KUpdateD::slotNewUpdateFile()
{
m_pTimer->start( 500, true /* single shot */ );
}
KHostnameD::KHostnameD(int pollInterval)
{
m_Timer.start(pollInterval, false /* repetitive */ );
connect(&m_Timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(checkHostname()));
checkHostname();
}
KHostnameD::~KHostnameD()
{
// Empty
}
void KHostnameD::checkHostname()
{
char buf[1024+1];
if (gethostname(buf, 1024) != 0)
return;
buf[sizeof(buf)-1] = '\0';
if (m_hostname.isEmpty())
{
m_hostname = buf;
return;
}
if (m_hostname == buf)
return;
TQCString newHostname = buf;
runDontChangeHostname(m_hostname, newHostname);
m_hostname = newHostname;
}
static TDECmdLineOptions options[] =
{
{ "check", I18N_NOOP("Check Sycoca database only once"), 0 },
{ "new-startup", "Internal", 0 },
TDECmdLineLastOption
};
class KDEDQtDCOPObject : public DCOPObject
{
public:
KDEDQtDCOPObject() : DCOPObject("qt/kded") { }
virtual bool process(const TQCString &fun, const TQByteArray &data,
TQCString& replyType, TQByteArray &replyData)
{
if ( kapp && (fun == "quit()") )
{
kapp->quit();
replyType = "void";
return true;
}
return DCOPObject::process(fun, data, replyType, replyData);
}
QCStringList functions()
{
QCStringList res = DCOPObject::functions();
res += "void quit()";
return res;
}
};
class KDEDApplication : public KUniqueApplication
{
public:
KDEDApplication() : KUniqueApplication( )
{
startup = true;
dcopClient()->connectDCOPSignal( "DCOPServer", "", "terminateTDE()",
objId(), "quit()", false );
}
int newInstance()
{
if (startup) {
startup = false;
if( Kded::self()->newStartup())
Kded::self()->initModules();
else
TQTimer::singleShot(500, Kded::self(), TQT_SLOT(initModules()));
} else
runBuildSycoca();
return 0;
}
QCStringList functions()
{
QCStringList res = KUniqueApplication::functions();
res += "bool loadModule(TQCString)";
res += "bool unloadModule(TQCString)";
res += "void registerWindowId(long int)";
res += "void unregisterWindowId(long int)";
res += "QCStringList loadedModules()";
res += "void reconfigure()";
res += "void loadSecondPhase()";
res += "void quit()";
return res;
}
bool process(const TQCString &fun, const TQByteArray &data,
TQCString &replyType, TQByteArray &replyData)
{
if (fun == "loadModule(TQCString)") {
TQCString module;
TQDataStream arg( data, IO_ReadOnly );
arg >> module;
bool result = (Kded::self()->loadModule(module, false) != 0);
replyType = "bool";
TQDataStream _replyStream( replyData, IO_WriteOnly );
_replyStream << result;
return true;
}
else if (fun == "unloadModule(TQCString)") {
TQCString module;
TQDataStream arg( data, IO_ReadOnly );
arg >> module;
bool result = Kded::self()->unloadModule(module);
replyType = "bool";
TQDataStream _replyStream( replyData, IO_WriteOnly );
_replyStream << result;
return true;
}
else if (fun == "registerWindowId(long int)") {
long windowId;
TQDataStream arg( data, IO_ReadOnly );
arg >> windowId;
Kded::self()->setCallingDcopClient(callingDcopClient());
Kded::self()->registerWindowId(windowId);
replyType = "void";
return true;
}
else if (fun == "unregisterWindowId(long int)") {
long windowId;
TQDataStream arg( data, IO_ReadOnly );
arg >> windowId;
Kded::self()->setCallingDcopClient(callingDcopClient());
Kded::self()->unregisterWindowId(windowId);
replyType = "void";
return true;
}
else if (fun == "loadedModules()") {
replyType = "QCStringList";
TQDataStream _replyStream(replyData, IO_WriteOnly);
_replyStream << Kded::self()->loadedModules();
return true;
}
else if (fun == "reconfigure()") {
config()->reparseConfiguration();
Kded::self()->initModules();
replyType = "void";
return true;
}
else if (fun == "loadSecondPhase()") {
Kded::self()->loadSecondPhase();
replyType = "void";
return true;
}
else if (fun == "quit()") {
quit();
replyType = "void";
return true;
}
return KUniqueApplication::process(fun, data, replyType, replyData);
}
bool startup;
KDEDQtDCOPObject kdedQtDcopObject;
};
extern "C" KDE_EXPORT int kdemain(int argc, char *argv[])
{
TDEAboutData aboutData( "kded", I18N_NOOP("TDE Daemon"),
"$Id$",
I18N_NOOP("TDE Daemon - triggers Sycoca database updates when needed"));
TDEApplication::installSigpipeHandler();
TDECmdLineArgs::init(argc, argv, &aboutData);
KUniqueApplication::addCmdLineOptions();
TDECmdLineArgs::addCmdLineOptions( options );
// this program is in tdelibs so it uses tdelibs as catalog
TDELocale::setMainCatalogue("tdelibs");
// WABA: Make sure not to enable session management.
putenv(strdup("SESSION_MANAGER="));
// Parse command line before checking DCOP
TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
// Check DCOP communication.
{
DCOPClient testDCOP;
TQCString dcopName = testDCOP.registerAs("kded", false);
if (dcopName.isEmpty())
{
kdFatal() << "DCOP communication problem!" << endl;
return 1;
}
}
TDEInstance *instance = new TDEInstance(&aboutData);
TDEConfig *config = instance->config(); // Enable translations.
if (args->isSet("check"))
{
config->setGroup("General");
checkStamps = config->readBoolEntry("CheckFileStamps", true);
runBuildSycoca();
runKonfUpdate();
exit(0);
}
if (!KUniqueApplication::start())
{
fprintf(stderr, "[kded] Daemon (kded) is already running.\n");
exit(0);
}
KUniqueApplication::dcopClient()->setQtBridgeEnabled(false);
config->setGroup("General");
int HostnamePollInterval = config->readNumEntry("HostnamePollInterval", 5000);
bool bCheckSycoca = config->readBoolEntry("CheckSycoca", true);
bool bCheckUpdates = config->readBoolEntry("CheckUpdates", true);
bool bCheckHostname = config->readBoolEntry("CheckHostname", true);
checkStamps = config->readBoolEntry("CheckFileStamps", true);
delayedCheck = config->readBoolEntry("DelayedCheck", false);
Kded *kded = new Kded(bCheckSycoca, args->isSet("new-startup")); // Build data base
signal(SIGTERM, sighandler);
signal(SIGHUP, sighandler);
KDEDApplication k;
kded->recreate(true); // initial
if (bCheckUpdates)
(void) new KUpdateD; // Watch for updates
runKonfUpdate(); // Run it once.
if (bCheckHostname)
(void) new KHostnameD(HostnamePollInterval); // Watch for hostname changes
DCOPClient *client = kapp->dcopClient();
TQObject::connect(client, TQT_SIGNAL(applicationRemoved(const TQCString&)),
kded, TQT_SLOT(slotApplicationRemoved(const TQCString&)));
client->setNotifications(true);
client->setDaemonMode( true );
// During startup kdesktop waits for KDED to finish.
// Send a notifyDatabaseChanged signal even if the database hasn't
// changed.
// If the database changed, tdebuildsycoca's signal didn't go anywhere
// anyway, because it was too early, so let's send this signal
// unconditionnally (David)
TQByteArray data;
client->send( "*", "tdesycoca", "notifyDatabaseChanged()", data );
client->send( "ksplash", "", "upAndRunning(TQString)", TQString("kded"));
#ifdef Q_WS_X11
XEvent e;
e.xclient.type = ClientMessage;
e.xclient.message_type = XInternAtom( tqt_xdisplay(), "_KDE_SPLASH_PROGRESS", False );
e.xclient.display = tqt_xdisplay();
e.xclient.window = tqt_xrootwin();
e.xclient.format = 8;
strcpy( e.xclient.data.b, "kded" );
XSendEvent( tqt_xdisplay(), tqt_xrootwin(), False, SubstructureNotifyMask, &e );
#endif
int result = k.exec(); // keep running
delete kded;
delete instance; // Deletes config as well
return result;
}
#include "kded.moc"