• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDEUI

kapplication.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002     Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
00003     Copyright (C) 1998, 1999, 2000 KDE Team
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Library General Public
00007     License as published by the Free Software Foundation; either
00008     version 2 of the License, or (at your option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to
00017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018     Boston, MA 02110-1301, USA.
00019         */
00020 
00021 #undef QT_NO_TRANSLATION
00022 #include "kapplication.h"
00023 #define QT_NO_TRANSLATION
00024 
00025 #include <config.h>
00026 
00027 #undef QT_NO_TRANSLATION
00028 #include <QtCore/QTranslator>
00029 #define QT_NO_TRANSLATION
00030 #include <QtCore/QDir>
00031 #include <QtCore/QFile>
00032 #include <QtGui/QSessionManager>
00033 #include <QtGui/QStyleFactory>
00034 #include <QtCore/QTimer>
00035 #include <QtGui/QWidget>
00036 #include <QtCore/QList>
00037 #include <QtDBus/QtDBus>
00038 #include <QtCore/QMetaType>
00039 
00040 #include "kauthorized.h"
00041 #include "kaboutdata.h"
00042 #include "kcheckaccelerators.h"
00043 #include "kcrash.h"
00044 #include "kconfig.h"
00045 #include "kcmdlineargs.h"
00046 #include "kclipboard.h"
00047 #include "kglobalsettings.h"
00048 #include "kdebug.h"
00049 #include "kglobal.h"
00050 #include "kicon.h"
00051 #include "klocale.h"
00052 #include "ksessionmanager.h"
00053 #include "kstandarddirs.h"
00054 #include "kstandardshortcut.h"
00055 #include "ktoolinvocation.h"
00056 #include "kgesturemap.h"
00057 #include "kurl.h"
00058 #include "kmessage.h"
00059 #include "kmessageboxmessagehandler.h"
00060 
00061 #if defined Q_WS_X11
00062 #include <QtGui/qx11info_x11.h>
00063 #include <kstartupinfo.h>
00064 #endif
00065 
00066 #include <sys/types.h>
00067 #ifdef HAVE_SYS_STAT_H
00068 #include <sys/stat.h>
00069 #endif
00070 #include <sys/wait.h>
00071 
00072 #ifndef Q_WS_WIN
00073 #include "kwindowsystem.h"
00074 #endif
00075 
00076 #include <fcntl.h>
00077 #include <stdlib.h> // srand(), rand()
00078 #include <unistd.h>
00079 #if defined Q_WS_X11
00080 //#ifndef Q_WS_QWS //FIXME(E): NetWM should talk to QWS...
00081 #include <netwm.h>
00082 #endif
00083 
00084 #ifdef HAVE_PATHS_H
00085 #include <paths.h>
00086 #endif
00087 
00088 #ifdef Q_WS_X11
00089 #include <X11/Xlib.h>
00090 #include <X11/Xutil.h>
00091 #include <X11/Xatom.h>
00092 #include <X11/SM/SMlib.h>
00093 #include <fixx11h.h>
00094 
00095 #include <QX11Info>
00096 #endif
00097 
00098 #ifdef Q_WS_MACX
00099 // ick
00100 #undef Status
00101 #include <Carbon/Carbon.h>
00102 #include <QImage>
00103 #include <ksystemtrayicon.h>
00104 #include <kkernel_mac.h>
00105 #endif
00106 
00107 #ifdef Q_OS_UNIX
00108 #include <signal.h>
00109 #endif
00110 
00111 #include <QtGui/QActionEvent>
00112 #include <kcomponentdata.h>
00113 
00114 KApplication* KApplication::KApp = 0L;
00115 bool KApplication::loadedByKdeinit = false;
00116 
00117 #ifdef Q_WS_X11
00118 static Atom atom_DesktopWindow;
00119 static Atom atom_NetSupported;
00120 static Atom kde_xdnd_drop;
00121 static QByteArray* startup_id_tmp;
00122 #endif
00123 
00124 template class QList<KSessionManager*>;
00125 
00126 #ifdef Q_WS_X11
00127 extern "C" {
00128 static int kde_xio_errhandler( Display * dpy )
00129 {
00130   return kapp->xioErrhandler( dpy );
00131 }
00132 
00133 static int kde_x_errhandler( Display *dpy, XErrorEvent *err )
00134 {
00135   return kapp->xErrhandler( dpy, err );
00136 }
00137 
00138 }
00139 #endif
00140 
00141 #ifdef Q_WS_WIN
00142 void KApplication_init_windows();
00143 #endif
00144 
00145 /*
00146   Private data to make keeping binary compatibility easier
00147  */
00148 class KApplicationPrivate
00149 {
00150 public:
00151   KApplicationPrivate(KApplication* q, const QByteArray &cName)
00152       : q(q),
00153       componentData(cName),
00154       checkAccelerators(0),
00155       startup_id("0"),
00156       app_started_timer(0),
00157       session_save(false)
00158 #ifdef Q_WS_X11
00159       , oldIceIOErrorHandler(0)
00160       , oldXErrorHandler(0)
00161       , oldXIOErrorHandler(0)
00162 #endif
00163       ,pSessionConfig( 0 )
00164       ,bSessionManagement( true )
00165   {
00166   }
00167 
00168   KApplicationPrivate(KApplication* q, const KComponentData &cData)
00169       : q(q),
00170       componentData(cData),
00171       checkAccelerators(0),
00172       startup_id("0"),
00173       app_started_timer(0),
00174       session_save(false)
00175 #ifdef Q_WS_X11
00176       , oldIceIOErrorHandler(0)
00177       , oldXErrorHandler(0)
00178       , oldXIOErrorHandler(0)
00179 #endif
00180       ,pSessionConfig( 0 )
00181       ,bSessionManagement( true )
00182   {
00183   }
00184 
00185   KApplicationPrivate(KApplication *q)
00186       : q(q),
00187       componentData(KCmdLineArgs::aboutData()),
00188       checkAccelerators(0),
00189       startup_id( "0" ),
00190       app_started_timer( 0 ),
00191       session_save( false )
00192 #ifdef Q_WS_X11
00193       ,oldIceIOErrorHandler( 0 )
00194       ,oldXErrorHandler( 0 )
00195       ,oldXIOErrorHandler( 0 )
00196 #endif
00197       ,pSessionConfig( 0 )
00198       ,bSessionManagement( true )
00199   {
00200   }
00201 
00202   ~KApplicationPrivate()
00203   {
00204   }
00205 
00206 #ifndef KDE3_SUPPORT
00207   KConfig *config() { return KGlobal::config().data(); }
00208 #endif
00209 
00210   void _k_x11FilterDestroyed();
00211   void _k_checkAppStartedSlot();
00212   void _k_slot_KToolInvocation_hook(QStringList&, QByteArray&);
00213 
00214   QString sessionConfigName() const;
00215   void init(bool GUIenabled=true);
00216   void parseCommandLine( ); // Handle KDE arguments (Using KCmdLineArgs)
00217   static void preqapplicationhack();
00218   static void preread_app_startup_id();
00219   void read_app_startup_id();
00220 
00221   KApplication *q;
00222   KComponentData componentData;
00223   KCheckAccelerators* checkAccelerators;
00224   QByteArray startup_id;
00225   QTimer* app_started_timer;
00226   bool session_save;
00227 
00228 #ifdef Q_WS_X11
00229   IceIOErrorHandler oldIceIOErrorHandler;
00230   int (*oldXErrorHandler)(Display*,XErrorEvent*);
00231   int (*oldXIOErrorHandler)(Display*);
00232 #endif
00233 
00234   QString sessionKey;
00235   QString pSessionConfigFile;
00236 
00237   KConfig* pSessionConfig; //instance specific application config object
00238   bool bSessionManagement;
00239 };
00240 
00241 
00242 static QList<const QWidget*> *x11Filter = 0;
00243 
00251 static void installSigpipeHandler()
00252 {
00253 #ifdef Q_OS_UNIX
00254     struct sigaction act;
00255     act.sa_handler = SIG_IGN;
00256     sigemptyset( &act.sa_mask );
00257     act.sa_flags = 0;
00258     sigaction( SIGPIPE, &act, 0 );
00259 #endif
00260 }
00261 
00262 void KApplication::installX11EventFilter( QWidget* filter )
00263 {
00264     if ( !filter )
00265         return;
00266     if (!x11Filter)
00267         x11Filter = new QList<const QWidget *>;
00268     connect ( filter, SIGNAL( destroyed() ), this, SLOT( _k_x11FilterDestroyed() ) );
00269     x11Filter->append( filter );
00270 }
00271 
00272 void KApplicationPrivate::_k_x11FilterDestroyed()
00273 {
00274     q->removeX11EventFilter( static_cast< const QWidget* >(q->sender()));
00275 }
00276 
00277 void KApplication::removeX11EventFilter( const QWidget* filter )
00278 {
00279     if ( !x11Filter || !filter )
00280         return;
00281     x11Filter->removeAll( filter );
00282     if ( x11Filter->isEmpty() ) {
00283         delete x11Filter;
00284         x11Filter = 0;
00285     }
00286 }
00287 
00288 bool KApplication::notify(QObject *receiver, QEvent *event)
00289 {
00290     QEvent::Type t = event->type();
00291     if( t == QEvent::Show && receiver->isWidgetType())
00292     {
00293         QWidget* w = static_cast< QWidget* >( receiver );
00294 #if defined Q_WS_X11
00295         if( w->isTopLevel() && !startupId().isEmpty()) // TODO better done using window group leader?
00296             KStartupInfo::setWindowStartupId( w->winId(), startupId());
00297 #endif
00298         if( w->isTopLevel() && !( w->windowFlags() & Qt::X11BypassWindowManagerHint ) && w->windowType() != Qt::Popup && !event->spontaneous())
00299         {
00300             if( d->app_started_timer == NULL )
00301             {
00302                 d->app_started_timer = new QTimer( this );
00303                 connect( d->app_started_timer, SIGNAL( timeout()), SLOT( _k_checkAppStartedSlot()));
00304             }
00305             if( !d->app_started_timer->isActive()) {
00306                 d->app_started_timer->setSingleShot( true );
00307                 d->app_started_timer->start( 0 );
00308             }
00309         }
00310     }
00311     return QApplication::notify(receiver, event);
00312 }
00313 
00314 void KApplicationPrivate::_k_checkAppStartedSlot()
00315 {
00316 #if defined Q_WS_X11
00317     KStartupInfo::handleAutoAppStartedSending();
00318 #endif
00319 }
00320 
00321 /*
00322   Auxiliary function to calculate a a session config name used for the
00323   instance specific config object.
00324   Syntax:  "session/<appname>_<sessionId>"
00325  */
00326 QString KApplicationPrivate::sessionConfigName() const
00327 {
00328 #ifdef QT_NO_SESSIONMANAGER
00329 #error QT_NO_SESSIONMANAGER was set, this will not compile. Reconfigure Qt with Session management support.
00330 #endif
00331     QString sessKey = q->sessionKey();
00332     if ( sessKey.isEmpty() && !sessionKey.isEmpty() )
00333         sessKey = sessionKey;
00334     return QString(QLatin1String("session/%1_%2_%3")).arg(q->applicationName()).arg(q->sessionId()).arg(sessKey);
00335 }
00336 
00337 #ifdef Q_WS_X11
00338 static SmcConn mySmcConnection = 0;
00339 #else
00340 // FIXME(E): Implement for Qt Embedded
00341 // Possibly "steal" XFree86's libSM?
00342 #endif
00343 
00344 KApplication::KApplication(bool GUIenabled)
00345     : QApplication((KApplicationPrivate::preqapplicationhack(),KCmdLineArgs::qtArgc()), KCmdLineArgs::qtArgv(), GUIenabled),
00346     d(new KApplicationPrivate(this))
00347 {
00348     d->read_app_startup_id();
00349     setApplicationName(d->componentData.componentName());
00350     setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
00351     installSigpipeHandler();
00352     d->init(GUIenabled);
00353 }
00354 
00355 #ifdef Q_WS_X11
00356 KApplication::KApplication(Display *dpy, Qt::HANDLE visual, Qt::HANDLE colormap)
00357     : QApplication((KApplicationPrivate::preqapplicationhack(),dpy), KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv(), visual, colormap),
00358     d(new KApplicationPrivate(this))
00359 {
00360     d->read_app_startup_id();
00361     setApplicationName(d->componentData.componentName());
00362     setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
00363     installSigpipeHandler();
00364     d->init();
00365 }
00366 
00367 KApplication::KApplication(Display *dpy, Qt::HANDLE visual, Qt::HANDLE colormap, const KComponentData &cData)
00368     : QApplication((KApplicationPrivate::preqapplicationhack(),dpy), KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv(), visual, colormap),
00369     d (new KApplicationPrivate(this, cData))
00370 {
00371     d->read_app_startup_id();
00372     setApplicationName(d->componentData.componentName());
00373     setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
00374     installSigpipeHandler();
00375     d->init();
00376 }
00377 #endif
00378 
00379 KApplication::KApplication(bool GUIenabled, const KComponentData &cData)
00380     : QApplication((KApplicationPrivate::preqapplicationhack(),KCmdLineArgs::qtArgc()), KCmdLineArgs::qtArgv(), GUIenabled),
00381     d (new KApplicationPrivate(this, cData))
00382 {
00383     d->read_app_startup_id();
00384     setApplicationName(d->componentData.componentName());
00385     setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
00386     installSigpipeHandler();
00387     d->init();
00388 }
00389 
00390 #ifdef Q_WS_X11
00391 KApplication::KApplication(Display *display, int& argc, char** argv, const QByteArray& rAppName,
00392         bool GUIenabled)
00393     : QApplication((KApplicationPrivate::preqapplicationhack(),display)),
00394     d(new KApplicationPrivate(this, rAppName))
00395 {
00396     Q_UNUSED(GUIenabled);
00397     d->read_app_startup_id();
00398     setApplicationName(QLatin1String(rAppName));
00399     installSigpipeHandler();
00400     KCmdLineArgs::initIgnore(argc, argv, rAppName.data());
00401     d->init();
00402 }
00403 #endif
00404 
00405 // this function is called in KApplication ctors while evaluating arguments to QApplication ctor,
00406 // i.e. before QApplication ctor is called
00407 void KApplicationPrivate::preqapplicationhack()
00408 {
00409     preread_app_startup_id();
00410 }
00411 
00412 int KApplication::xioErrhandler( Display* dpy )
00413 {
00414     if(kapp)
00415     {
00416 #ifdef Q_WS_X11
00417         d->oldXIOErrorHandler( dpy );
00418 #else
00419         Q_UNUSED(dpy);
00420 #endif
00421     }
00422     exit( 1 );
00423     return 0;
00424 }
00425 
00426 int KApplication::xErrhandler( Display* dpy, void* err_ )
00427 { // no idea how to make forward decl. for XErrorEvent
00428 #ifdef Q_WS_X11
00429     XErrorEvent* err = static_cast< XErrorEvent* >( err_ );
00430     if(kapp)
00431     {
00432         // add KDE specific stuff here
00433         d->oldXErrorHandler( dpy, err );
00434     }
00435     const QByteArray fatalXError = qgetenv("KDE_FATAL_X_ERROR");
00436     if (!fatalXError.isEmpty()) {
00437         abort();
00438     }
00439 #endif
00440     return 0;
00441 }
00442 
00443 void KApplication::iceIOErrorHandler( _IceConn *conn )
00444 {
00445     emit aboutToQuit();
00446 
00447 #ifdef Q_WS_X11
00448     if ( d->oldIceIOErrorHandler != NULL )
00449       (*d->oldIceIOErrorHandler)( conn );
00450 #endif
00451     exit( 1 );
00452 }
00453 
00454 class KDETranslator : public QTranslator
00455 {
00456 public:
00457   KDETranslator(QObject *parent) : QTranslator(parent)
00458   {
00459     setObjectName(QLatin1String("kdetranslator"));
00460   }
00461 
00462   virtual QString translate(const char* context,
00463                      const char *sourceText,
00464                      const char* message) const
00465   {
00466     return KGlobal::locale()->translateQt(context, sourceText, message);
00467   }
00468 };
00469 
00470 void KApplicationPrivate::init(bool GUIenabled)
00471 {
00472   if ((getuid() != geteuid()) ||
00473       (getgid() != getegid()))
00474   {
00475      fprintf(stderr, "The KDE libraries are not designed to run with suid privileges.\n");
00476      ::exit(127);
00477   }
00478 
00479 #ifdef Q_WS_MAC
00480   mac_initialize_dbus();
00481 #endif
00482 
00483   if ( q->type() == KApplication::GuiClient )
00484   {
00485     const QStringList plugins = KGlobal::dirs()->resourceDirs( "qtplugins" );
00486     QStringList::ConstIterator it = plugins.begin();
00487     while (it != plugins.end()) {
00488       q->addLibraryPath( *it );
00489       ++it;
00490     }
00491   }
00492 
00493   KApplication::KApp = q;
00494 
00495   parseCommandLine();
00496 
00497   if(GUIenabled)
00498     (void) KClipboardSynchronizer::self();
00499 
00500   extern KDECORE_EXPORT bool kde_kdebug_enable_dbus_interface;
00501   kde_kdebug_enable_dbus_interface = true;
00502 
00503   QApplication::setDesktopSettingsAware( false );
00504 
00505 #ifdef Q_WS_X11 //FIXME(E)
00506   // create all required atoms in _one_ roundtrip to the X server
00507   if ( q->type() == KApplication::GuiClient ) {
00508       const int max = 20;
00509       Atom* atoms[max];
00510       char* names[max];
00511       Atom atoms_return[max];
00512       int n = 0;
00513 
00514       atoms[n] = &atom_DesktopWindow;
00515       names[n++] = (char *) "KDE_DESKTOP_WINDOW";
00516 
00517       atoms[n] = &atom_NetSupported;
00518       names[n++] = (char *) "_NET_SUPPORTED";
00519 
00520       atoms[n] = &kde_xdnd_drop;
00521       names[n++] = (char *) "XdndDrop";
00522 
00523       XInternAtoms( QX11Info::display(), names, n, false, atoms_return );
00524 
00525       for (int i = 0; i < n; i++ )
00526         *atoms[i] = atoms_return[i];
00527   }
00528 #endif
00529 
00530 
00531   // sanity checking, to make sure we've connected
00532   extern void qDBusBindToApplication();
00533   qDBusBindToApplication();
00534   QDBusConnectionInterface *bus = 0;
00535   if (!QDBusConnection::sessionBus().isConnected() || !(bus = QDBusConnection::sessionBus().interface())) {
00536   }
00537 
00538   extern bool s_kuniqueapplication_startCalled;
00539   if ( bus && !s_kuniqueapplication_startCalled ) // don't register again if KUniqueApplication did so already
00540   {
00541       QStringList parts = q->organizationDomain().split(QLatin1Char('.'), QString::SkipEmptyParts);
00542       QString reversedDomain;
00543       if (parts.isEmpty())
00544           reversedDomain = QLatin1String("local.");
00545       else
00546           foreach (const QString& s, parts)
00547           {
00548               reversedDomain.prepend(QLatin1Char('.'));
00549               reversedDomain.prepend(s);
00550           }
00551       const QString pidSuffix = QString::number( getpid() ).prepend( QLatin1String("-") );
00552       const QString serviceName = reversedDomain + q->applicationName() + pidSuffix;
00553       if ( bus->registerService(serviceName) == QDBusConnectionInterface::ServiceNotRegistered ) {
00554           kError(101) << "Couldn't register name '" << serviceName << "' with DBUS - another process owns it already!" << endl;
00555           ::exit(126);
00556       }
00557   }
00558   QDBusConnection::sessionBus().registerObject(QLatin1String("/MainApplication"), q,
00559                                                QDBusConnection::ExportScriptableSlots |
00560                                                QDBusConnection::ExportScriptableProperties |
00561                                                QDBusConnection::ExportAdaptors);
00562 
00563   // Trigger creation of locale.
00564   (void) KGlobal::locale();
00565 
00566   KSharedConfig::Ptr config = componentData.config();
00567   QByteArray readOnly = qgetenv("KDE_HOME_READONLY");
00568   if (readOnly.isEmpty() && q->applicationName() != QLatin1String("kdialog"))
00569   {
00570     if (KAuthorized::authorize(QLatin1String("warn_unwritable_config")))
00571        config->isConfigWritable(true);
00572   }
00573 
00574   if (q->type() == KApplication::GuiClient)
00575   {
00576 #ifdef Q_WS_X11
00577     // this is important since we fork() to launch the help (Matthias)
00578     fcntl(ConnectionNumber(QX11Info::display()), F_SETFD, FD_CLOEXEC);
00579     // set up the fancy (=robust and error ignoring ) KDE xio error handlers (Matthias)
00580     oldXErrorHandler = XSetErrorHandler( kde_x_errhandler );
00581     oldXIOErrorHandler = XSetIOErrorHandler( kde_xio_errhandler );
00582 #endif
00583 
00584     // Trigger initial settings
00585     KGlobalSettings::self();
00586 
00587     KMessage::setMessageHandler( new KMessageBoxMessageHandler(0) );
00588 
00589     checkAccelerators = new KCheckAccelerators( q );
00590     KGestureMap::self()->installEventFilterOnMe( q );
00591 
00592     q->connect(KToolInvocation::self(), SIGNAL(kapplication_hook(QStringList&, QByteArray&)),
00593                q, SLOT(_k_slot_KToolInvocation_hook(QStringList&,QByteArray&)));
00594   }
00595 
00596 #ifdef Q_WS_MAC
00597   if (q->type() == KApplication::GuiClient) {
00598       // This is a QSystemTrayIcon instead of K* because we can't be sure q is a QWidget
00599       QSystemTrayIcon *trayIcon;
00600       if (QSystemTrayIcon::isSystemTrayAvailable())
00601       {
00602           trayIcon = new QSystemTrayIcon(q);
00603           trayIcon->setIcon(q->windowIcon());
00604           /* it's counter-intuitive, but once you do setIcon it's already set the
00605              dock icon... ->show actually shows an icon in the menu bar too  :P */
00606           // trayIcon->show();
00607       }
00608   }
00609 #endif
00610 
00611 
00612   // save and restore the RTL setting, as installTranslator calls qt_detectRTLLanguage,
00613   // which makes it impossible to use the -reverse cmdline switch with KDE apps
00614   // FIXME is this still needed? it looks like QApplication takes care of this
00615   bool rtl = q->isRightToLeft();
00616   q->installTranslator(new KDETranslator(q));
00617   q->setLayoutDirection( rtl ? Qt::RightToLeft:Qt::LeftToRight);
00618   if (i18nc( "Dear Translator! Translate this string to the string 'LTR' in "
00619      "left-to-right languages (as English) or to 'RTL' in right-to-left "
00620      "languages (such as Hebrew and Arabic) to get proper widget layout.",
00621          "LTR" ) == QLatin1String("RTL"))
00622       rtl = !rtl;
00623   q->setLayoutDirection( rtl ? Qt::RightToLeft:Qt::LeftToRight);
00624 
00625   qRegisterMetaType<KUrl>();
00626   qRegisterMetaType<KUrl::List>();
00627 
00628 #ifdef Q_WS_WIN
00629   KApplication_init_windows();
00630 #endif
00631 }
00632 
00633 KApplication* KApplication::kApplication()
00634 {
00635     return KApp;
00636 }
00637 
00638 KConfig* KApplication::sessionConfig()
00639 {
00640     if (!d->pSessionConfig) // create an instance specific config object
00641         d->pSessionConfig = new KConfig( d->sessionConfigName(), KConfig::SimpleConfig );
00642     return d->pSessionConfig;
00643 }
00644 
00645 void KApplication::reparseConfiguration()
00646 {
00647     KGlobal::config()->reparseConfiguration();
00648 }
00649 
00650 void KApplication::quit()
00651 {
00652     QApplication::quit();
00653 }
00654 
00655 void KApplication::disableSessionManagement() {
00656   d->bSessionManagement = false;
00657 }
00658 
00659 void KApplication::enableSessionManagement() {
00660   d->bSessionManagement = true;
00661 #ifdef Q_WS_X11
00662   // Session management support in Qt/KDE is awfully broken.
00663   // If konqueror disables session management right after its startup,
00664   // and enables it later (preloading stuff), it won't be properly
00665   // saved on session shutdown.
00666   // I'm not actually sure why it doesn't work, but saveState()
00667   // doesn't seem to be called on session shutdown, possibly
00668   // because disabling session management after konqueror startup
00669   // disabled it somehow. Forcing saveState() here for this application
00670   // seems to fix it.
00671   if( mySmcConnection ) {
00672         SmcRequestSaveYourself( mySmcConnection, SmSaveLocal, False,
00673                 SmInteractStyleAny,
00674                 False, False );
00675 
00676     // flush the request
00677     IceFlush(SmcGetIceConnection(mySmcConnection));
00678   }
00679 #endif
00680 }
00681 
00682 void KApplication::commitData( QSessionManager& sm )
00683 {
00684     d->session_save = true;
00685     bool canceled = false;
00686 
00687     foreach (KSessionManager *it, KSessionManager::sessionClients()) {
00688         if ( ( canceled = !it->commitData( sm ) ) )
00689             break;
00690     }
00691 
00692     if ( canceled )
00693         sm.cancel();
00694 
00695     if ( sm.allowsInteraction() ) {
00696         QWidgetList donelist, todolist;
00697         QWidget* w;
00698 
00699 commitDataRestart:
00700         todolist = QApplication::topLevelWidgets();
00701 
00702         for ( int i = 0; i < todolist.size(); ++i ) {
00703             w = todolist.at( i );
00704             if( !w )
00705                 break;
00706 
00707             if ( donelist.contains( w ) )
00708                 continue;
00709 
00710             if ( !w->isHidden() && !w->inherits( "KMainWindow" ) ) {
00711                 QCloseEvent e;
00712                 sendEvent( w, &e );
00713                 if ( !e.isAccepted() )
00714                     break; //canceled
00715 
00716                 donelist.append( w );
00717 
00718                 //grab the new list that was just modified by our closeevent
00719                 goto commitDataRestart;
00720             }
00721         }
00722     }
00723 
00724     if ( !d->bSessionManagement )
00725         sm.setRestartHint( QSessionManager::RestartNever );
00726     else
00727         sm.setRestartHint( QSessionManager::RestartIfRunning );
00728     d->session_save = false;
00729 }
00730 
00731 #ifdef Q_WS_X11
00732 static void checkRestartVersion( QSessionManager& sm )
00733 {
00734     Display* dpy = QX11Info::display();
00735     Atom type;
00736     int format;
00737     unsigned long nitems, after;
00738     unsigned char* data;
00739     if( XGetWindowProperty( dpy, RootWindow( dpy, 0 ), XInternAtom( dpy, "KDE_SESSION_VERSION", False ),
00740         0, 1, False, AnyPropertyType, &type, &format, &nitems, &after, &data ) == Success ) {
00741         if( type == XA_INTEGER && format == 32 ) {
00742             int version = *( long* ) data;
00743             if( version == KDE_VERSION_MAJOR ) { // we run in our native session
00744                 XFree( data );
00745                 return; // no need to wrap
00746             }
00747         }
00748         XFree( data );
00749     }
00750 #define NUM_TO_STRING2( num ) #num
00751 #define NUM_TO_STRING( num ) NUM_TO_STRING2( num )
00752     QString wrapper = KStandardDirs::findExe( "kde" NUM_TO_STRING( KDE_VERSION_MAJOR ) ); // "kde4", etc.
00753 #undef NUM_TO_STRING
00754 #undef NUM_TO_STRING2
00755     QStringList restartCommand = sm.restartCommand();
00756     restartCommand.prepend( wrapper );
00757     sm.setRestartCommand( restartCommand );
00758 }
00759 #endif // Q_WS_X11
00760 
00761 void KApplication::saveState( QSessionManager& sm )
00762 {
00763     d->session_save = true;
00764 #ifdef Q_WS_X11
00765     static bool firstTime = true;
00766     mySmcConnection = (SmcConn) sm.handle();
00767 
00768     if ( !d->bSessionManagement ) {
00769         sm.setRestartHint( QSessionManager::RestartNever );
00770     d->session_save = false;
00771         return;
00772     }
00773     else
00774     sm.setRestartHint( QSessionManager::RestartIfRunning );
00775 
00776     if ( firstTime ) {
00777         firstTime = false;
00778     d->session_save = false;
00779         return; // no need to save the state.
00780     }
00781 
00782     // remove former session config if still existing, we want a new
00783     // and fresh one. Note that we do not delete the config file here,
00784     // this is done by the session manager when it executes the
00785     // discard commands. In fact it would be harmful to remove the
00786     // file here, as the session might be stored under a different
00787     // name, meaning the user still might need it eventually.
00788     if ( d->pSessionConfig ) {
00789         delete d->pSessionConfig;
00790         d->pSessionConfig = 0;
00791     }
00792 
00793     // tell the session manager about our new lifecycle
00794     QStringList restartCommand = sm.restartCommand();
00795 
00796     QByteArray multiHead = qgetenv("KDE_MULTIHEAD");
00797     if (multiHead.toLower() == "true") {
00798         // if multihead is enabled, we save our -display argument so that
00799         // we are restored onto the correct head... one problem with this
00800         // is that the display is hard coded, which means we cannot restore
00801         // to a different display (ie. if we are in a university lab and try,
00802         // try to restore a multihead session, our apps could be started on
00803         // someone else's display instead of our own)
00804         QByteArray displayname = qgetenv("DISPLAY");
00805         if (! displayname.isNull()) {
00806             // only store the command if we actually have a DISPLAY
00807             // environment variable
00808             restartCommand.append(QLatin1String("-display"));
00809             restartCommand.append(QLatin1String(displayname));
00810         }
00811         sm.setRestartCommand( restartCommand );
00812     }
00813 
00814 #ifdef Q_WS_X11
00815     checkRestartVersion( sm );
00816 #endif
00817 
00818     // finally: do session management
00819     emit saveYourself(); // for compatibility
00820     bool canceled = false;
00821     foreach(KSessionManager* it, KSessionManager::sessionClients()) {
00822       if(canceled) break;
00823       canceled = !it->saveState( sm );
00824     }
00825 
00826     // if we created a new session config object, register a proper discard command
00827     if ( d->pSessionConfig ) {
00828         d->pSessionConfig->sync();
00829         QStringList discard;
00830         discard  << QLatin1String("rm") << KStandardDirs::locateLocal("config", d->sessionConfigName());
00831         sm.setDiscardCommand( discard );
00832     } else {
00833     sm.setDiscardCommand( QStringList( QLatin1String("") ) );
00834     }
00835 
00836     if ( canceled )
00837         sm.cancel();
00838 #else
00839     // FIXME(E): Implement for Qt Embedded
00840 #endif
00841     d->session_save = false;
00842 }
00843 
00844 bool KApplication::sessionSaving() const
00845 {
00846     return d->session_save;
00847 }
00848 
00849 void KApplicationPrivate::parseCommandLine( )
00850 {
00851     KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
00852 
00853 #ifdef Q_WS_X11
00854     if (args && args->isSet("style"))
00855     {
00856         extern QString kde_overrideStyle; // see KGlobalSettings. Should we have a static setter?
00857         QString reqStyle(args->getOption("style").toLower());
00858         if (QStyleFactory::keys().contains(reqStyle, Qt::CaseInsensitive))
00859             kde_overrideStyle = reqStyle;
00860         else
00861             qWarning() << i18n("The style '%1' was not found", reqStyle);
00862     }
00863 #endif
00864 
00865     if ( q->type() != KApplication::Tty ) {
00866         if (args && args->isSet("icon"))
00867         {
00868             q->setWindowIcon(KIcon(args->getOption("icon")));
00869         }
00870         else {
00871             q->setWindowIcon(KIcon(componentData.aboutData()->programIconName()));
00872         }
00873     }
00874 
00875     if (!args)
00876         return;
00877 
00878     if (args->isSet("config"))
00879     {
00880         QString config = args->getOption("config");
00881         componentData.setConfigName(config);
00882     }
00883 
00884     bool nocrashhandler = (!qgetenv("KDE_DEBUG").isEmpty());
00885     if (!nocrashhandler && args->isSet("crashhandler"))
00886     {
00887         // set default crash handler
00888         KCrash::setCrashHandler(KCrash::defaultCrashHandler);
00889     }
00890     // Always set the app name, can be usefuls for apps that call setEmergencySaveFunction or enable AutoRestart
00891     KCrash::setApplicationName(args->appName());
00892 
00893 #ifdef Q_WS_X11
00894     if ( args->isSet( "waitforwm" ) ) {
00895         Atom type;
00896         (void) q->desktop(); // trigger desktop creation, we need PropertyNotify events for the root window
00897         int format;
00898         unsigned long length, after;
00899         unsigned char *data;
00900         while ( XGetWindowProperty( QX11Info::display(), QX11Info::appRootWindow(), atom_NetSupported,
00901                     0, 1, false, AnyPropertyType, &type, &format,
00902                                     &length, &after, &data ) != Success || !length ) {
00903             if ( data )
00904                 XFree( data );
00905             XEvent event;
00906             XWindowEvent( QX11Info::display(), QX11Info::appRootWindow(), PropertyChangeMask, &event );
00907         }
00908         if ( data )
00909             XFree( data );
00910     }
00911 #else
00912     // FIXME(E): Implement for Qt Embedded
00913 #endif
00914 
00915 #ifndef Q_WS_WIN
00916     if (args->isSet("smkey"))
00917     {
00918         sessionKey = args->getOption("smkey");
00919     }
00920 #endif
00921 }
00922 
00923 extern void kDebugCleanup();
00924 
00925 KApplication::~KApplication()
00926 {
00927 #ifdef Q_WS_X11
00928   if ( d->oldXErrorHandler != NULL )
00929       XSetErrorHandler( d->oldXErrorHandler );
00930   if ( d->oldXIOErrorHandler != NULL )
00931       XSetIOErrorHandler( d->oldXIOErrorHandler );
00932   if ( d->oldIceIOErrorHandler != NULL )
00933       IceSetIOErrorHandler( d->oldIceIOErrorHandler );
00934 #endif
00935 
00936   delete d;
00937   KApp = 0;
00938 
00939 #ifdef Q_WS_X11
00940   mySmcConnection = 0;
00941 #else
00942   // FIXME(E): Implement for Qt Embedded
00943 #endif
00944 }
00945 
00946 
00947 #ifdef Q_WS_X11
00948 class KAppX11HackWidget: public QWidget
00949 {
00950 public:
00951     bool publicx11Event( XEvent * e) { return x11Event( e ); }
00952 };
00953 #endif
00954 
00955 
00956 
00957 #ifdef Q_WS_X11
00958 bool KApplication::x11EventFilter( XEvent *_event )
00959 {
00960     switch ( _event->type ) {
00961         case ClientMessage:
00962         {
00963 #if KDE_IS_VERSION( 3, 90, 90 )
00964 #ifdef __GNUC__
00965 #warning This should be already in Qt, check.
00966 #endif
00967 #endif
00968         // Workaround for focus stealing prevention not working when dragging e.g. text from KWrite
00969         // to KDesktop -> the dialog asking for filename doesn't get activated. This is because
00970         // Qt-3.2.x doesn't have concept of qt_x_user_time at all, and Qt-3.3.0b1 passes the timestamp
00971         // in the XdndDrop message in incorrect field (and doesn't update qt_x_user_time either).
00972         // Patch already sent, future Qt version should have this fixed.
00973             if( _event->xclient.message_type == kde_xdnd_drop )
00974                 { // if the message is XdndDrop
00975                 if( _event->xclient.data.l[ 1 ] == 1 << 24     // and it's broken the way it's in Qt-3.2.x
00976                     && _event->xclient.data.l[ 2 ] == 0
00977                     && _event->xclient.data.l[ 4 ] == 0
00978                     && _event->xclient.data.l[ 3 ] != 0 )
00979                     {
00980                     if( QX11Info::appUserTime() == 0
00981                         || NET::timestampCompare( _event->xclient.data.l[ 3 ], QX11Info::appUserTime() ) > 0 )
00982                         { // and the timestamp looks reasonable
00983                         QX11Info::setAppUserTime(_event->xclient.data.l[ 3 ]); // update our qt_x_user_time from it
00984                         }
00985                     }
00986                 else // normal DND, only needed until Qt updates qt_x_user_time from XdndDrop
00987                     {
00988                     if( QX11Info::appUserTime() == 0
00989                         || NET::timestampCompare( _event->xclient.data.l[ 2 ], QX11Info::appUserTime() ) > 0 )
00990                         { // the timestamp looks reasonable
00991                         QX11Info::setAppUserTime(_event->xclient.data.l[ 2 ]); // update our qt_x_user_time from it
00992                         }
00993                     }
00994                 }
00995         }
00996         default: break;
00997     }
00998 
00999     if (x11Filter) {
01000         foreach (const QWidget *w, *x11Filter) {
01001             if (((KAppX11HackWidget*) w)->publicx11Event(_event))
01002                 return true;
01003         }
01004     }
01005 
01006     return false;
01007 }
01008 #endif // Q_WS_X11
01009 
01010 void KApplication::updateUserTimestamp( int time )
01011 {
01012 #if defined Q_WS_X11
01013     if( time == 0 )
01014     { // get current X timestamp
01015         Window w = XCreateSimpleWindow( QX11Info::display(), QX11Info::appRootWindow(), 0, 0, 1, 1, 0, 0, 0 );
01016         XSelectInput( QX11Info::display(), w, PropertyChangeMask );
01017         unsigned char data[ 1 ];
01018         XChangeProperty( QX11Info::display(), w, XA_ATOM, XA_ATOM, 8, PropModeAppend, data, 1 );
01019         XEvent ev;
01020         XWindowEvent( QX11Info::display(), w, PropertyChangeMask, &ev );
01021         time = ev.xproperty.time;
01022         XDestroyWindow( QX11Info::display(), w );
01023     }
01024     if( QX11Info::appUserTime() == 0
01025         || NET::timestampCompare( time, QX11Info::appUserTime()) > 0 ) // time > appUserTime
01026         QX11Info::setAppUserTime(time);
01027     if( QX11Info::appTime() == 0
01028         || NET::timestampCompare( time, QX11Info::appTime()) > 0 ) // time > appTime
01029         QX11Info::setAppTime(time);
01030 #endif
01031 }
01032 
01033 unsigned long KApplication::userTimestamp() const
01034 {
01035 #if defined Q_WS_X11
01036     return QX11Info::appUserTime();
01037 #else
01038     return 0;
01039 #endif
01040 }
01041 
01042 void KApplication::updateRemoteUserTimestamp( const QString& service, int time )
01043 {
01044 #if defined Q_WS_X11
01045     Q_ASSERT(service.contains('.'));
01046     if( time == 0 )
01047         time = QX11Info::appUserTime();
01048     QDBusInterface(service, QLatin1String("/MainApplication"),
01049             QString(QLatin1String("org.kde.KApplication")))
01050         .call(QLatin1String("updateUserTimestamp"), time);
01051 #endif
01052 }
01053 
01054 
01055 QString KApplication::tempSaveName( const QString& pFilename )
01056 {
01057   QString aFilename;
01058 
01059   if( QDir::isRelativePath(pFilename) )
01060     {
01061       kWarning(101) << "Relative filename passed to KApplication::tempSaveName";
01062       aFilename = QFileInfo( QDir( QLatin1String(".") ), pFilename ).absoluteFilePath();
01063     }
01064   else
01065     aFilename = pFilename;
01066 
01067   QDir aAutosaveDir( QDir::homePath() + QLatin1String("/autosave/") );
01068   if( !aAutosaveDir.exists() )
01069     {
01070       if( !aAutosaveDir.mkdir( aAutosaveDir.absolutePath() ) )
01071         {
01072           // Last chance: use temp dir
01073           aAutosaveDir.setPath( KGlobal::dirs()->saveLocation("tmp") );
01074         }
01075     }
01076 
01077   aFilename.replace( '/', QLatin1String("\\!") )
01078     .prepend( QLatin1Char('#') )
01079     .append( QLatin1Char('#') )
01080     .prepend( QLatin1Char('/') ).prepend( aAutosaveDir.absolutePath() );
01081 
01082   return aFilename;
01083 }
01084 
01085 
01086 QString KApplication::checkRecoverFile( const QString& pFilename,
01087         bool& bRecover )
01088 {
01089   QString aFilename;
01090 
01091   if( QDir::isRelativePath(pFilename) )
01092     {
01093       kWarning(101) << "Relative filename passed to KApplication::tempSaveName";
01094       aFilename = QFileInfo( QDir( QLatin1String(".") ), pFilename ).absoluteFilePath();
01095     }
01096   else
01097     aFilename = pFilename;
01098 
01099   QDir aAutosaveDir( QDir::homePath() + QLatin1String("/autosave/") );
01100   if( !aAutosaveDir.exists() )
01101     {
01102       if( !aAutosaveDir.mkdir( aAutosaveDir.absolutePath() ) )
01103         {
01104           // Last chance: use temp dir
01105           aAutosaveDir.setPath( KGlobal::dirs()->saveLocation("tmp") );
01106         }
01107     }
01108 
01109   aFilename.replace( QLatin1String("/"), QLatin1String("\\!") )
01110       .prepend( QLatin1Char('#') )
01111       .append( QLatin1Char('#') )
01112       .prepend( QLatin1Char('/') )
01113       .prepend( aAutosaveDir.absolutePath() );
01114 
01115   if( QFile( aFilename ).exists() )
01116     {
01117       bRecover = true;
01118       return aFilename;
01119     }
01120   else
01121     {
01122       bRecover = false;
01123       return pFilename;
01124     }
01125 }
01126 
01127 
01128 void KApplication::setTopWidget( QWidget *topWidget )
01129 {
01130     if( !topWidget )
01131       return;
01132 
01133     // set the specified caption
01134     if ( !topWidget->inherits("KMainWindow") ) { // KMainWindow does this already for us
01135         topWidget->setWindowTitle(KGlobal::caption());
01136     }
01137 
01138 #if defined Q_WS_X11
01139 //#ifdef Q_WS_X11 // FIXME(E): Implement for Qt/Embedded
01140     // set the app startup notification window property
01141     KStartupInfo::setWindowStartupId( topWidget->winId(), startupId());
01142 #endif
01143 }
01144 
01145 QByteArray KApplication::startupId() const
01146 {
01147     return d->startup_id;
01148 }
01149 
01150 void KApplication::setStartupId( const QByteArray& startup_id )
01151 {
01152     if( startup_id == d->startup_id )
01153         return;
01154 #if defined Q_WS_X11
01155     KStartupInfo::handleAutoAppStartedSending(); // finish old startup notification if needed
01156 #endif
01157     if( startup_id.isEmpty())
01158         d->startup_id = "0";
01159     else
01160         {
01161         d->startup_id = startup_id;
01162 #if defined Q_WS_X11
01163         KStartupInfoId id;
01164         id.initId( startup_id );
01165         long timestamp = id.timestamp();
01166         if( timestamp != 0 )
01167             updateUserTimestamp( timestamp );
01168 #endif
01169         }
01170 }
01171 
01172 void KApplication::clearStartupId()
01173 {
01174     d->startup_id = "0";
01175 }
01176 
01177 // Qt reads and unsets the value and doesn't provide any way to reach the value,
01178 // so steal it from it beforehand. If Qt gets API for taking (reading and unsetting)
01179 // the startup id from it, this can be dumped.
01180 void KApplicationPrivate::preread_app_startup_id()
01181 {
01182 #if defined Q_WS_X11
01183     KStartupInfoId id = KStartupInfo::currentStartupIdEnv();
01184     KStartupInfo::resetStartupEnv();
01185     startup_id_tmp = new QByteArray( id.id());
01186 #endif
01187 }
01188 
01189 // read the startup notification env variable, save it and unset it in order
01190 // not to propagate it to processes started from this app
01191 void KApplicationPrivate::read_app_startup_id()
01192 {
01193 #if defined Q_WS_X11
01194     startup_id = *startup_id_tmp;
01195     delete startup_id_tmp;
01196     startup_id_tmp = NULL;
01197 #endif
01198 }
01199 
01200 // Hook called by KToolInvocation
01201 void KApplicationPrivate::_k_slot_KToolInvocation_hook(QStringList& envs,QByteArray& startup_id)
01202 {
01203 #ifdef Q_WS_X11
01204     if (QX11Info::display()) {
01205         QByteArray dpystring(XDisplayString(QX11Info::display()));
01206         envs << QString::fromLatin1( QByteArray("DISPLAY=") + dpystring );
01207     } else {
01208         const QByteArray dpystring( qgetenv( "DISPLAY" ));
01209         if(!dpystring.isEmpty())
01210             envs << QString::fromLatin1( QByteArray("DISPLAY=") + dpystring );
01211     }
01212 
01213     if(startup_id.isEmpty())
01214         startup_id = KStartupInfo::createNewStartupId();
01215 #else
01216     Q_UNUSED(envs);
01217     Q_UNUSED(startup_id);
01218 #endif
01219 }
01220 
01221 void KApplication::setSynchronizeClipboard(bool synchronize)
01222 {
01223     KClipboardSynchronizer::self()->setSynchronizing(synchronize);
01224     KClipboardSynchronizer::self()->setReverseSynchronizing(synchronize);
01225 }
01226 
01227 #include "kapplication.moc"
01228 

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal