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

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
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
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