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

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
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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