• Skip to content
  • Skip to link menu
KDE 4.4 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       kFatal(101) << "Session bus not found" << endl;
00502       ::exit(125);
00503   }
00504 
00505   extern bool s_kuniqueapplication_startCalled;
00506   if ( bus && !s_kuniqueapplication_startCalled ) // don't register again if KUniqueApplication did so already
00507   {
00508       QStringList parts = q->organizationDomain().split(QLatin1Char('.'), QString::SkipEmptyParts);
00509       QString reversedDomain;
00510       if (parts.isEmpty())
00511           reversedDomain = QLatin1String("local.");
00512       else
00513           foreach (const QString& s, parts)
00514           {
00515               reversedDomain.prepend(QLatin1Char('.'));
00516               reversedDomain.prepend(s);
00517           }
00518       const QString pidSuffix = QString::number( getpid() ).prepend( QLatin1String("-") );
00519       const QString serviceName = reversedDomain + q->applicationName() + pidSuffix;
00520       if ( bus->registerService(serviceName) == QDBusConnectionInterface::ServiceNotRegistered ) {
00521           kError(101) << "Couldn't register name '" << serviceName << "' with DBUS - another process owns it already!" << endl;
00522           ::exit(126);
00523       }
00524   }
00525   QDBusConnection::sessionBus().registerObject(QLatin1String("/MainApplication"), q,
00526                                                QDBusConnection::ExportScriptableSlots |
00527                                                QDBusConnection::ExportScriptableProperties |
00528                                                QDBusConnection::ExportAdaptors);
00529 
00530   // Trigger creation of locale.
00531   (void) KGlobal::locale();
00532 
00533   KSharedConfig::Ptr config = componentData.config();
00534   QByteArray readOnly = qgetenv("KDE_HOME_READONLY");
00535   if (readOnly.isEmpty() && q->applicationName() != QLatin1String("kdialog"))
00536   {
00537     if (KAuthorized::authorize(QLatin1String("warn_unwritable_config")))
00538        config->isConfigWritable(true);
00539   }
00540 
00541   if (q->type() == KApplication::GuiClient)
00542   {
00543 #ifdef Q_WS_X11
00544     // this is important since we fork() to launch the help (Matthias)
00545     fcntl(ConnectionNumber(QX11Info::display()), F_SETFD, FD_CLOEXEC);
00546     // set up the fancy (=robust and error ignoring ) KDE xio error handlers (Matthias)
00547     oldXErrorHandler = XSetErrorHandler( kde_x_errhandler );
00548     oldXIOErrorHandler = XSetIOErrorHandler( kde_xio_errhandler );
00549 #endif
00550 
00551     // Trigger initial settings
00552     KGlobalSettings::self()->activate();
00553 
00554     KMessage::setMessageHandler( new KMessageBoxMessageHandler(0) );
00555 
00556     KCheckAccelerators::initiateIfNeeded(q);
00557     KGestureMap::self()->installEventFilterOnMe( q );
00558 
00559     q->connect(KToolInvocation::self(), SIGNAL(kapplication_hook(QStringList&, QByteArray&)),
00560                q, SLOT(_k_slot_KToolInvocation_hook(QStringList&,QByteArray&)));
00561   }
00562 
00563 #ifdef Q_WS_MAC
00564   if (q->type() == KApplication::GuiClient) {
00565       // This is a QSystemTrayIcon instead of K* because we can't be sure q is a QWidget
00566       QSystemTrayIcon *trayIcon; //krazy:exclude=qclasses
00567       if (QSystemTrayIcon::isSystemTrayAvailable()) //krazy:exclude=qclasses
00568       {
00569           trayIcon = new QSystemTrayIcon(q); //krazy:exclude=qclasses
00570           trayIcon->setIcon(q->windowIcon());
00571           /* it's counter-intuitive, but once you do setIcon it's already set the
00572              dock icon... ->show actually shows an icon in the menu bar too  :P */
00573           // trayIcon->show();
00574       }
00575   }
00576 #endif
00577 
00578   qRegisterMetaType<KUrl>();
00579   qRegisterMetaType<KUrl::List>();
00580 
00581 #ifdef Q_WS_WIN
00582   KApplication_init_windows();
00583 #endif
00584 }
00585 
00586 KApplication* KApplication::kApplication()
00587 {
00588     return KApp;
00589 }
00590 
00591 KConfig* KApplication::sessionConfig()
00592 {
00593     if (!d->pSessionConfig) // create an instance specific config object
00594         d->pSessionConfig = new KConfig( d->sessionConfigName(), KConfig::SimpleConfig );
00595     return d->pSessionConfig;
00596 }
00597 
00598 void KApplication::reparseConfiguration()
00599 {
00600     KGlobal::config()->reparseConfiguration();
00601 }
00602 
00603 void KApplication::quit()
00604 {
00605     QApplication::quit();
00606 }
00607 
00608 void KApplication::disableSessionManagement() {
00609   d->bSessionManagement = false;
00610 }
00611 
00612 void KApplication::enableSessionManagement() {
00613   d->bSessionManagement = true;
00614 #ifdef Q_WS_X11
00615   // Session management support in Qt/KDE is awfully broken.
00616   // If konqueror disables session management right after its startup,
00617   // and enables it later (preloading stuff), it won't be properly
00618   // saved on session shutdown.
00619   // I'm not actually sure why it doesn't work, but saveState()
00620   // doesn't seem to be called on session shutdown, possibly
00621   // because disabling session management after konqueror startup
00622   // disabled it somehow. Forcing saveState() here for this application
00623   // seems to fix it.
00624   if( mySmcConnection ) {
00625         SmcRequestSaveYourself( mySmcConnection, SmSaveLocal, False,
00626                 SmInteractStyleAny,
00627                 False, False );
00628 
00629     // flush the request
00630     IceFlush(SmcGetIceConnection(mySmcConnection));
00631   }
00632 #endif
00633 }
00634 
00635 void KApplication::commitData( QSessionManager& sm )
00636 {
00637     d->session_save = true;
00638     bool canceled = false;
00639 
00640     foreach (KSessionManager *it, KSessionManager::sessionClients()) {
00641         if ( ( canceled = !it->commitData( sm ) ) )
00642             break;
00643     }
00644 
00645     if ( canceled )
00646         sm.cancel();
00647 
00648     if ( sm.allowsInteraction() ) {
00649         QWidgetList donelist, todolist;
00650         QWidget* w;
00651 
00652 commitDataRestart:
00653         todolist = QApplication::topLevelWidgets();
00654 
00655         for ( int i = 0; i < todolist.size(); ++i ) {
00656             w = todolist.at( i );
00657             if( !w )
00658                 break;
00659 
00660             if ( donelist.contains( w ) )
00661                 continue;
00662 
00663             if ( !w->isHidden() && !w->inherits( "KMainWindow" ) ) {
00664                 QCloseEvent e;
00665                 sendEvent( w, &e );
00666                 if ( !e.isAccepted() )
00667                     break; //canceled
00668 
00669                 donelist.append( w );
00670 
00671                 //grab the new list that was just modified by our closeevent
00672                 goto commitDataRestart;
00673             }
00674         }
00675     }
00676 
00677     if ( !d->bSessionManagement )
00678         sm.setRestartHint( QSessionManager::RestartNever );
00679     else
00680         sm.setRestartHint( QSessionManager::RestartIfRunning );
00681     d->session_save = false;
00682 }
00683 
00684 #ifdef Q_WS_X11
00685 static void checkRestartVersion( QSessionManager& sm )
00686 {
00687     Display* dpy = QX11Info::display();
00688     Atom type;
00689     int format;
00690     unsigned long nitems, after;
00691     unsigned char* data;
00692     if( dpy != NULL && XGetWindowProperty( dpy, RootWindow( dpy, 0 ), XInternAtom( dpy, "KDE_SESSION_VERSION", False ),
00693         0, 1, False, AnyPropertyType, &type, &format, &nitems, &after, &data ) == Success ) {
00694         if( type == XA_CARDINAL && format == 32 ) {
00695             int version = *( long* ) data;
00696             if( version == KDE_VERSION_MAJOR ) { // we run in our native session
00697                 XFree( data );
00698                 return; // no need to wrap
00699             }
00700         }
00701         XFree( data );
00702     }
00703     if( getenv( "KDE_SESSION_VERSION" ) != NULL && atoi( getenv( "KDE_SESSION_VERSION" )) == KDE_VERSION_MAJOR )
00704         return; // we run in our native session, no need to wrap
00705 #define NUM_TO_STRING2( num ) #num
00706 #define NUM_TO_STRING( num ) NUM_TO_STRING2( num )
00707     QString wrapper = KStandardDirs::findExe( "kde" NUM_TO_STRING( KDE_VERSION_MAJOR ) ); // "kde4", etc.
00708 #undef NUM_TO_STRING
00709 #undef NUM_TO_STRING2
00710     if( !wrapper.isEmpty()) {
00711         QStringList restartCommand = sm.restartCommand();
00712         restartCommand.prepend( wrapper );
00713         sm.setRestartCommand( restartCommand );
00714     }
00715 }
00716 #endif // Q_WS_X11
00717 
00718 void KApplication::saveState( QSessionManager& sm )
00719 {
00720     d->session_save = true;
00721 #ifdef Q_WS_X11
00722     static bool firstTime = true;
00723     mySmcConnection = (SmcConn) sm.handle();
00724 
00725     if ( !d->bSessionManagement ) {
00726         sm.setRestartHint( QSessionManager::RestartNever );
00727     d->session_save = false;
00728         return;
00729     }
00730     else
00731     sm.setRestartHint( QSessionManager::RestartIfRunning );
00732 
00733     if ( firstTime ) {
00734         firstTime = false;
00735     d->session_save = false;
00736         return; // no need to save the state.
00737     }
00738 
00739     // remove former session config if still existing, we want a new
00740     // and fresh one. Note that we do not delete the config file here,
00741     // this is done by the session manager when it executes the
00742     // discard commands. In fact it would be harmful to remove the
00743     // file here, as the session might be stored under a different
00744     // name, meaning the user still might need it eventually.
00745     if ( d->pSessionConfig ) {
00746         delete d->pSessionConfig;
00747         d->pSessionConfig = 0;
00748     }
00749 
00750     // tell the session manager about our new lifecycle
00751     QStringList restartCommand = sm.restartCommand();
00752 
00753     QByteArray multiHead = qgetenv("KDE_MULTIHEAD");
00754     if (multiHead.toLower() == "true") {
00755         // if multihead is enabled, we save our -display argument so that
00756         // we are restored onto the correct head... one problem with this
00757         // is that the display is hard coded, which means we cannot restore
00758         // to a different display (ie. if we are in a university lab and try,
00759         // try to restore a multihead session, our apps could be started on
00760         // someone else's display instead of our own)
00761         QByteArray displayname = qgetenv("DISPLAY");
00762         if (! displayname.isNull()) {
00763             // only store the command if we actually have a DISPLAY
00764             // environment variable
00765             restartCommand.append(QLatin1String("-display"));
00766             restartCommand.append(QLatin1String(displayname));
00767         }
00768         sm.setRestartCommand( restartCommand );
00769     }
00770 
00771 #ifdef Q_WS_X11
00772     checkRestartVersion( sm );
00773 #endif
00774 
00775     // finally: do session management
00776     emit saveYourself(); // for compatibility
00777     bool canceled = false;
00778     foreach(KSessionManager* it, KSessionManager::sessionClients()) {
00779       if(canceled) break;
00780       canceled = !it->saveState( sm );
00781     }
00782 
00783     // if we created a new session config object, register a proper discard command
00784     if ( d->pSessionConfig ) {
00785         d->pSessionConfig->sync();
00786         QStringList discard;
00787         discard  << QLatin1String("rm") << KStandardDirs::locateLocal("config", d->sessionConfigName());
00788         sm.setDiscardCommand( discard );
00789     } else {
00790     sm.setDiscardCommand( QStringList( QLatin1String("") ) );
00791     }
00792 
00793     if ( canceled )
00794         sm.cancel();
00795 #else
00796     // FIXME(E): Implement for Qt Embedded
00797 #endif
00798     d->session_save = false;
00799 }
00800 
00801 bool KApplication::sessionSaving() const
00802 {
00803     return d->session_save;
00804 }
00805 
00806 void KApplicationPrivate::parseCommandLine( )
00807 {
00808     KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
00809 
00810     if (args && args->isSet("style"))
00811     {
00812         extern QString kde_overrideStyle; // see KGlobalSettings. Should we have a static setter?
00813         QString reqStyle(args->getOption("style").toLower());
00814         if (QStyleFactory::keys().contains(reqStyle, Qt::CaseInsensitive))
00815             kde_overrideStyle = reqStyle;
00816         else
00817             qWarning() << i18n("The style '%1' was not found", reqStyle);
00818     }
00819 
00820     if ( q->type() != KApplication::Tty ) {
00821         if (args && args->isSet("icon"))
00822         {
00823             q->setWindowIcon(KIcon(args->getOption("icon")));
00824         }
00825         else {
00826             q->setWindowIcon(KIcon(componentData.aboutData()->programIconName()));
00827         }
00828     }
00829 
00830     if (!args)
00831         return;
00832 
00833     if (args->isSet("config"))
00834     {
00835         QString config = args->getOption("config");
00836         componentData.setConfigName(config);
00837     }
00838 
00839     bool nocrashhandler = (!qgetenv("KDE_DEBUG").isEmpty());
00840     if (!nocrashhandler && args->isSet("crashhandler"))
00841     {
00842         // set default crash handler
00843         KCrash::setCrashHandler(KCrash::defaultCrashHandler);
00844     }
00845     // Always set the app name, can be usefuls for apps that call setEmergencySaveFunction or enable AutoRestart
00846     KCrash::setApplicationName(args->appName());
00847     if (!QCoreApplication::applicationDirPath().isEmpty()) {
00848         KCrash::setApplicationPath(QCoreApplication::applicationDirPath());
00849     }
00850 
00851 #ifdef Q_WS_X11
00852     if ( args->isSet( "waitforwm" ) ) {
00853         Atom type;
00854         (void) q->desktop(); // trigger desktop creation, we need PropertyNotify events for the root window
00855         int format;
00856         unsigned long length, after;
00857         unsigned char *data;
00858         while ( XGetWindowProperty( QX11Info::display(), QX11Info::appRootWindow(), atom_NetSupported,
00859                     0, 1, false, AnyPropertyType, &type, &format,
00860                                     &length, &after, &data ) != Success || !length ) {
00861             if ( data )
00862                 XFree( data );
00863             XEvent event;
00864             XWindowEvent( QX11Info::display(), QX11Info::appRootWindow(), PropertyChangeMask, &event );
00865         }
00866         if ( data )
00867             XFree( data );
00868     }
00869 #else
00870     // FIXME(E): Implement for Qt Embedded
00871 #endif
00872 
00873 #ifndef Q_WS_WIN
00874     if (args->isSet("smkey"))
00875     {
00876         sessionKey = args->getOption("smkey");
00877     }
00878 #endif
00879 }
00880 
00881 extern void kDebugCleanup();
00882 
00883 KApplication::~KApplication()
00884 {
00885 #ifdef Q_WS_X11
00886   if ( d->oldXErrorHandler != NULL )
00887       XSetErrorHandler( d->oldXErrorHandler );
00888   if ( d->oldXIOErrorHandler != NULL )
00889       XSetIOErrorHandler( d->oldXIOErrorHandler );
00890   if ( d->oldIceIOErrorHandler != NULL )
00891       IceSetIOErrorHandler( d->oldIceIOErrorHandler );
00892 #endif
00893 
00894   delete d;
00895   KApp = 0;
00896 
00897 #ifdef Q_WS_X11
00898   mySmcConnection = 0;
00899 #else
00900   // FIXME(E): Implement for Qt Embedded
00901 #endif
00902 }
00903 
00904 
00905 #ifdef Q_WS_X11
00906 class KAppX11HackWidget: public QWidget
00907 {
00908 public:
00909     bool publicx11Event( XEvent * e) { return x11Event( e ); }
00910 };
00911 #endif
00912 
00913 
00914 
00915 #ifdef Q_WS_X11
00916 bool KApplication::x11EventFilter( XEvent *_event )
00917 {
00918     switch ( _event->type ) {
00919         case ClientMessage:
00920         {
00921 #if KDE_IS_VERSION( 3, 90, 90 )
00922 #ifdef __GNUC__
00923 #warning This should be already in Qt, check.
00924 #endif
00925 #endif
00926         // Workaround for focus stealing prevention not working when dragging e.g. text from KWrite
00927         // to KDesktop -> the dialog asking for filename doesn't get activated. This is because
00928         // Qt-3.2.x doesn't have concept of qt_x_user_time at all, and Qt-3.3.0b1 passes the timestamp
00929         // in the XdndDrop message in incorrect field (and doesn't update qt_x_user_time either).
00930         // Patch already sent, future Qt version should have this fixed.
00931             if( _event->xclient.message_type == kde_xdnd_drop )
00932                 { // if the message is XdndDrop
00933                 if( _event->xclient.data.l[ 1 ] == 1 << 24     // and it's broken the way it's in Qt-3.2.x
00934                     && _event->xclient.data.l[ 2 ] == 0
00935                     && _event->xclient.data.l[ 4 ] == 0
00936                     && _event->xclient.data.l[ 3 ] != 0 )
00937                     {
00938                     if( QX11Info::appUserTime() == 0
00939                         || NET::timestampCompare( _event->xclient.data.l[ 3 ], QX11Info::appUserTime() ) > 0 )
00940                         { // and the timestamp looks reasonable
00941                         QX11Info::setAppUserTime(_event->xclient.data.l[ 3 ]); // update our qt_x_user_time from it
00942                         }
00943                     }
00944                 else // normal DND, only needed until Qt updates qt_x_user_time from XdndDrop
00945                     {
00946                     if( QX11Info::appUserTime() == 0
00947                         || NET::timestampCompare( _event->xclient.data.l[ 2 ], QX11Info::appUserTime() ) > 0 )
00948                         { // the timestamp looks reasonable
00949                         QX11Info::setAppUserTime(_event->xclient.data.l[ 2 ]); // update our qt_x_user_time from it
00950                         }
00951                     }
00952                 }
00953         }
00954         default: break;
00955     }
00956 
00957     if (x11Filter) {
00958         foreach (const QWidget *w, *x11Filter) {
00959             if (((KAppX11HackWidget*) w)->publicx11Event(_event))
00960                 return true;
00961         }
00962     }
00963 
00964     return false;
00965 }
00966 #endif // Q_WS_X11
00967 
00968 void KApplication::updateUserTimestamp( int time )
00969 {
00970 #if defined Q_WS_X11
00971     if( time == 0 )
00972     { // get current X timestamp
00973         Window w = XCreateSimpleWindow( QX11Info::display(), QX11Info::appRootWindow(), 0, 0, 1, 1, 0, 0, 0 );
00974         XSelectInput( QX11Info::display(), w, PropertyChangeMask );
00975         unsigned char data[ 1 ];
00976         XChangeProperty( QX11Info::display(), w, XA_ATOM, XA_ATOM, 8, PropModeAppend, data, 1 );
00977         XEvent ev;
00978         XWindowEvent( QX11Info::display(), w, PropertyChangeMask, &ev );
00979         time = ev.xproperty.time;
00980         XDestroyWindow( QX11Info::display(), w );
00981     }
00982     if( QX11Info::appUserTime() == 0
00983         || NET::timestampCompare( time, QX11Info::appUserTime()) > 0 ) // time > appUserTime
00984         QX11Info::setAppUserTime(time);
00985     if( QX11Info::appTime() == 0
00986         || NET::timestampCompare( time, QX11Info::appTime()) > 0 ) // time > appTime
00987         QX11Info::setAppTime(time);
00988 #endif
00989 }
00990 
00991 unsigned long KApplication::userTimestamp() const
00992 {
00993 #if defined Q_WS_X11
00994     return QX11Info::appUserTime();
00995 #else
00996     return 0;
00997 #endif
00998 }
00999 
01000 void KApplication::updateRemoteUserTimestamp( const QString& service, int time )
01001 {
01002 #if defined Q_WS_X11
01003     Q_ASSERT(service.contains('.'));
01004     if( time == 0 )
01005         time = QX11Info::appUserTime();
01006     QDBusInterface(service, QLatin1String("/MainApplication"),
01007             QString(QLatin1String("org.kde.KApplication")))
01008         .call(QLatin1String("updateUserTimestamp"), time);
01009 #endif
01010 }
01011 
01012 
01013 QString KApplication::tempSaveName( const QString& pFilename )
01014 {
01015   QString aFilename;
01016 
01017   if( QDir::isRelativePath(pFilename) )
01018     {
01019       kWarning(101) << "Relative filename passed to KApplication::tempSaveName";
01020       aFilename = QFileInfo( QDir( QLatin1String(".") ), pFilename ).absoluteFilePath();
01021     }
01022   else
01023     aFilename = pFilename;
01024 
01025   QDir aAutosaveDir( QDir::homePath() + QLatin1String("/autosave/") );
01026   if( !aAutosaveDir.exists() )
01027     {
01028       if( !aAutosaveDir.mkdir( aAutosaveDir.absolutePath() ) )
01029         {
01030           // Last chance: use temp dir
01031           aAutosaveDir.setPath( KGlobal::dirs()->saveLocation("tmp") );
01032         }
01033     }
01034 
01035   aFilename.replace( '/', QLatin1String("\\!") )
01036     .prepend( QLatin1Char('#') )
01037     .append( QLatin1Char('#') )
01038     .prepend( QLatin1Char('/') ).prepend( aAutosaveDir.absolutePath() );
01039 
01040   return aFilename;
01041 }
01042 
01043 
01044 QString KApplication::checkRecoverFile( const QString& pFilename,
01045         bool& bRecover )
01046 {
01047   QString aFilename;
01048 
01049   if( QDir::isRelativePath(pFilename) )
01050     {
01051       kWarning(101) << "Relative filename passed to KApplication::tempSaveName";
01052       aFilename = QFileInfo( QDir( QLatin1String(".") ), pFilename ).absoluteFilePath();
01053     }
01054   else
01055     aFilename = pFilename;
01056 
01057   QDir aAutosaveDir( QDir::homePath() + QLatin1String("/autosave/") );
01058   if( !aAutosaveDir.exists() )
01059     {
01060       if( !aAutosaveDir.mkdir( aAutosaveDir.absolutePath() ) )
01061         {
01062           // Last chance: use temp dir
01063           aAutosaveDir.setPath( KGlobal::dirs()->saveLocation("tmp") );
01064         }
01065     }
01066 
01067   aFilename.replace( QLatin1String("/"), QLatin1String("\\!") )
01068       .prepend( QLatin1Char('#') )
01069       .append( QLatin1Char('#') )
01070       .prepend( QLatin1Char('/') )
01071       .prepend( aAutosaveDir.absolutePath() );
01072 
01073   if( QFile( aFilename ).exists() )
01074     {
01075       bRecover = true;
01076       return aFilename;
01077     }
01078   else
01079     {
01080       bRecover = false;
01081       return pFilename;
01082     }
01083 }
01084 
01085 
01086 void KApplication::setTopWidget( QWidget *topWidget )
01087 {
01088     if( !topWidget )
01089       return;
01090 
01091     // set the specified caption
01092     if ( !topWidget->inherits("KMainWindow") ) { // KMainWindow does this already for us
01093         topWidget->setWindowTitle(KGlobal::caption());
01094     }
01095 
01096 #if defined Q_WS_X11
01097 //#ifdef Q_WS_X11 // FIXME(E): Implement for Qt/Embedded
01098     // set the app startup notification window property
01099     KStartupInfo::setWindowStartupId( topWidget->winId(), startupId());
01100 #endif
01101 }
01102 
01103 QByteArray KApplication::startupId() const
01104 {
01105     return d->startup_id;
01106 }
01107 
01108 void KApplication::setStartupId( const QByteArray& startup_id )
01109 {
01110     if( startup_id == d->startup_id )
01111         return;
01112 #if defined Q_WS_X11
01113     KStartupInfo::handleAutoAppStartedSending(); // finish old startup notification if needed
01114 #endif
01115     if( startup_id.isEmpty())
01116         d->startup_id = "0";
01117     else
01118         {
01119         d->startup_id = startup_id;
01120 #if defined Q_WS_X11
01121         KStartupInfoId id;
01122         id.initId( startup_id );
01123         long timestamp = id.timestamp();
01124         if( timestamp != 0 )
01125             updateUserTimestamp( timestamp );
01126 #endif
01127         }
01128 }
01129 
01130 void KApplication::clearStartupId()
01131 {
01132     d->startup_id = "0";
01133 }
01134 
01135 // Qt reads and unsets the value and doesn't provide any way to reach the value,
01136 // so steal it from it beforehand. If Qt gets API for taking (reading and unsetting)
01137 // the startup id from it, this can be dumped.
01138 void KApplicationPrivate::preread_app_startup_id()
01139 {
01140 #if defined Q_WS_X11
01141     KStartupInfoId id = KStartupInfo::currentStartupIdEnv();
01142     KStartupInfo::resetStartupEnv();
01143     startup_id_tmp = new QByteArray( id.id());
01144 #endif
01145 }
01146 
01147 // read the startup notification env variable, save it and unset it in order
01148 // not to propagate it to processes started from this app
01149 void KApplicationPrivate::read_app_startup_id()
01150 {
01151 #if defined Q_WS_X11
01152     startup_id = *startup_id_tmp;
01153     delete startup_id_tmp;
01154     startup_id_tmp = NULL;
01155 #endif
01156 }
01157 
01158 // Hook called by KToolInvocation
01159 void KApplicationPrivate::_k_slot_KToolInvocation_hook(QStringList& envs,QByteArray& startup_id)
01160 {
01161 #ifdef Q_WS_X11
01162     if (QX11Info::display()) {
01163         QByteArray dpystring(XDisplayString(QX11Info::display()));
01164         envs << QString::fromLatin1( QByteArray("DISPLAY=") + dpystring );
01165     } else {
01166         const QByteArray dpystring( qgetenv( "DISPLAY" ));
01167         if(!dpystring.isEmpty())
01168             envs << QString::fromLatin1( QByteArray("DISPLAY=") + dpystring );
01169     }
01170 
01171     if(startup_id.isEmpty())
01172         startup_id = KStartupInfo::createNewStartupId();
01173 #else
01174     Q_UNUSED(envs);
01175     Q_UNUSED(startup_id);
01176 #endif
01177 }
01178 
01179 void KApplication::setSynchronizeClipboard(bool synchronize)
01180 {
01181     KClipboardSynchronizer::self()->setSynchronizing(synchronize);
01182     KClipboardSynchronizer::self()->setReverseSynchronizing(synchronize);
01183 }
01184 
01185 #include "kapplication.moc"
01186 

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
  • KUtils
  • Nepomuk
  • Plasma
  •     Sodep
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.9-20090814
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