~ubuntu-branches/ubuntu/gutsy/kde4libs/gutsy

« back to all changes in this revision

Viewing changes to kdeui/kernel/kapplication.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2007-02-21 11:00:12 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20070221110012-6kw8khr9knv6lmg1
Tags: 3.80.3-0ubuntu1
New upstream unstable release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is part of the KDE libraries
 
2
    Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
 
3
    Copyright (C) 1998, 1999, 2000 KDE Team
 
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 as published by the Free Software Foundation; either
 
8
    version 2 of the License, or (at your option) any later version.
 
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 "config.h"
 
22
 
 
23
#undef QT_NO_TRANSLATION
 
24
#include <qtranslator.h>
 
25
#define QT_NO_TRANSLATION
 
26
#include <qtextedit.h>
 
27
#include <qdatetime.h>
 
28
#include <qdir.h>
 
29
#include <qfile.h>
 
30
#include <qicon.h>
 
31
#include <qlineedit.h>
 
32
#include <qmessagebox.h>
 
33
#include <qmetaobject.h>
 
34
#include <qregexp.h>
 
35
#include <qsessionmanager.h>
 
36
#include <qstylefactory.h>
 
37
#include <qtextstream.h>
 
38
#include <qtimer.h>
 
39
#include <qtooltip.h>
 
40
#include <qwidget.h>
 
41
#include <qlist.h>
 
42
#include <QtDBus/QtDBus>
 
43
 
 
44
#undef QT_NO_TRANSLATION
 
45
#include "kapplication.h"
 
46
#define QT_NO_TRANSLATION
 
47
#include "kauthorized.h"
 
48
#include "kaboutdata.h"
 
49
#include "kcheckaccelerators.h"
 
50
#include "kcrash.h"
 
51
#include "kconfig.h"
 
52
#include "kcmdlineargs.h"
 
53
#include "kclipboard.h"
 
54
#include "kglobalsettings.h"
 
55
#include "kdebug.h"
 
56
#include "kglobal.h"
 
57
#include "kiconloader.h"
 
58
#include "klibloader.h"
 
59
#include "klocale.h"
 
60
#include "ksessionmanager.h"
 
61
#include "kstandarddirs.h"
 
62
#include "kstandardshortcut.h"
 
63
#include "ktoolinvocation.h"
 
64
 
 
65
#if defined Q_WS_X11
 
66
#include <QtGui/qx11info_x11.h>
 
67
#include <kstartupinfo.h>
 
68
#endif
 
69
 
 
70
#include <sys/types.h>
 
71
#ifdef HAVE_SYS_STAT_H
 
72
#include <sys/stat.h>
 
73
#endif
 
74
#include <sys/wait.h>
 
75
 
 
76
#ifndef Q_WS_WIN
 
77
#include "kwin.h"
 
78
#endif
 
79
 
 
80
#include <fcntl.h>
 
81
#include <stdlib.h> // getenv(), srand(), rand()
 
82
#include <signal.h>
 
83
#include <unistd.h>
 
84
#include <time.h>
 
85
#include <sys/time.h>
 
86
#include <errno.h>
 
87
#include <string.h>
 
88
#include <netdb.h>
 
89
#if defined Q_WS_X11
 
90
//#ifndef Q_WS_QWS //FIXME(E): NetWM should talk to QWS...
 
91
#include <netwm.h>
 
92
#endif
 
93
 
 
94
#ifdef HAVE_PATHS_H
 
95
#include <paths.h>
 
96
#endif
 
97
 
 
98
#ifdef Q_WS_X11
 
99
#include <X11/Xlib.h>
 
100
#include <X11/Xutil.h>
 
101
#include <X11/Xatom.h>
 
102
#include <X11/SM/SMlib.h>
 
103
#include <fixx11h.h>
 
104
 
 
105
#include <QX11Info>
 
106
#endif
 
107
 
 
108
#ifdef Q_WS_MACX
 
109
// ick
 
110
#undef Status
 
111
#include <Carbon/Carbon.h>
 
112
#include <QImage>
 
113
#include <QSystemTrayIcon>
 
114
#endif
 
115
 
 
116
#include <qevent.h>
 
117
#include <QDesktopWidget>
 
118
#include <QMetaObject>
 
119
#include <kcomponentdata.h>
 
120
 
 
121
KApplication* KApplication::KApp = 0L;
 
122
bool KApplication::loadedByKdeinit = false;
 
123
 
 
124
#ifdef Q_WS_X11
 
125
static Atom atom_DesktopWindow;
 
126
static Atom atom_NetSupported;
 
127
static Atom kde_xdnd_drop;
 
128
#endif
 
129
 
 
130
// duplicated from patched Qt, so that there won't be unresolved symbols if Qt gets
 
131
// replaced by unpatched one
 
132
KDEUI_EXPORT bool qt_qclipboard_bailout_hack = false;
 
133
 
 
134
template class QList<KSessionManager*>;
 
135
 
 
136
#ifdef Q_WS_X11
 
137
extern "C" {
 
138
static int kde_xio_errhandler( Display * dpy )
 
139
{
 
140
  return kapp->xioErrhandler( dpy );
 
141
}
 
142
 
 
143
static int kde_x_errhandler( Display *dpy, XErrorEvent *err )
 
144
{
 
145
  return kapp->xErrhandler( dpy, err );
 
146
}
 
147
 
 
148
}
 
149
#endif
 
150
 
 
151
#ifdef Q_WS_WIN
 
152
void KApplication_init_windows();
 
153
#endif
 
154
 
 
155
/*
 
156
  Private data to make keeping binary compatibility easier
 
157
 */
 
158
class KApplication::Private
 
159
{
 
160
public:
 
161
  Private(const QByteArray &cName)
 
162
      : componentData(cName),
 
163
      checkAccelerators(0),
 
164
      startup_id("0"),
 
165
      app_started_timer(0),
 
166
      session_save(false)
 
167
#ifdef Q_WS_X11
 
168
      , oldIceIOErrorHandler(0)
 
169
      , oldXErrorHandler(0)
 
170
      , oldXIOErrorHandler(0)
 
171
#endif
 
172
  {
 
173
  }
 
174
 
 
175
  Private(const KComponentData &cData)
 
176
      : componentData(cData),
 
177
      checkAccelerators(0),
 
178
      startup_id("0"),
 
179
      app_started_timer(0),
 
180
      session_save(false)
 
181
#ifdef Q_WS_X11
 
182
      , oldIceIOErrorHandler(0)
 
183
      , oldXErrorHandler(0)
 
184
      , oldXIOErrorHandler(0)
 
185
#endif
 
186
  {
 
187
  }
 
188
 
 
189
  Private()
 
190
      : componentData(KCmdLineArgs::aboutData()),
 
191
      checkAccelerators(0),
 
192
      startup_id( "0" ),
 
193
      app_started_timer( 0 ),
 
194
      session_save( false )
 
195
#ifdef Q_WS_X11
 
196
      ,oldIceIOErrorHandler( 0 )
 
197
      ,oldXErrorHandler( 0 )
 
198
      ,oldXIOErrorHandler( 0 )
 
199
#endif
 
200
  {
 
201
  }
 
202
 
 
203
  ~Private()
 
204
  {
 
205
  }
 
206
 
 
207
  KComponentData componentData;
 
208
  KCheckAccelerators* checkAccelerators;
 
209
  QByteArray startup_id;
 
210
  QTimer* app_started_timer;
 
211
  bool session_save;
 
212
#ifdef Q_WS_X11
 
213
  IceIOErrorHandler oldIceIOErrorHandler;
 
214
  int (*oldXErrorHandler)(Display*,XErrorEvent*);
 
215
  int (*oldXIOErrorHandler)(Display*);
 
216
#endif
 
217
 
 
218
  QString sessionKey;
 
219
  QString pSessionConfigFile;
 
220
};
 
221
 
 
222
 
 
223
static QList<const QWidget*> *x11Filter = 0;
 
224
 
 
225
/**
 
226
   * Installs a handler for the SIGPIPE signal. It is thrown when you write to
 
227
   * a pipe or socket that has been closed.
 
228
   * The handler is installed automatically in the constructor, but you may
 
229
   * need it if your application or component does not have a KApplication
 
230
   * instance.
 
231
   */
 
232
static void installSigpipeHandler()
 
233
{
 
234
#ifdef Q_OS_UNIX
 
235
    struct sigaction act;
 
236
    act.sa_handler = SIG_IGN;
 
237
    sigemptyset( &act.sa_mask );
 
238
    act.sa_flags = 0;
 
239
    sigaction( SIGPIPE, &act, 0 );
 
240
#endif
 
241
}
 
242
 
 
243
void KApplication::installX11EventFilter( QWidget* filter )
 
244
{
 
245
    if ( !filter )
 
246
        return;
 
247
    if (!x11Filter)
 
248
        x11Filter = new QList<const QWidget *>;
 
249
    connect ( filter, SIGNAL( destroyed() ), this, SLOT( x11FilterDestroyed() ) );
 
250
    x11Filter->append( filter );
 
251
}
 
252
 
 
253
void KApplication::x11FilterDestroyed()
 
254
{
 
255
    removeX11EventFilter( static_cast< const QWidget* >( sender()));
 
256
}
 
257
 
 
258
void KApplication::removeX11EventFilter( const QWidget* filter )
 
259
{
 
260
    if ( !x11Filter || !filter )
 
261
        return;
 
262
    x11Filter->removeAll( filter );
 
263
    if ( x11Filter->isEmpty() ) {
 
264
        delete x11Filter;
 
265
        x11Filter = 0;
 
266
    }
 
267
}
 
268
 
 
269
bool KApplication::notify(QObject *receiver, QEvent *event)
 
270
{
 
271
    QEvent::Type t = event->type();
 
272
    if( t == QEvent::Show && receiver->isWidgetType())
 
273
    {
 
274
        QWidget* w = static_cast< QWidget* >( receiver );
 
275
#if defined Q_WS_X11
 
276
        if( w->isTopLevel() && !startupId().isEmpty()) // TODO better done using window group leader?
 
277
            KStartupInfo::setWindowStartupId( w->winId(), startupId());
 
278
#endif
 
279
        if( w->isTopLevel() && !( w->windowFlags() & Qt::X11BypassWindowManagerHint ) && w->windowType() != Qt::Popup && !event->spontaneous())
 
280
        {
 
281
            if( d->app_started_timer == NULL )
 
282
            {
 
283
                d->app_started_timer = new QTimer( this );
 
284
                connect( d->app_started_timer, SIGNAL( timeout()), SLOT( checkAppStartedSlot()));
 
285
            }
 
286
            if( !d->app_started_timer->isActive()) {
 
287
                d->app_started_timer->setSingleShot( true );
 
288
                d->app_started_timer->start( 0 );
 
289
            }
 
290
        }
 
291
    }
 
292
    return QApplication::notify(receiver, event);
 
293
}
 
294
 
 
295
void KApplication::checkAppStartedSlot()
 
296
{
 
297
#if defined Q_WS_X11
 
298
    KStartupInfo::handleAutoAppStartedSending();
 
299
#endif
 
300
}
 
301
 
 
302
/*
 
303
  Auxiliary function to calculate a a session config name used for the
 
304
  instance specific config object.
 
305
  Syntax:  "session/<appname>_<sessionId>"
 
306
 */
 
307
QString KApplication::sessionConfigName() const
 
308
{
 
309
#ifdef QT_NO_SESSIONMANAGER
 
310
#error QT_NO_SESSIONMANAGER was set, this will not compile. Reconfigure Qt with Session management support.
 
311
#endif
 
312
    QString sessKey = sessionKey();
 
313
    if ( sessKey.isEmpty() && !d->sessionKey.isEmpty() )
 
314
        sessKey = d->sessionKey;
 
315
    return QString(QLatin1String("session/%1_%2_%3")).arg(applicationName()).arg(sessionId()).arg(sessKey);
 
316
}
 
317
 
 
318
#ifdef Q_WS_X11
 
319
static SmcConn mySmcConnection = 0;
 
320
#else
 
321
// FIXME(E): Implement for Qt Embedded
 
322
// Possibly "steal" XFree86's libSM?
 
323
#endif
 
324
 
 
325
KApplication::KApplication(bool GUIenabled)
 
326
    : QApplication(KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv(), GUIenabled),
 
327
    d(new Private)
 
328
{
 
329
    read_app_startup_id();
 
330
    setApplicationName(QLatin1String(d->componentData.componentName()));
 
331
    setOrganizationDomain( KCmdLineArgs::about->organizationDomain() );
 
332
    installSigpipeHandler();
 
333
    init();
 
334
}
 
335
 
 
336
#ifdef Q_WS_X11
 
337
KApplication::KApplication(Display *dpy, Qt::HANDLE visual, Qt::HANDLE colormap)
 
338
    : QApplication(dpy, KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv(), visual, colormap),
 
339
    d(new Private)
 
340
{
 
341
    read_app_startup_id();
 
342
    setApplicationName(QLatin1String(d->componentData.componentName()));
 
343
    setOrganizationDomain( KCmdLineArgs::about->organizationDomain() );
 
344
    installSigpipeHandler();
 
345
    init();
 
346
}
 
347
 
 
348
KApplication::KApplication(Display *dpy, Qt::HANDLE visual, Qt::HANDLE colormap, const KComponentData &cData)
 
349
    : QApplication(dpy, KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv(), visual, colormap),
 
350
    d (new Private(cData))
 
351
{
 
352
    read_app_startup_id();
 
353
    setApplicationName(QLatin1String(d->componentData.componentName()));
 
354
    setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
 
355
    installSigpipeHandler();
 
356
    init();
 
357
}
 
358
#endif
 
359
 
 
360
KApplication::KApplication(bool GUIenabled, const KComponentData &cData)
 
361
    : QApplication(KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv(), GUIenabled),
 
362
    d (new Private(cData))
 
363
{
 
364
    read_app_startup_id();
 
365
    setApplicationName(QLatin1String(d->componentData.componentName()));
 
366
    setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
 
367
    installSigpipeHandler();
 
368
    init();
 
369
}
 
370
 
 
371
#ifdef Q_WS_X11
 
372
KApplication::KApplication(Display *display, int& argc, char** argv, const QByteArray& rAppName,
 
373
        bool GUIenabled)
 
374
    : QApplication(display),
 
375
    d(new Private(rAppName))
 
376
{
 
377
    Q_UNUSED(GUIenabled);
 
378
    read_app_startup_id();
 
379
    setApplicationName(QLatin1String(rAppName));
 
380
    installSigpipeHandler();
 
381
    KCmdLineArgs::initIgnore(argc, argv, rAppName.data());
 
382
    init();
 
383
}
 
384
#endif
 
385
 
 
386
int KApplication::xioErrhandler( Display* dpy )
 
387
{
 
388
    if(kapp)
 
389
    {
 
390
        emit aboutToQuit();
 
391
#ifdef Q_WS_X11
 
392
        d->oldXIOErrorHandler( dpy );
 
393
#else
 
394
        Q_UNUSED(dpy);
 
395
#endif
 
396
    }
 
397
    exit( 1 );
 
398
    return 0;
 
399
}
 
400
 
 
401
int KApplication::xErrhandler( Display* dpy, void* err_ )
 
402
{ // no idea how to make forward decl. for XErrorEvent
 
403
#ifdef Q_WS_X11
 
404
    XErrorEvent* err = static_cast< XErrorEvent* >( err_ );
 
405
    if(kapp)
 
406
    {
 
407
        // add KDE specific stuff here
 
408
        d->oldXErrorHandler( dpy, err );
 
409
    }
 
410
#endif
 
411
    return 0;
 
412
}
 
413
 
 
414
void KApplication::iceIOErrorHandler( _IceConn *conn )
 
415
{
 
416
    emit aboutToQuit();
 
417
 
 
418
#ifdef Q_WS_X11
 
419
    if ( d->oldIceIOErrorHandler != NULL )
 
420
      (*d->oldIceIOErrorHandler)( conn );
 
421
#endif
 
422
    exit( 1 );
 
423
}
 
424
 
 
425
class KDETranslator : public QTranslator
 
426
{
 
427
public:
 
428
  KDETranslator(QObject *parent) : QTranslator(parent)
 
429
  {
 
430
    setObjectName(QLatin1String("kdetranslator"));
 
431
  }
 
432
 
 
433
  virtual QString translate(const char* context,
 
434
                                         const char *sourceText,
 
435
                                         const char* message) const
 
436
  {
 
437
    return KGlobal::locale()->translateQt(context, sourceText, message);
 
438
  }
 
439
};
 
440
 
 
441
void KApplication::init()
 
442
{
 
443
  if ((getuid() != geteuid()) ||
 
444
      (getgid() != getegid()))
 
445
  {
 
446
     fprintf(stderr, "The KDE libraries are not designed to run with suid privileges.\n");
 
447
     ::exit(127);
 
448
  }
 
449
 
 
450
  if ( type() == GuiClient )
 
451
  {
 
452
    QStringList plugins = KGlobal::dirs()->resourceDirs( "qtplugins" );
 
453
    QStringList::Iterator it = plugins.begin();
 
454
    while (it != plugins.end()) {
 
455
      addLibraryPath( *it );
 
456
      ++it;
 
457
    }
 
458
  }
 
459
 
 
460
  KApp = this;
 
461
 
 
462
  parseCommandLine();
 
463
 
 
464
  (void) KClipboardSynchronizer::self();
 
465
 
 
466
  extern KDECORE_EXPORT bool kde_kdebug_enable_dbus_interface;
 
467
  kde_kdebug_enable_dbus_interface = true;
 
468
 
 
469
  QApplication::setDesktopSettingsAware( false );
 
470
 
 
471
#ifdef Q_WS_X11 //FIXME(E)
 
472
  // create all required atoms in _one_ roundtrip to the X server
 
473
  if ( type() == GuiClient ) {
 
474
      const int max = 20;
 
475
      Atom* atoms[max];
 
476
      char* names[max];
 
477
      Atom atoms_return[max];
 
478
      int n = 0;
 
479
 
 
480
      atoms[n] = &atom_DesktopWindow;
 
481
      names[n++] = (char *) "KDE_DESKTOP_WINDOW";
 
482
 
 
483
      atoms[n] = &atom_NetSupported;
 
484
      names[n++] = (char *) "_NET_SUPPORTED";
 
485
 
 
486
      atoms[n] = &kde_xdnd_drop;
 
487
      names[n++] = (char *) "XdndDrop";
 
488
 
 
489
      XInternAtoms( QX11Info::display(), names, n, false, atoms_return );
 
490
 
 
491
      for (int i = 0; i < n; i++ )
 
492
          *atoms[i] = atoms_return[i];
 
493
  }
 
494
#endif
 
495
 
 
496
 
 
497
  // sanity checking, to make sure we've connected
 
498
  extern void qDBusBindToApplication();
 
499
  qDBusBindToApplication();
 
500
  QDBusConnectionInterface *bus = 0;
 
501
  if (!QDBusConnection::sessionBus().isConnected() || !(bus = QDBusConnection::sessionBus().interface())) {
 
502
      kFatal(101) << "Session bus not found" << endl;
 
503
      ::exit(125);
 
504
  }
 
505
 
 
506
  extern bool s_kuniqueapplication_startCalled;
 
507
  if ( !s_kuniqueapplication_startCalled ) // don't register again if KUniqueApplication did so already
 
508
  {
 
509
      QStringList parts = organizationDomain().split(QLatin1Char('.'), QString::SkipEmptyParts);
 
510
      QString reversedDomain;
 
511
      if (parts.isEmpty())
 
512
          reversedDomain = QLatin1String("local.");
 
513
      else
 
514
          foreach (const QString& s, parts)
 
515
          {
 
516
              reversedDomain.prepend(QLatin1Char('.'));
 
517
              reversedDomain.prepend(s);
 
518
          }
 
519
      const QString pidSuffix = QString::number( getpid() ).prepend( QLatin1String("-") );
 
520
      const QString serviceName = reversedDomain + applicationName() + pidSuffix;
 
521
      if ( bus->registerService(serviceName) == QDBusConnectionInterface::ServiceNotRegistered ) {
 
522
          kError(101) << "Couldn't register name '" << serviceName << "' with DBUS - another process owns it already!" << endl;
 
523
          ::exit(126);
 
524
      }
 
525
  }
 
526
  QDBusConnection::sessionBus().registerObject(QLatin1String("/MainApplication"), this,
 
527
                                               QDBusConnection::ExportScriptableSlots |
 
528
                                               QDBusConnection::ExportScriptableProperties |
 
529
                                               QDBusConnection::ExportAdaptors);
 
530
 
 
531
  // Trigger creation of locale.
 
532
  (void) KGlobal::locale();
 
533
 
 
534
  KSharedConfig::Ptr config = d->componentData.config();
 
535
  QByteArray readOnly = getenv("KDE_HOME_READONLY");
 
536
  if (readOnly.isEmpty() && applicationName() != QLatin1String("kdialog"))
 
537
  {
 
538
    if (KAuthorized::authorize(QLatin1String("warn_unwritable_config")))
 
539
       config->checkConfigFilesWritable(true);
 
540
  }
 
541
 
 
542
  if (type() == GuiClient)
 
543
  {
 
544
#ifdef Q_WS_X11
 
545
    // this is important since we fork() to launch the help (Matthias)
 
546
    fcntl(ConnectionNumber(QX11Info::display()), F_SETFD, FD_CLOEXEC);
 
547
    // set up the fancy (=robust and error ignoring ) KDE xio error handlers (Matthias)
 
548
    d->oldXErrorHandler = XSetErrorHandler( kde_x_errhandler );
 
549
    d->oldXIOErrorHandler = XSetIOErrorHandler( kde_xio_errhandler );
 
550
#endif
 
551
 
 
552
    // Trigger initial settings
 
553
    KGlobalSettings::self();
 
554
 
 
555
    d->checkAccelerators = new KCheckAccelerators( this );
 
556
 
 
557
    connect(KToolInvocation::self(), SIGNAL(kapplication_hook(QStringList&, QByteArray&)),
 
558
            this, SLOT(slot_KToolInvication_hook(QStringList&,QByteArray&)));
 
559
  }
 
560
 
 
561
#ifdef Q_WS_MAC
 
562
  if (type() == GuiClient) {
 
563
      QSystemTrayIcon *trayIcon;
 
564
      QPixmap pixmap = KIconLoader::global()->loadIcon( KCmdLineArgs::appName(),
 
565
              K3Icon::NoGroup, K3Icon::SizeEnormous, K3Icon::DefaultState, 0L, false );
 
566
      if (!pixmap.isNull() && QSystemTrayIcon::isSystemTrayAvailable())
 
567
      {
 
568
          trayIcon = new QSystemTrayIcon(this);
 
569
          trayIcon->setIcon(QIcon(pixmap));
 
570
          /* it's counter-intuitive, but once you do setIcon it's already set the
 
571
             dock icon... ->show actually shows an icon in the menu bar too  :P */
 
572
          // trayIcon->show();
 
573
      }
 
574
  }
 
575
#endif
 
576
 
 
577
 
 
578
  // save and restore the RTL setting, as installTranslator calls qt_detectRTLLanguage,
 
579
  // which makes it impossible to use the -reverse cmdline switch with KDE apps
 
580
  // FIXME is this still needed? it looks like QApplication takes care of this
 
581
  bool rtl = isRightToLeft();
 
582
  installTranslator(new KDETranslator(this));
 
583
  setLayoutDirection( rtl ? Qt::RightToLeft:Qt::LeftToRight);
 
584
  if (i18nc( "Dear Translator! Translate this string to the string 'LTR' in "
 
585
         "left-to-right languages (as English) or to 'RTL' in right-to-left "
 
586
         "languages (such as Hebrew and Arabic) to get proper widget layout.",
 
587
         "LTR" ) == QLatin1String("RTL"))
 
588
      rtl = !rtl;
 
589
  setLayoutDirection( rtl ? Qt::RightToLeft:Qt::LeftToRight);
 
590
 
 
591
  pSessionConfig = 0L;
 
592
  bSessionManagement = true;
 
593
 
 
594
#ifdef Q_WS_WIN
 
595
  KApplication_init_windows();
 
596
#endif
 
597
}
 
598
 
 
599
KConfig* KApplication::sessionConfig()
 
600
{
 
601
    if (!pSessionConfig) // create an instance specific config object
 
602
        pSessionConfig = new KConfig( sessionConfigName(), false, false);
 
603
    return pSessionConfig;
 
604
}
 
605
 
 
606
void KApplication::reparseConfiguration()
 
607
{
 
608
    KGlobal::config()->reparseConfiguration();
 
609
}
 
610
 
 
611
void KApplication::quit()
 
612
{
 
613
    QApplication::quit();
 
614
}
 
615
 
 
616
void KApplication::disableSessionManagement() {
 
617
  bSessionManagement = false;
 
618
}
 
619
 
 
620
void KApplication::enableSessionManagement() {
 
621
  bSessionManagement = true;
 
622
#ifdef Q_WS_X11
 
623
  // Session management support in Qt/KDE is awfully broken.
 
624
  // If konqueror disables session management right after its startup,
 
625
  // and enables it later (preloading stuff), it won't be properly
 
626
  // saved on session shutdown.
 
627
  // I'm not actually sure why it doesn't work, but saveState()
 
628
  // doesn't seem to be called on session shutdown, possibly
 
629
  // because disabling session management after konqueror startup
 
630
  // disabled it somehow. Forcing saveState() here for this application
 
631
  // seems to fix it.
 
632
  if( mySmcConnection ) {
 
633
        SmcRequestSaveYourself( mySmcConnection, SmSaveLocal, False,
 
634
                                SmInteractStyleAny,
 
635
                                False, False );
 
636
 
 
637
        // flush the request
 
638
        IceFlush(SmcGetIceConnection(mySmcConnection));
 
639
  }
 
640
#endif
 
641
}
 
642
 
 
643
void KApplication::commitData( QSessionManager& sm )
 
644
{
 
645
    d->session_save = true;
 
646
    bool canceled = false;
 
647
 
 
648
    foreach (KSessionManager *it, KSessionManager::sessionClients()) {
 
649
        if ( ( canceled = !it->commitData( sm ) ) )
 
650
            break;
 
651
    }
 
652
 
 
653
    if ( canceled )
 
654
        sm.cancel();
 
655
 
 
656
    if ( sm.allowsInteraction() ) {
 
657
        QWidgetList donelist, todolist;
 
658
        QWidget* w;
 
659
 
 
660
commitDataRestart:
 
661
        todolist = QApplication::topLevelWidgets();
 
662
 
 
663
        for ( int i = 0; i < todolist.size(); ++i ) {
 
664
            w = todolist.at( i );
 
665
            if( !w )
 
666
                break;
 
667
 
 
668
            if ( donelist.contains( w ) )
 
669
                continue;
 
670
 
 
671
            if ( !w->isHidden() && !w->inherits( "KMainWindow" ) ) {
 
672
                QCloseEvent e;
 
673
                sendEvent( w, &e );
 
674
                if ( !e.isAccepted() )
 
675
                    break; //canceled
 
676
 
 
677
                donelist.append( w );
 
678
 
 
679
                //grab the new list that was just modified by our closeevent
 
680
                goto commitDataRestart;
 
681
            }
 
682
        }
 
683
    }
 
684
 
 
685
    if ( !bSessionManagement )
 
686
        sm.setRestartHint( QSessionManager::RestartNever );
 
687
    else
 
688
        sm.setRestartHint( QSessionManager::RestartIfRunning );
 
689
    d->session_save = false;
 
690
}
 
691
 
 
692
void KApplication::saveState( QSessionManager& sm )
 
693
{
 
694
    d->session_save = true;
 
695
#ifdef Q_WS_X11
 
696
    static bool firstTime = true;
 
697
    mySmcConnection = (SmcConn) sm.handle();
 
698
 
 
699
    if ( !bSessionManagement ) {
 
700
        sm.setRestartHint( QSessionManager::RestartNever );
 
701
        d->session_save = false;
 
702
        return;
 
703
    }
 
704
    else
 
705
        sm.setRestartHint( QSessionManager::RestartIfRunning );
 
706
 
 
707
    if ( firstTime ) {
 
708
        firstTime = false;
 
709
        d->session_save = false;
 
710
        return; // no need to save the state.
 
711
    }
 
712
 
 
713
    // remove former session config if still existing, we want a new
 
714
    // and fresh one. Note that we do not delete the config file here,
 
715
    // this is done by the session manager when it executes the
 
716
    // discard commands. In fact it would be harmful to remove the
 
717
    // file here, as the session might be stored under a different
 
718
    // name, meaning the user still might need it eventually.
 
719
    if ( pSessionConfig ) {
 
720
        delete pSessionConfig;
 
721
        pSessionConfig = 0;
 
722
    }
 
723
 
 
724
    // tell the session manager about our new lifecycle
 
725
    QStringList restartCommand = sm.restartCommand();
 
726
 
 
727
    QByteArray multiHead = getenv("KDE_MULTIHEAD");
 
728
    if (multiHead.toLower() == "true") {
 
729
        // if multihead is enabled, we save our -display argument so that
 
730
        // we are restored onto the correct head... one problem with this
 
731
        // is that the display is hard coded, which means we cannot restore
 
732
        // to a different display (ie. if we are in a university lab and try,
 
733
        // try to restore a multihead session, our apps could be started on
 
734
        // someone else's display instead of our own)
 
735
        QByteArray displayname = getenv("DISPLAY");
 
736
        if (! displayname.isNull()) {
 
737
            // only store the command if we actually have a DISPLAY
 
738
            // environment variable
 
739
            restartCommand.append(QLatin1String("-display"));
 
740
            restartCommand.append(QLatin1String(displayname));
 
741
        }
 
742
        sm.setRestartCommand( restartCommand );
 
743
    }
 
744
 
 
745
 
 
746
    // finally: do session management
 
747
    emit saveYourself(); // for compatibility
 
748
    bool canceled = false;
 
749
    foreach(KSessionManager* it, KSessionManager::sessionClients()) {
 
750
      if(canceled) break;
 
751
      canceled = !it->saveState( sm );
 
752
    }
 
753
 
 
754
    // if we created a new session config object, register a proper discard command
 
755
    if ( pSessionConfig ) {
 
756
        pSessionConfig->sync();
 
757
        QStringList discard;
 
758
        discard  << QLatin1String("rm") << KStandardDirs::locateLocal("config", sessionConfigName());
 
759
        sm.setDiscardCommand( discard );
 
760
    } else {
 
761
        sm.setDiscardCommand( QStringList( QLatin1String("") ) );
 
762
    }
 
763
 
 
764
    if ( canceled )
 
765
        sm.cancel();
 
766
#else
 
767
    // FIXME(E): Implement for Qt Embedded
 
768
#endif
 
769
    d->session_save = false;
 
770
}
 
771
 
 
772
bool KApplication::sessionSaving() const
 
773
{
 
774
    return d->session_save;
 
775
}
 
776
 
 
777
void KApplication::parseCommandLine( )
 
778
{
 
779
    KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
 
780
 
 
781
    if ( type() != Tty ) {
 
782
        if (args && args->isSet("icon"))
 
783
        {
 
784
            QPixmap largeIcon = DesktopIcon(QFile::decodeName(args->getOption("icon")));
 
785
            QIcon icon = windowIcon();
 
786
            icon.addPixmap(largeIcon, QIcon::Normal, QIcon::On);
 
787
            setWindowIcon(icon);
 
788
        }
 
789
        else {
 
790
            QIcon icon = windowIcon();
 
791
            QPixmap largeIcon = DesktopIcon(QFile::decodeName(d->componentData.componentName()));
 
792
            icon.addPixmap(largeIcon, QIcon::Normal, QIcon::On);
 
793
            setWindowIcon(icon);
 
794
        }
 
795
    }
 
796
 
 
797
    if (!args)
 
798
        return;
 
799
 
 
800
    if (args->isSet("config"))
 
801
    {
 
802
        QString config = QString::fromLocal8Bit(args->getOption("config"));
 
803
        d->componentData.setConfigName(config);
 
804
    }
 
805
 
 
806
    if (args->isSet("style"))
 
807
    {
 
808
        extern KDEUI_EXPORT QString kde_overrideStyle; // see KGlobalSettings. Should we have a static setter?
 
809
        QStringList styles = QStyleFactory::keys();
 
810
        QString reqStyle(QLatin1String(args->getOption("style").toLower()));
 
811
 
 
812
        for (QStringList::ConstIterator it = styles.begin(); it != styles.end(); ++it)
 
813
            if ((*it).toLower() == reqStyle) {
 
814
                kde_overrideStyle = *it;
 
815
                break;
 
816
            }
 
817
 
 
818
        if (kde_overrideStyle.isEmpty())
 
819
            fprintf(stderr, "%s", i18n("The style %1 was not found\n", reqStyle).toLocal8Bit().data());
 
820
    }
 
821
 
 
822
    bool nocrashhandler = (getenv("KDE_DEBUG") != NULL);
 
823
    if (!nocrashhandler && args->isSet("crashhandler"))
 
824
    {
 
825
        // set default crash handler / set emergency save function to nothing
 
826
        KCrash::setCrashHandler(KCrash::defaultCrashHandler);
 
827
        KCrash::setEmergencySaveFunction(NULL);
 
828
 
 
829
        KCrash::setApplicationName(QLatin1String(args->appName()));
 
830
    }
 
831
 
 
832
#ifdef Q_WS_X11
 
833
    if ( args->isSet( "waitforwm" ) ) {
 
834
        Atom type;
 
835
        (void) desktop(); // trigger desktop creation, we need PropertyNotify events for the root window
 
836
        int format;
 
837
        unsigned long length, after;
 
838
        unsigned char *data;
 
839
        while ( XGetWindowProperty( QX11Info::display(), QX11Info::appRootWindow(), atom_NetSupported,
 
840
                                    0, 1, false, AnyPropertyType, &type, &format,
 
841
                                    &length, &after, &data ) != Success || !length ) {
 
842
            if ( data )
 
843
                XFree( data );
 
844
            XEvent event;
 
845
            XWindowEvent( QX11Info::display(), QX11Info::appRootWindow(), PropertyChangeMask, &event );
 
846
        }
 
847
        if ( data )
 
848
            XFree( data );
 
849
    }
 
850
#else
 
851
    // FIXME(E): Implement for Qt Embedded
 
852
#endif
 
853
 
 
854
    if (args->isSet("smkey"))
 
855
    {
 
856
        d->sessionKey = QLatin1String(args->getOption("smkey"));
 
857
    }
 
858
 
 
859
}
 
860
 
 
861
extern void kDebugCleanup();
 
862
 
 
863
KApplication::~KApplication()
 
864
{
 
865
  // First call the static deleters and then call KLibLoader::cleanup()
 
866
  // The static deleters may delete libraries for which they need KLibLoader.
 
867
  // KLibLoader will take care of the remaining ones.
 
868
  KGlobal::deleteStaticDeleters();
 
869
 
 
870
#ifdef Q_WS_X11
 
871
  if ( d->oldXErrorHandler != NULL )
 
872
      XSetErrorHandler( d->oldXErrorHandler );
 
873
  if ( d->oldXIOErrorHandler != NULL )
 
874
      XSetIOErrorHandler( d->oldXIOErrorHandler );
 
875
  if ( d->oldIceIOErrorHandler != NULL )
 
876
      IceSetIOErrorHandler( d->oldIceIOErrorHandler );
 
877
#endif
 
878
 
 
879
  delete d;
 
880
  KApp = 0;
 
881
 
 
882
#ifdef Q_WS_X11
 
883
  mySmcConnection = 0;
 
884
#else
 
885
  // FIXME(E): Implement for Qt Embedded
 
886
#endif
 
887
}
 
888
 
 
889
 
 
890
#ifdef Q_WS_X11
 
891
class KAppX11HackWidget: public QWidget
 
892
{
 
893
public:
 
894
    bool publicx11Event( XEvent * e) { return x11Event( e ); }
 
895
};
 
896
#endif
 
897
 
 
898
 
 
899
 
 
900
#ifdef Q_WS_X11
 
901
bool KApplication::x11EventFilter( XEvent *_event )
 
902
{
 
903
    switch ( _event->type ) {
 
904
        case ClientMessage:
 
905
        {
 
906
#if KDE_IS_VERSION( 3, 90, 90 )
 
907
#warning This should be already in Qt, check.
 
908
#endif
 
909
        // Workaround for focus stealing prevention not working when dragging e.g. text from KWrite
 
910
        // to KDesktop -> the dialog asking for filename doesn't get activated. This is because
 
911
        // Qt-3.2.x doesn't have concept of qt_x_user_time at all, and Qt-3.3.0b1 passes the timestamp
 
912
        // in the XdndDrop message in incorrect field (and doesn't update qt_x_user_time either).
 
913
        // Patch already sent, future Qt version should have this fixed.
 
914
            if( _event->xclient.message_type == kde_xdnd_drop )
 
915
                { // if the message is XdndDrop
 
916
                if( _event->xclient.data.l[ 1 ] == 1 << 24     // and it's broken the way it's in Qt-3.2.x
 
917
                    && _event->xclient.data.l[ 2 ] == 0
 
918
                    && _event->xclient.data.l[ 4 ] == 0
 
919
                    && _event->xclient.data.l[ 3 ] != 0 )
 
920
                    {
 
921
                    if( QX11Info::appUserTime() == 0
 
922
                        || NET::timestampCompare( _event->xclient.data.l[ 3 ], QX11Info::appUserTime() ) > 0 )
 
923
                        { // and the timestamp looks reasonable
 
924
                        QX11Info::setAppUserTime(_event->xclient.data.l[ 3 ]); // update our qt_x_user_time from it
 
925
                        }
 
926
                    }
 
927
                else // normal DND, only needed until Qt updates qt_x_user_time from XdndDrop
 
928
                    {
 
929
                    if( QX11Info::appUserTime() == 0
 
930
                        || NET::timestampCompare( _event->xclient.data.l[ 2 ], QX11Info::appUserTime() ) > 0 )
 
931
                        { // the timestamp looks reasonable
 
932
                        QX11Info::setAppUserTime(_event->xclient.data.l[ 2 ]); // update our qt_x_user_time from it
 
933
                        }
 
934
                    }
 
935
                }
 
936
        }
 
937
        default: break;
 
938
    }
 
939
 
 
940
    if (x11Filter) {
 
941
        foreach (const QWidget *w, *x11Filter) {
 
942
            if (((KAppX11HackWidget*) w)->publicx11Event(_event))
 
943
                return true;
 
944
        }
 
945
    }
 
946
 
 
947
    return false;
 
948
}
 
949
#endif // Q_WS_X11
 
950
 
 
951
void KApplication::updateUserTimestamp( int time )
 
952
{
 
953
#if defined Q_WS_X11
 
954
    if( time == 0 )
 
955
    { // get current X timestamp
 
956
        Window w = XCreateSimpleWindow( QX11Info::display(), QX11Info::appRootWindow(), 0, 0, 1, 1, 0, 0, 0 );
 
957
        XSelectInput( QX11Info::display(), w, PropertyChangeMask );
 
958
        unsigned char data[ 1 ];
 
959
        XChangeProperty( QX11Info::display(), w, XA_ATOM, XA_ATOM, 8, PropModeAppend, data, 1 );
 
960
        XEvent ev;
 
961
        XWindowEvent( QX11Info::display(), w, PropertyChangeMask, &ev );
 
962
        time = ev.xproperty.time;
 
963
        XDestroyWindow( QX11Info::display(), w );
 
964
    }
 
965
    if( QX11Info::appUserTime() == 0
 
966
        || NET::timestampCompare( time, QX11Info::appUserTime()) > 0 ) // time > appUserTime
 
967
        QX11Info::setAppUserTime(time);
 
968
#endif
 
969
}
 
970
 
 
971
unsigned long KApplication::userTimestamp() const
 
972
{
 
973
#if defined Q_WS_X11
 
974
    return QX11Info::appUserTime();
 
975
#else
 
976
    return 0;
 
977
#endif
 
978
}
 
979
 
 
980
void KApplication::updateRemoteUserTimestamp( const QString& service, int time )
 
981
{
 
982
#if defined Q_WS_X11
 
983
    if( time == 0 )
 
984
        time = QX11Info::appUserTime();
 
985
    QDBusInterface(service, QLatin1String("/MainApplication"),
 
986
            QString(QLatin1String("org.kde.KApplication")))
 
987
        .call(QLatin1String("updateUserTimestamp"), time);
 
988
#endif
 
989
}
 
990
 
 
991
 
 
992
QString KApplication::tempSaveName( const QString& pFilename )
 
993
{
 
994
  QString aFilename;
 
995
 
 
996
  if( QDir::isRelativePath(pFilename) )
 
997
    {
 
998
      kWarning(101) << "Relative filename passed to KApplication::tempSaveName" << endl;
 
999
      aFilename = QFileInfo( QDir( QLatin1String(".") ), pFilename ).absoluteFilePath();
 
1000
    }
 
1001
  else
 
1002
    aFilename = pFilename;
 
1003
 
 
1004
  QDir aAutosaveDir( QDir::homePath() + QLatin1String("/autosave/") );
 
1005
  if( !aAutosaveDir.exists() )
 
1006
    {
 
1007
      if( !aAutosaveDir.mkdir( aAutosaveDir.absolutePath() ) )
 
1008
        {
 
1009
          // Last chance: use temp dir
 
1010
          aAutosaveDir.setPath( KGlobal::dirs()->saveLocation("tmp") );
 
1011
        }
 
1012
    }
 
1013
 
 
1014
  aFilename.replace( QLatin1String("/"), QLatin1String("\\!") )
 
1015
    .prepend( QLatin1Char('#') )
 
1016
    .append( QLatin1Char('#') )
 
1017
    .prepend( QLatin1Char('/') ).prepend( aAutosaveDir.absolutePath() );
 
1018
 
 
1019
  return aFilename;
 
1020
}
 
1021
 
 
1022
 
 
1023
QString KApplication::checkRecoverFile( const QString& pFilename,
 
1024
        bool& bRecover )
 
1025
{
 
1026
  QString aFilename;
 
1027
 
 
1028
  if( QDir::isRelativePath(pFilename) )
 
1029
    {
 
1030
      kWarning(101) << "Relative filename passed to KApplication::tempSaveName" << endl;
 
1031
      aFilename = QFileInfo( QDir( QLatin1String(".") ), pFilename ).absoluteFilePath();
 
1032
    }
 
1033
  else
 
1034
    aFilename = pFilename;
 
1035
 
 
1036
  QDir aAutosaveDir( QDir::homePath() + QLatin1String("/autosave/") );
 
1037
  if( !aAutosaveDir.exists() )
 
1038
    {
 
1039
      if( !aAutosaveDir.mkdir( aAutosaveDir.absolutePath() ) )
 
1040
        {
 
1041
          // Last chance: use temp dir
 
1042
          aAutosaveDir.setPath( KGlobal::dirs()->saveLocation("tmp") );
 
1043
        }
 
1044
    }
 
1045
 
 
1046
  aFilename.replace( QLatin1String("/"), QLatin1String("\\!") )
 
1047
      .prepend( QLatin1Char('#') )
 
1048
      .append( QLatin1Char('#') )
 
1049
      .prepend( QLatin1Char('/') )
 
1050
      .prepend( aAutosaveDir.absolutePath() );
 
1051
 
 
1052
  if( QFile( aFilename ).exists() )
 
1053
    {
 
1054
      bRecover = true;
 
1055
      return aFilename;
 
1056
    }
 
1057
  else
 
1058
    {
 
1059
      bRecover = false;
 
1060
      return pFilename;
 
1061
    }
 
1062
}
 
1063
 
 
1064
 
 
1065
void KApplication::setTopWidget( QWidget *topWidget )
 
1066
{
 
1067
    if( !topWidget )
 
1068
      return;
 
1069
 
 
1070
    // set the specified caption
 
1071
    if ( !topWidget->inherits("KMainWindow") ) { // KMainWindow does this already for us
 
1072
        topWidget->setWindowTitle(KGlobal::caption());
 
1073
    }
 
1074
 
 
1075
#if defined Q_WS_X11
 
1076
//#ifdef Q_WS_X11 // FIXME(E): Implement for Qt/Embedded
 
1077
    // set the app startup notification window property
 
1078
    KStartupInfo::setWindowStartupId( topWidget->winId(), startupId());
 
1079
#endif
 
1080
}
 
1081
 
 
1082
QByteArray KApplication::startupId() const
 
1083
{
 
1084
    return d->startup_id;
 
1085
}
 
1086
 
 
1087
void KApplication::setStartupId( const QByteArray& startup_id )
 
1088
{
 
1089
    if( startup_id == d->startup_id )
 
1090
        return;
 
1091
#if defined Q_WS_X11
 
1092
    KStartupInfo::handleAutoAppStartedSending(); // finish old startup notification if needed
 
1093
#endif
 
1094
    if( startup_id.isEmpty())
 
1095
        d->startup_id = "0";
 
1096
    else
 
1097
        {
 
1098
        d->startup_id = startup_id;
 
1099
#if defined Q_WS_X11
 
1100
        KStartupInfoId id;
 
1101
        id.initId( startup_id );
 
1102
        long timestamp = id.timestamp();
 
1103
        if( timestamp != 0 )
 
1104
            updateUserTimestamp( timestamp );
 
1105
#endif
 
1106
        }
 
1107
}
 
1108
 
 
1109
// read the startup notification env variable, save it and unset it in order
 
1110
// not to propagate it to processes started from this app
 
1111
void KApplication::read_app_startup_id()
 
1112
{
 
1113
#if defined Q_WS_X11
 
1114
    KStartupInfoId id = KStartupInfo::currentStartupIdEnv();
 
1115
    KStartupInfo::resetStartupEnv();
 
1116
    d->startup_id = id.id();
 
1117
#endif
 
1118
}
 
1119
 
 
1120
// Hook called by KToolInvocation
 
1121
void KApplication::slot_KToolInvication_hook(QStringList& envs,QByteArray& startup_id)
 
1122
{
 
1123
#ifdef Q_WS_X11
 
1124
    if (QX11Info::display()) {
 
1125
        QByteArray dpystring(XDisplayString(QX11Info::display()));
 
1126
        envs << QString::fromLatin1( QByteArray("DISPLAY=") + dpystring );
 
1127
    } else if( getenv( "DISPLAY" )) {
 
1128
        QByteArray dpystring( getenv( "DISPLAY" ));
 
1129
        envs << QString::fromLatin1( QByteArray("DISPLAY=") + dpystring );
 
1130
    }
 
1131
 
 
1132
    if(startup_id.isEmpty())
 
1133
        startup_id = KStartupInfo::createNewStartupId();
 
1134
#else
 
1135
    Q_UNUSED(envs);
 
1136
    Q_UNUSED(startup_id);
 
1137
#endif
 
1138
}
 
1139
 
 
1140
void KApplication::setSynchronizeClipboard(bool synchronize)
 
1141
{
 
1142
    KClipboardSynchronizer::self()->setSynchronizing(synchronize);
 
1143
    KClipboardSynchronizer::self()->setReverseSynchronizing(synchronize);
 
1144
}
 
1145
 
 
1146
#include "kapplication.moc"
 
1147