~ubuntu-branches/ubuntu/oneiric/kdelibs/oneiric

« back to all changes in this revision

Viewing changes to .pc/kubuntu_9902_kde4_kded_blacklist_modules.diff/kded/kded.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2010-10-15 19:20:42 UTC
  • mfrom: (1.1.19 sid)
  • Revision ID: james.westby@ubuntu.com-20101015192042-jv1fhj33n4f5b398
Tags: 4:3.5.10.dfsg.1-5ubuntu1
* Merge from Debian unstable. Remaining Ubuntu changes:
  - make sure control and control.in are in sync
  - --with-distribution="Kubuntu (`lsb_release --codename --short`)
    $(DEB_VERSION)"
  - binary-install/kdelibs-data installs aboutkde-kubuntu.png.uu and
    cr*-device-system.png.uu
  - don't build-dep on libgamin-dev, libfam-dev
  - stop kdelibs4-dev depending on gamin/fam
  - don't install .svgz icons, docs or all_languages in kdelibs-data.install
  - rosetta support in rules common-install-prehook-impl:: [and
    common-post-build-arch:: ?] and include debian/kubuntu-desktop-i18n/
  - build-dep on: gettext-kde, kdesdk-scripts, lsb-release, base-files, sudo
  - cdbs build-dep 0.4.41ubuntu2
  - kdelibs4-dev depends on gettext-kde, kdesdk-scripts
  - copy debian/icons over
  - Make kdelibs4c2a depend on launchpad-integration, sudo.  Recommends on
    xdg-user-dirs
  - Remove 19_debianize_useragent.diff (changed to
    kubuntu_19_debianize_useragent.diff) s/Debian/Kubuntu
  - remove kdelibs4c2a depends on menu-xdg
  - include kubuntu_01_kdepot.diff and kde.pot in debian/patches/common
  - use a local copy of kde.mk without the common-install-prehook-impl::
    rule; edit debian-qt-kde.mk to include debian/cdbs/kde.mk
  - build with --with-sudo-kdesu-backend and build-dep on sudo and make
    kdelibs4c2a depend on sudo
  - kdelibs-data.install : Add nzb mimetype
  - Make kdelibs4-dev replace more recent kdelibs4c2a for overlapping files
  - remove /usr/bin/preparetips, arts files and ksvntopng from
    kdelibs4-dev.install
  - Drop the package kdelibs4-doc completely. It contained API documentation
    which is now obsolete, but still available via api.kde.org.
  - make sure control and control.in are in sync
  - in debian/rule remove .pot files outside .po directory
  - 97_automake_cleanup.diff becomes kubuntu_97_automake_cleanup.diff
  - Remove libarts1-dev from build-depends and kdelibs4-dev depends from
    control.in
* Drop kubuntu_98_fix_khc_invocation.diff, replaced by
  68_support_khelpcenter4.diff
* Drop kubuntu_97_automake_cleanup.diff, replaced by 97_automake_cleanup.diff
* Re-add security_05_XMLHttpRequest_vulnerability.diff which has been
  accidentally dropped
* Fix FTBFS, in debian/rules:
  - Add -Wl,--add-needed to LDFLAGS
  - Disable parallel building

Show diffs side-by-side

added added

removed removed

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