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

KDEUI

kapplication.cpp

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

KDEUI

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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