kdecore Library API Documentation

kapplication.cpp

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., 59 Temple Place - Suite 330,
00018     Boston, MA 02111-1307, USA.
00019         */
00020 
00021 // $Id: kapplication.cpp,v 1.637.2.8 2004/04/08 09:56:28 lunakl Exp $
00022 
00023 #include "config.h"
00024 
00025 #undef QT_NO_TRANSLATION
00026 #include <qtranslator.h>
00027 #define QT_NO_TRANSLATION
00028 #include <qdir.h>
00029 #include <qptrcollection.h>
00030 #include <qwidgetlist.h>
00031 #include <qstrlist.h>
00032 #include <qfile.h>
00033 #include <qmessagebox.h>
00034 #include <qtextstream.h>
00035 #include <qregexp.h>
00036 #include <qlineedit.h>
00037 #include <qtextedit.h>
00038 #include <qsessionmanager.h>
00039 #include <qptrlist.h>
00040 #include <qtimer.h>
00041 #include <qstylesheet.h>
00042 #include <qpixmapcache.h>
00043 #include <qtooltip.h>
00044 #include <qstylefactory.h>
00045 #include <qmetaobject.h>
00046 #ifndef QT_NO_SQL
00047 #include <qsqlpropertymap.h>
00048 #endif
00049 
00050 #undef QT_NO_TRANSLATION
00051 #include "kapplication.h"
00052 #define QT_NO_TRANSLATION
00053 #include <kglobal.h>
00054 #include <kstandarddirs.h>
00055 #include <kdebug.h>
00056 #include <klocale.h>
00057 #include <kstyle.h>
00058 #include <kiconloader.h>
00059 #include <kclipboard.h>
00060 #include <kconfig.h>
00061 #include <ksimpleconfig.h>
00062 #include <kcmdlineargs.h>
00063 #include <kaboutdata.h>
00064 #include <kglobalsettings.h>
00065 #include <kcrash.h>
00066 #include <kdatastream.h>
00067 #include <klibloader.h>
00068 #include <kmimesourcefactory.h>
00069 #include <kstdaccel.h>
00070 #include <kaccel.h>
00071 #include "kcheckaccelerators.h"
00072 #include <qptrdict.h>
00073 #include <kmacroexpander.h>
00074 #include <kshell.h>
00075 #include <kprotocolinfo.h>
00076 
00077 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00078 #include <kstartupinfo.h> // schroder
00079 #endif
00080 
00081 #include <dcopclient.h>
00082 #include <dcopref.h>
00083 
00084 #include <sys/types.h>
00085 #ifdef HAVE_SYS_STAT_H
00086 #include <sys/stat.h>
00087 #endif
00088 #include <sys/wait.h>
00089 
00090 #include "kwin.h"
00091 
00092 #include <fcntl.h>
00093 #include <stdlib.h> // getenv(), srand(), rand()
00094 #include <signal.h>
00095 #include <unistd.h>
00096 #include <time.h>
00097 #include <sys/time.h>
00098 #include <errno.h>
00099 #include <string.h>
00100 #include <netdb.h>
00101 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00102 //#ifndef Q_WS_QWS //FIXME(E): NetWM should talk to QWS...
00103 #include <netwm.h> // schroder
00104 #endif
00105 
00106 #include "kprocctrl.h"
00107 
00108 #ifdef HAVE_PATHS_H
00109 #include <paths.h>
00110 #endif
00111 
00112 //#if defined Q_WS_X11 && ! defined K_WS_QTONLY
00113 #ifdef Q_WS_X11
00114 #include <X11/Xlib.h> // schrode
00115 #include <X11/Xutil.h> // schrode
00116 #include <X11/Xatom.h> // schrode
00117 #include <X11/SM/SMlib.h> // schrode
00118 #include <fixx11h.h> // schrode
00119 #endif
00120 #include <KDE-ICE/ICElib.h>
00121 
00122 #ifdef Q_WS_X11
00123 #define DISPLAY "DISPLAY"
00124 #elif defined(Q_WS_QWS)
00125 #define DISPLAY "QWS_DISPLAY"
00126 #endif
00127 
00128 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00129 #include <kipc.h> // schroder
00130 #endif
00131 
00132 #include "kappdcopiface.h"
00133 
00134 bool kde_have_kipc = true; // magic hook to disable kipc in kdm
00135 bool kde_kiosk_exception = false; // flag to disable kiosk restrictions
00136 
00137 KApplication* KApplication::KApp = 0L;
00138 bool KApplication::loadedByKdeinit = false;
00139 DCOPClient *KApplication::s_DCOPClient = 0L;
00140 bool KApplication::s_dcopClientNeedsPostInit = false;
00141 
00142 static Atom atom_DesktopWindow;
00143 static Atom atom_NetSupported;
00144 #if KDE_IS_VERSION( 3, 2, 91 )
00145 #warning Obsolete, remove.
00146 // remove atom_KdeNetUserTime related stuff (l.lunak@kde.org)
00147 #endif
00148 static Atom atom_KdeNetUserTime;
00149 static Atom kde_net_wm_user_time     = 0;
00150 #if KDE_IS_VERSION( 3, 2, 91 )
00151 #warning This should be in Qt already, check.
00152 // remove things related to qt_x_user_time that should be in Qt by now (l.lunak@kde.org)
00153 #endif
00154 Time   qt_x_user_time = CurrentTime;
00155 extern Time qt_x_time;
00156 static Atom kde_xdnd_drop;
00157 
00158 template class QPtrList<KSessionManaged>;
00159 
00160 #ifdef Q_WS_X11
00161 extern "C" {
00162 static int kde_xio_errhandler( Display * dpy )
00163 {
00164   return kapp->xioErrhandler( dpy );
00165 }
00166 
00167 static int kde_x_errhandler( Display *dpy, XErrorEvent *err )
00168 {
00169   return kapp->xErrhandler( dpy, err );
00170 }
00171 
00172 }
00173 #endif
00174 
00175 extern "C" {
00176 static void kde_ice_ioerrorhandler( IceConn conn )
00177 {
00178     if(kapp)
00179         kapp->iceIOErrorHandler( conn );
00180     // else ignore the error for now
00181 }
00182 }
00183 
00184 /*
00185   Private data to make keeping binary compatibility easier
00186  */
00187 class KApplicationPrivate
00188 {
00189 public:
00190   KApplicationPrivate()
00191     :   actionRestrictions( false ),
00192     refCount( 1 ),
00193     oldIceIOErrorHandler( 0 ),
00194     checkAccelerators( 0 ),
00195     overrideStyle( QString::null ),
00196     startup_id( "0" ),
00197         app_started_timer( NULL ),
00198     m_KAppDCOPInterface( 0L ),
00199     session_save( false ),
00200         oldXErrorHandler( NULL ),
00201         oldXIOErrorHandler( NULL )
00202   {
00203   }
00204 
00205   ~KApplicationPrivate()
00206   {}
00207 
00208 
00209   bool actionRestrictions : 1;
00210   bool guiEnabled : 1;
00217   int refCount;
00218   IceIOErrorHandler oldIceIOErrorHandler;
00219   KCheckAccelerators* checkAccelerators;
00220   QString overrideStyle;
00221   QString geometry_arg;
00222   QCString startup_id;
00223   QTimer* app_started_timer;
00224   KAppDCOPInterface *m_KAppDCOPInterface;
00225   bool session_save;
00226   int (*oldXErrorHandler)(Display*,XErrorEvent*);
00227   int (*oldXIOErrorHandler)(Display*);
00228 
00229   class URLActionRule
00230   {
00231   public:
00232 #define checkExactMatch(s, b) \
00233         if (s.isEmpty()) b = true; \
00234         else if (s[s.length()-1] == '!') \
00235         { b = false; s.truncate(s.length()-1); } \
00236         else b = true;
00237 #define checkStartWildCard(s, b) \
00238         if (s.isEmpty()) b = true; \
00239         else if (s[0] == '*') \
00240         { b = true; s = s.mid(1); } \
00241         else b = false;
00242 #define checkEqual(s, b) \
00243         b = (s == "=");
00244 
00245      URLActionRule(const QString &act,
00246                    const QString &bProt, const QString &bHost, const QString &bPath,
00247                    const QString &dProt, const QString &dHost, const QString &dPath,
00248                    bool perm)
00249                    : action(act),
00250                      baseProt(bProt), baseHost(bHost), basePath(bPath),
00251                      destProt(dProt), destHost(dHost), destPath(dPath),
00252                      permission(perm)
00253                    {
00254                       checkExactMatch(baseProt, baseProtWildCard);
00255                       checkStartWildCard(baseHost, baseHostWildCard);
00256                       checkExactMatch(basePath, basePathWildCard);
00257                       checkExactMatch(destProt, destProtWildCard);
00258                       checkStartWildCard(destHost, destHostWildCard);
00259                       checkExactMatch(destPath, destPathWildCard);
00260                       checkEqual(destProt, destProtEqual);
00261                       checkEqual(destHost, destHostEqual);
00262                    }
00263 
00264      bool baseMatch(const KURL &url, const QString &protClass)
00265      {
00266         if (baseProtWildCard)
00267         {
00268            if ( !baseProt.isEmpty() && !url.protocol().startsWith(baseProt) &&
00269                 (protClass.isEmpty() || (protClass != baseProt)) )
00270               return false;
00271         }
00272         else
00273         {
00274            if ( (url.protocol() != baseProt) &&
00275                 (protClass.isEmpty() || (protClass != baseProt)) )
00276               return false;
00277         }
00278         if (baseHostWildCard)
00279         {
00280            if (!baseHost.isEmpty() && !url.host().endsWith(baseHost))
00281               return false;
00282         }
00283         else
00284         {
00285            if (url.host() != baseHost)
00286               return false;
00287         }
00288         if (basePathWildCard)
00289         {
00290            if (!basePath.isEmpty() && !url.path().startsWith(basePath))
00291               return false;
00292         }
00293         else
00294         {
00295            if (url.path() != basePath)
00296               return false;
00297         }
00298         return true;
00299      }
00300 
00301      bool destMatch(const KURL &url, const QString &protClass, const KURL &base, const QString &baseClass)
00302      {
00303         if (destProtEqual)
00304         {
00305            if ( (url.protocol() != base.protocol()) &&
00306                 (protClass.isEmpty() || baseClass.isEmpty() || protClass != baseClass) )
00307               return false;
00308         }
00309         else if (destProtWildCard)
00310         {
00311            if ( !destProt.isEmpty() && !url.protocol().startsWith(destProt) &&
00312                 (protClass.isEmpty() || (protClass != destProt)) )
00313               return false;
00314         }
00315         else
00316         {
00317            if ( (url.protocol() != destProt) &&
00318                 (protClass.isEmpty() || (protClass != destProt)) )
00319               return false;
00320         }
00321         if (destHostWildCard)
00322         {
00323            if (!destHost.isEmpty() && !url.host().endsWith(destHost))
00324               return false;
00325         }
00326         else if (destHostEqual)
00327         {
00328            if (url.host() != base.host())
00329               return false;
00330         }
00331         else
00332         {
00333            if (url.host() != destHost)
00334               return false;
00335         }
00336         if (destPathWildCard)
00337         {
00338            if (!destPath.isEmpty() && !url.path().startsWith(destPath))
00339               return false;
00340         }
00341         else
00342         {
00343            if (url.path() != destPath)
00344               return false;
00345         }
00346         return true;
00347      }
00348 
00349      QString action;
00350      QString baseProt;
00351      QString baseHost;
00352      QString basePath;
00353      QString destProt;
00354      QString destHost;
00355      QString destPath;
00356      bool baseProtWildCard : 1;
00357      bool baseHostWildCard : 1;
00358      bool basePathWildCard : 1;
00359      bool destProtWildCard : 1;
00360      bool destHostWildCard : 1;
00361      bool destPathWildCard : 1;
00362      bool destProtEqual    : 1;
00363      bool destHostEqual    : 1;
00364      bool permission;
00365   };
00366   QPtrList<URLActionRule> urlActionRestrictions;
00367 
00368     QString sessionKey;
00369     QString pSessionConfigFile;
00370 };
00371 
00372 
00373 static QPtrList<QWidget>*x11Filter = 0;
00374 static bool autoDcopRegistration = true;
00375 
00376 void KApplication::installX11EventFilter( QWidget* filter )
00377 {
00378     if ( !filter )
00379         return;
00380     if (!x11Filter)
00381         x11Filter = new QPtrList<QWidget>;
00382     connect ( filter, SIGNAL( destroyed() ), this, SLOT( x11FilterDestroyed() ) );
00383     x11Filter->append( filter );
00384 }
00385 
00386 void KApplication::x11FilterDestroyed()
00387 {
00388     removeX11EventFilter( static_cast< const QWidget* >( sender()));
00389 }
00390 
00391 void KApplication::removeX11EventFilter( const QWidget* filter )
00392 {
00393     if ( !x11Filter || !filter )
00394         return;
00395     x11Filter->removeRef( filter );
00396     if ( x11Filter->isEmpty() ) {
00397         delete x11Filter;
00398         x11Filter = 0;
00399     }
00400 }
00401 
00402 // FIXME: remove this when we've get a better method of
00403 // customizing accelerator handling -- hopefully in Qt.
00404 // For now, this is set whenever an accelerator is overridden
00405 // in KAccelEventHandler so that the AccelOverride isn't sent twice. -- ellis, 19/10/02
00406 extern bool kde_g_bKillAccelOverride;
00407 
00408 bool KApplication::notify(QObject *receiver, QEvent *event)
00409 {
00410     QEvent::Type t = event->type();
00411     if (kde_g_bKillAccelOverride)
00412     {
00413        kde_g_bKillAccelOverride = false;
00414        // Indicate that the accelerator has been overridden.
00415        if (t == QEvent::AccelOverride)
00416        {
00417           static_cast<QKeyEvent *>(event)->accept();
00418           return true;
00419        }
00420        else
00421           kdWarning(125) << "kde_g_bKillAccelOverride set, but received an event other than AccelOverride." << endl;
00422     }
00423 
00424     if ((t == QEvent::AccelOverride) || (t == QEvent::KeyPress))
00425     {
00426        static const KShortcut& _selectAll = KStdAccel::selectAll();
00427        if (receiver && receiver->inherits("QLineEdit"))
00428        {
00429           QLineEdit *edit = static_cast<QLineEdit *>(receiver);
00430           // We have a keypress for a lineedit...
00431           QKeyEvent *kevent = static_cast<QKeyEvent *>(event);
00432           KKey key(kevent);
00433           if (_selectAll.contains(key))
00434           {
00435              if (t == QEvent::KeyPress)
00436              {
00437                 edit->selectAll();
00438                 return true;
00439              }
00440              else
00441              {
00442                 kevent->accept();
00443              }
00444           }
00445           // Ctrl-U deletes from start of line.
00446           if (key == KKey(Qt::CTRL + Qt::Key_U))
00447           {
00448              if (t == QEvent::KeyPress)
00449              {
00450                 if (!edit->isReadOnly())
00451                 {
00452                    QString t(edit->text());
00453                    t = t.mid(edit->cursorPosition());
00454                    edit->validateAndSet(t, 0, 0, 0);
00455                 }
00456                 return true;
00457              }
00458              else
00459              {
00460                 kevent->accept();
00461              }
00462 
00463           }
00464        }
00465        if (receiver && receiver->inherits("QTextEdit"))
00466        {
00467           QTextEdit *medit = static_cast<QTextEdit *>(receiver);
00468           // We have a keypress for a multilineedit...
00469           QKeyEvent *kevent = static_cast<QKeyEvent *>(event);
00470           if (_selectAll.contains(KKey(kevent)))
00471           {
00472              if (t == QEvent::KeyPress)
00473              {
00474                 medit->selectAll();
00475                 return true;
00476              }
00477              else
00478              {
00479                 kevent->accept();
00480              }
00481           }
00482        }
00483     }
00484     if( event->type() == QEvent::Show && receiver->isWidgetType())
00485     {
00486     QWidget* w = static_cast< QWidget* >( receiver );
00487         if( w->isTopLevel() && !startupId().isEmpty()) // TODO better done using window group leader?
00488             KStartupInfo::setWindowStartupId( w->winId(), startupId());
00489     if( w->isTopLevel() && qt_x_user_time != CurrentTime ) // CurrentTime means no input event yet
00490             XChangeProperty( qt_xdisplay(), w->winId(), kde_net_wm_user_time, XA_CARDINAL,
00491                 32, PropModeReplace, (unsigned char*)&qt_x_user_time, 1 );
00492     }
00493     if( event->type() == QEvent::Show && receiver->isWidgetType())
00494     {
00495     QWidget* w = static_cast< QWidget* >( receiver );
00496         if( w->isTopLevel() && !w->testWFlags( WX11BypassWM ) && !w->isPopup() && !event->spontaneous())
00497         {
00498             if( d->app_started_timer == NULL )
00499             {
00500                 d->app_started_timer = new QTimer( this );
00501                 connect( d->app_started_timer, SIGNAL( timeout()), SLOT( checkAppStartedSlot()));
00502             }
00503             if( !d->app_started_timer->isActive())
00504                 d->app_started_timer->start( 0, true );
00505         }
00506     }
00507     return QApplication::notify(receiver, event);
00508 }
00509 
00510 void KApplication::checkAppStartedSlot()
00511 {
00512     KStartupInfo::handleAutoAppStartedSending();
00513 }
00514 
00515 // the help class for session management communication
00516 static QPtrList<KSessionManaged>* sessionClients()
00517 {
00518     static QPtrList<KSessionManaged>* session_clients = 0L;
00519     if ( !session_clients )
00520         session_clients = new QPtrList<KSessionManaged>;
00521     return session_clients;
00522 }
00523 
00524 /*
00525   Auxiliary function to calculate a a session config name used for the
00526   instance specific config object.
00527   Syntax:  "session/<appname>_<sessionId>"
00528  */
00529 QString KApplication::sessionConfigName() const
00530 {
00531 #if QT_VERSION < 0x030100
00532     return QString("session/%1_%2_%3").arg(name()).arg(sessionId()).arg(d->sessionKey);
00533 #else
00534     QString sessKey = sessionKey();
00535     if ( sessKey.isEmpty() && !d->sessionKey.isEmpty() )
00536         sessKey = d->sessionKey;
00537     return QString("session/%1_%2_%3").arg(name()).arg(sessionId()).arg(sessKey);
00538 #endif
00539 }
00540 
00541 #ifndef Q_WS_QWS
00542 static SmcConn mySmcConnection = 0;
00543 static SmcConn tmpSmcConnection = 0;
00544 #else
00545 // FIXME(E): Implement for Qt Embedded
00546 // Possibly "steal" XFree86's libSM?
00547 #endif
00548 static QTime* smModificationTime = 0;
00549 
00550 KApplication::KApplication( int& argc, char** argv, const QCString& rAppName,
00551                             bool allowStyles, bool GUIenabled ) :
00552   QApplication( argc, argv, GUIenabled ), KInstance(rAppName),
00553 #ifdef Q_WS_X11
00554   display(0L),
00555 #endif
00556   d (new KApplicationPrivate())
00557 {
00558     read_app_startup_id();
00559     if (!GUIenabled)
00560        allowStyles = false;
00561     useStyles = allowStyles;
00562     Q_ASSERT (!rAppName.isEmpty());
00563     setName(rAppName);
00564 
00565     installSigpipeHandler();
00566     KCmdLineArgs::initIgnore(argc, argv, rAppName.data());
00567     parseCommandLine( );
00568     init(GUIenabled);
00569     d->m_KAppDCOPInterface = new KAppDCOPInterface(this);
00570 }
00571 
00572 KApplication::KApplication( bool allowStyles, bool GUIenabled ) :
00573   QApplication( *KCmdLineArgs::qt_argc(), *KCmdLineArgs::qt_argv(),
00574                 GUIenabled ),
00575   KInstance( KCmdLineArgs::about),
00576 #ifdef Q_WS_X11
00577   display(0L),
00578 #endif
00579   d (new KApplicationPrivate)
00580 {
00581     read_app_startup_id();
00582     if (!GUIenabled)
00583        allowStyles = false;
00584     useStyles = allowStyles;
00585     setName( instanceName() );
00586 
00587     installSigpipeHandler();
00588     parseCommandLine( );
00589     init(GUIenabled);
00590     d->m_KAppDCOPInterface = new KAppDCOPInterface(this);
00591 }
00592 
00593 KApplication::KApplication( bool allowStyles, bool GUIenabled, KInstance* _instance ) :
00594   QApplication( *KCmdLineArgs::qt_argc(), *KCmdLineArgs::qt_argv(),
00595                 GUIenabled ),
00596   KInstance( _instance ),
00597 #ifdef Q_WS_X11
00598   display(0L),
00599 #endif
00600   d (new KApplicationPrivate)
00601 {
00602     read_app_startup_id();
00603     if (!GUIenabled)
00604        allowStyles = false;
00605     useStyles = allowStyles;
00606     setName( instanceName() );
00607 
00608     installSigpipeHandler();
00609     parseCommandLine( );
00610     init(GUIenabled);
00611     d->m_KAppDCOPInterface = new KAppDCOPInterface(this);
00612 }
00613 
00614 #ifdef Q_WS_X11
00615 KApplication::KApplication(Display *display, int& argc, char** argv, const QCString& rAppName,
00616                            bool allowStyles, bool GUIenabled ) :
00617   QApplication( display ), KInstance(rAppName),
00618   display(0L),
00619   d (new KApplicationPrivate())
00620 {
00621     read_app_startup_id();
00622     if (!GUIenabled)
00623        allowStyles = false;
00624     useStyles = allowStyles;
00625 
00626     Q_ASSERT (!rAppName.isEmpty());
00627     setName(rAppName);
00628 
00629     installSigpipeHandler();
00630     KCmdLineArgs::initIgnore(argc, argv, rAppName.data());
00631     parseCommandLine( );
00632     init(GUIenabled);
00633     d->m_KAppDCOPInterface = new KAppDCOPInterface(this);
00634 }
00635 #endif
00636 
00637 int KApplication::xioErrhandler( Display* dpy )
00638 {
00639     if(kapp)
00640     {
00641         emit shutDown();
00642         d->oldXIOErrorHandler( dpy );
00643     }
00644     exit( 1 );
00645     return 0;
00646 }
00647 
00648 int KApplication::xErrhandler( Display* dpy, void* err_ )
00649 { // no idea how to make forward decl. for XErrorEvent
00650     XErrorEvent* err = static_cast< XErrorEvent* >( err_ );
00651     if(kapp)
00652     {
00653         // add KDE specific stuff here
00654         d->oldXErrorHandler( dpy, err );
00655     }
00656     return 0;
00657 }
00658 
00659 void KApplication::iceIOErrorHandler( _IceConn *conn )
00660 {
00661     emit shutDown();
00662 
00663     if ( d->oldIceIOErrorHandler != NULL )
00664       (*d->oldIceIOErrorHandler)( conn );
00665 
00666     exit( 1 );
00667 }
00668 
00669 class KDETranslator : public QTranslator
00670 {
00671 public:
00672   KDETranslator(QObject *parent) : QTranslator(parent, "kdetranslator") {}
00673   virtual QTranslatorMessage findMessage(const char* context,
00674                      const char *sourceText,
00675                      const char* message) const
00676   {
00677     QTranslatorMessage res;
00678     res.setTranslation(KGlobal::locale()->translateQt(context, sourceText, message));
00679     return res;
00680   }
00681 };
00682 
00683 void KApplication::init(bool GUIenabled)
00684 {
00685   d->guiEnabled = GUIenabled;
00686   if ((getuid() != geteuid()) ||
00687       (getgid() != getegid()))
00688   {
00689      fprintf(stderr, "The KDE libraries are not designed to run with suid privileges.\n");
00690      ::exit(127);
00691   }
00692 
00693   KProcessController::ref();
00694 
00695   (void) KClipboardSynchronizer::self();
00696 
00697   QApplication::setDesktopSettingsAware( false );
00698 
00699   KApp = this;
00700 
00701 
00702 #ifdef Q_WS_X11 //FIXME(E)
00703   // create all required atoms in _one_ roundtrip to the X server
00704   if ( GUIenabled ) {
00705       const int max = 20;
00706       Atom* atoms[max];
00707       char* names[max];
00708       Atom atoms_return[max];
00709       int n = 0;
00710 
00711       atoms[n] = &kipcCommAtom;
00712       names[n++] = (char *) "KIPC_COMM_ATOM";
00713 
00714       atoms[n] = &atom_DesktopWindow;
00715       names[n++] = (char *) "KDE_DESKTOP_WINDOW";
00716 
00717       atoms[n] = &atom_NetSupported;
00718       names[n++] = (char *) "_NET_SUPPORTED";
00719 
00720       atoms[n] = &atom_KdeNetUserTime;
00721       names[n++] = (char *) "_KDE_NET_USER_TIME";
00722 
00723       atoms[n] = &kde_net_wm_user_time;
00724       names[n++] = (char *) "_NET_WM_USER_TIME";
00725       
00726       atoms[n] = &kde_xdnd_drop;
00727       names[n++] = (char *) "XdndDrop";
00728 
00729       XInternAtoms( qt_xdisplay(), names, n, false, atoms_return );
00730 
00731       for (int i = 0; i < n; i++ )
00732       *atoms[i] = atoms_return[i];
00733   }
00734 #endif
00735 
00736   dcopAutoRegistration();
00737   dcopClientPostInit();
00738 
00739   smw = 0;
00740 
00741   // Initial KIPC event mask.
00742 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00743   kipcEventMask = (1 << KIPC::StyleChanged) | (1 << KIPC::PaletteChanged) |
00744                   (1 << KIPC::FontChanged) | (1 << KIPC::BackgroundChanged) |
00745                   (1 << KIPC::ToolbarStyleChanged) | (1 << KIPC::SettingsChanged) |
00746                   (1 << KIPC::ClipboardConfigChanged);
00747 #endif
00748 
00749   // Trigger creation of locale.
00750   (void) KGlobal::locale();
00751 
00752   KConfig* config = KGlobal::config();
00753   d->actionRestrictions = config->hasGroup("KDE Action Restrictions" ) && !kde_kiosk_exception;
00754   // For brain-dead configurations where the user's local config file is not writable.
00755   // * We use kdialog to warn the user, so we better not generate warnings from
00756   //   kdialog itself.
00757   // * Don't warn if we run with a read-only $HOME
00758   QCString readOnly = getenv("KDE_HOME_READONLY");
00759   if (readOnly.isEmpty() && (qstrcmp(name(), "kdialog") != 0))
00760   {
00761     KConfigGroupSaver saver(config, "KDE Action Restrictions");
00762     if (config->readBoolEntry("warn_unwritable_config",true))
00763        config->checkConfigFilesWritable(true);
00764   }
00765 
00766   if (GUIenabled)
00767   {
00768 #ifdef Q_WS_X11
00769     // this is important since we fork() to launch the help (Matthias)
00770     fcntl(ConnectionNumber(qt_xdisplay()), F_SETFD, FD_CLOEXEC);
00771     // set up the fancy (=robust and error ignoring ) KDE xio error handlers (Matthias)
00772     d->oldXErrorHandler = XSetErrorHandler( kde_x_errhandler );
00773     d->oldXIOErrorHandler = XSetIOErrorHandler( kde_xio_errhandler );
00774 #endif
00775 
00776     connect( this, SIGNAL( aboutToQuit() ), this, SIGNAL( shutDown() ) );
00777 
00778 #ifdef Q_WS_X11 //FIXME(E)
00779     display = desktop()->x11Display();
00780 #endif
00781 
00782     {
00783         QStringList plugins = KGlobal::dirs()->resourceDirs( "qtplugins" );
00784         QStringList::Iterator it = plugins.begin();
00785         while (it != plugins.end()) {
00786             addLibraryPath( *it );
00787             ++it;
00788         }
00789 
00790     }
00791     kdisplaySetStyle();
00792     kdisplaySetFont();
00793 //    kdisplaySetPalette(); done by kdisplaySetStyle
00794     propagateSettings(SETTINGS_QT);
00795 
00796     // Set default mime-source factory
00797     // XXX: This is a hack. Make our factory the default factory, but add the
00798     // previous default factory to the list of factories. Why? When the default
00799     // factory can't resolve something, it iterates in the list of factories.
00800     // But it QWhatsThis only uses the default factory. So if there was already
00801     // a default factory (which happens when using an image library using uic),
00802     // we prefer KDE's factory and so we put that old default factory in the
00803     // list and use KDE as the default. This may speed up things as well.
00804     QMimeSourceFactory* oldDefaultFactory = QMimeSourceFactory::takeDefaultFactory();
00805     QMimeSourceFactory::setDefaultFactory( mimeSourceFactory() );
00806     if ( oldDefaultFactory ) {
00807         QMimeSourceFactory::addFactory( oldDefaultFactory );
00808     }
00809 
00810     KConfigGroupSaver saver( config, "Development" );
00811     if( config->hasKey( "CheckAccelerators" ) || config->hasKey( "AutoCheckAccelerators" ))
00812         d->checkAccelerators = new KCheckAccelerators( this );
00813   }
00814 
00815   // save and restore the RTL setting, as installTranslator calls qt_detectRTLLanguage,
00816   // which makes it impossible to use the -reverse cmdline switch with KDE apps
00817   bool rtl = reverseLayout();
00818   installTranslator(new KDETranslator(this));
00819   setReverseLayout( rtl );
00820   if (i18n( "_: Dear Translator! Translate this string to the string 'LTR' in "
00821      "left-to-right languages (as english) or to 'RTL' in right-to-left "
00822      "languages (such as Hebrew and Arabic) to get proper widget layout." ) == "RTL")
00823     setReverseLayout( !rtl );
00824 
00825   // install appdata resource type
00826   KGlobal::dirs()->addResourceType("appdata", KStandardDirs::kde_default("data")
00827                                    + QString::fromLatin1(name()) + '/');
00828   pSessionConfig = 0L;
00829   bSessionManagement = true;
00830 
00831 #ifdef Q_WS_X11
00832   // register a communication window for desktop changes (Matthias)
00833   if (GUIenabled && kde_have_kipc )
00834   {
00835     smw = new QWidget(0,0);
00836     long data = 1;
00837     XChangeProperty(qt_xdisplay(), smw->winId(),
00838             atom_DesktopWindow, atom_DesktopWindow,
00839             32, PropModeReplace, (unsigned char *)&data, 1);
00840   }
00841 #else
00842   // FIXME(E): Implement for Qt Embedded
00843 #endif
00844 
00845   d->oldIceIOErrorHandler = IceSetIOErrorHandler( kde_ice_ioerrorhandler );
00846 }
00847 
00848 static int my_system (const char *command) {
00849    int pid, status;
00850 
00851    QApplication::flushX();
00852    pid = fork();
00853    if (pid == -1)
00854       return -1;
00855    if (pid == 0) {
00856       const char* shell = "/bin/sh";
00857       execl(shell, shell, "-c", command, (void *)0);
00858       ::exit(127);
00859    }
00860    do {
00861       if (waitpid(pid, &status, 0) == -1) {
00862          if (errno != EINTR)
00863             return -1;
00864        } else
00865             return status;
00866    } while(1);
00867 }
00868 
00869 
00870 DCOPClient *KApplication::dcopClient()
00871 {
00872   if (s_DCOPClient)
00873     return s_DCOPClient;
00874 
00875   s_DCOPClient = new DCOPClient();
00876   KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
00877   if (args && args->isSet("dcopserver"))
00878   {
00879     s_DCOPClient->setServerAddress( args->getOption("dcopserver"));
00880   }
00881   if( kapp ) {
00882     connect(s_DCOPClient, SIGNAL(attachFailed(const QString &)),
00883             kapp, SLOT(dcopFailure(const QString &)));
00884     connect(s_DCOPClient, SIGNAL(blockUserInput(bool) ),
00885             kapp, SLOT(dcopBlockUserInput(bool)) );
00886   }
00887   else
00888     s_dcopClientNeedsPostInit = true;
00889 
00890   DCOPClient::setMainClient( s_DCOPClient );
00891   return s_DCOPClient;
00892 }
00893 
00894 void KApplication::dcopClientPostInit()
00895 {
00896   if( s_dcopClientNeedsPostInit )
00897     {
00898     s_dcopClientNeedsPostInit = false;
00899     connect(s_DCOPClient, SIGNAL(blockUserInput(bool) ),
00900             SLOT(dcopBlockUserInput(bool)) );
00901     s_DCOPClient->bindToApp(); // Make sure we get events from the DCOPClient.
00902     }
00903 }
00904 
00905 void KApplication::dcopAutoRegistration()
00906 {
00907   if (autoDcopRegistration)
00908      {
00909      ( void ) dcopClient();
00910      if( dcopClient()->appId().isEmpty())
00911          dcopClient()->registerAs(name());
00912      }
00913 }
00914 
00915 void KApplication::disableAutoDcopRegistration()
00916 {
00917   autoDcopRegistration = false;
00918 }
00919 
00920 KConfig* KApplication::sessionConfig()
00921 {
00922     if (pSessionConfig)
00923         return pSessionConfig;
00924 
00925     // create an instance specific config object
00926     pSessionConfig = new KConfig( sessionConfigName(), false, false);
00927     return pSessionConfig;
00928 }
00929 
00930 void KApplication::ref()
00931 {
00932     d->refCount++;
00933     //kdDebug() << "KApplication::ref() : refCount = " << d->refCount << endl;
00934 }
00935 
00936 void KApplication::deref()
00937 {
00938     d->refCount--;
00939     //kdDebug() << "KApplication::deref() : refCount = " << d->refCount << endl;
00940     if ( d->refCount <= 0 )
00941         quit();
00942 }
00943 
00944 KSessionManaged::KSessionManaged()
00945 {
00946     sessionClients()->remove( this );
00947     sessionClients()->append( this );
00948 }
00949 
00950 KSessionManaged::~KSessionManaged()
00951 {
00952     sessionClients()->remove( this );
00953 }
00954 
00955 bool KSessionManaged::saveState(QSessionManager&)
00956 {
00957     return true;
00958 }
00959 
00960 bool KSessionManaged::commitData(QSessionManager&)
00961 {
00962     return true;
00963 }
00964 
00965 
00966 void KApplication::disableSessionManagement() {
00967   bSessionManagement = false;
00968 }
00969 
00970 void KApplication::enableSessionManagement() {
00971   bSessionManagement = true;
00972   // Session management support in Qt/KDE is awfully broken.
00973   // If konqueror disables session management right after its startup,
00974   // and enables it later (preloading stuff), it won't be properly
00975   // saved on session shutdown.
00976   // I'm not actually sure why it doesn't work, but saveState()
00977   // doesn't seem to be called on session shutdown, possibly
00978   // because disabling session management after konqueror startup
00979   // disabled it somehow. Forcing saveState() here for this application
00980   // seems to fix it.
00981   if( mySmcConnection ) {
00982         SmcRequestSaveYourself( mySmcConnection, SmSaveLocal, False,
00983                 SmInteractStyleAny,
00984                 False, False );
00985 
00986     // flush the request
00987     IceFlush(SmcGetIceConnection(mySmcConnection));
00988   }
00989 }
00990 
00991 
00992 bool KApplication::requestShutDown(
00993     ShutdownConfirm confirm, ShutdownType sdtype, ShutdownMode sdmode )
00994 {
00995 #ifdef Q_WS_X11
00996     QApplication::syncX();
00997     /*  use ksmserver's dcop interface if necessary  */
00998     if ( confirm == ShutdownConfirmYes ||
00999          sdtype != ShutdownTypeDefault ||
01000          sdmode != ShutdownModeDefault )
01001     {
01002         QByteArray data;
01003         QDataStream arg(data, IO_WriteOnly);
01004         arg << (int)confirm << (int)sdtype << (int)sdmode;
01005     return dcopClient()->send( "ksmserver", "ksmserver",
01006                                    "logout(int,int,int)", data );
01007     }
01008 
01009     if ( mySmcConnection ) {
01010         // we already have a connection to the session manager, use it.
01011         SmcRequestSaveYourself( mySmcConnection, SmSaveBoth, True,
01012                 SmInteractStyleAny,
01013                 confirm == ShutdownConfirmNo, True );
01014 
01015     // flush the request
01016     IceFlush(SmcGetIceConnection(mySmcConnection));
01017         return true;
01018     }
01019 
01020     // open a temporary connection, if possible
01021 
01022     propagateSessionManager();
01023     QCString smEnv = ::getenv("SESSION_MANAGER");
01024     if (smEnv.isEmpty())
01025         return false;
01026 
01027     if (! tmpSmcConnection) {
01028     char cerror[256];
01029     char* myId = 0;
01030     char* prevId = 0;
01031     SmcCallbacks cb;
01032     tmpSmcConnection = SmcOpenConnection( 0, 0, 1, 0,
01033                           0, &cb,
01034                           prevId,
01035                           &myId,
01036                           255,
01037                           cerror );
01038     ::free( myId ); // it was allocated by C
01039     if (!tmpSmcConnection )
01040         return false;
01041     }
01042 
01043     SmcRequestSaveYourself( tmpSmcConnection, SmSaveBoth, True,
01044                 SmInteractStyleAny, False, True );
01045 
01046     // flush the request
01047     IceFlush(SmcGetIceConnection(tmpSmcConnection));
01048     return true;
01049 #else
01050     // FIXME(E): Implement for Qt Embedded
01051     return false;
01052 #endif
01053 }
01054 
01055 void KApplication::propagateSessionManager()
01056 {
01057     QCString fName = QFile::encodeName(locateLocal("socket", "KSMserver"));
01058     QCString display = ::getenv(DISPLAY);
01059     // strip the screen number from the display
01060     display.replace(QRegExp("\\.[0-9]+$"), "");
01061     int i;
01062     while( (i = display.find(':')) >= 0)
01063        display[i] = '_';
01064 
01065     fName += "_"+display;
01066     QCString smEnv = ::getenv("SESSION_MANAGER");
01067     bool check = smEnv.isEmpty();
01068     if ( !check && smModificationTime ) {
01069          QFileInfo info( fName );
01070          QTime current = info.lastModified().time();
01071          check = current > *smModificationTime;
01072     }
01073     if ( check ) {
01074         delete smModificationTime;
01075         QFile f( fName );
01076         if ( !f.open( IO_ReadOnly ) )
01077             return;
01078         QFileInfo info ( f );
01079         smModificationTime = new QTime( info.lastModified().time() );
01080         QTextStream t(&f);
01081         t.setEncoding( QTextStream::Latin1 );
01082         QString s = t.readLine();
01083         f.close();
01084         ::setenv( "SESSION_MANAGER", s.latin1(), true  );
01085     }
01086 }
01087 
01088 void KApplication::commitData( QSessionManager& sm )
01089 {
01090     d->session_save = true;
01091     bool canceled = false;
01092     for (KSessionManaged* it = sessionClients()->first();
01093          it && !canceled;
01094          it = sessionClients()->next() ) {
01095         canceled = !it->commitData( sm );
01096     }
01097     if ( canceled )
01098         sm.cancel();
01099 
01100     if ( sm.allowsInteraction() ) {
01101         QWidgetList done;
01102         QWidgetList *list = QApplication::topLevelWidgets();
01103         bool canceled = false;
01104         QWidget* w = list->first();
01105         while ( !canceled && w ) {
01106             if ( !w->testWState( WState_ForceHide ) && !w->inherits("KMainWindow") ) {
01107                 QCloseEvent e;
01108                 sendEvent( w, &e );
01109                 canceled = !e.isAccepted();
01110                 if ( !canceled )
01111                     done.append( w );
01112                 delete list; // one never knows...
01113                 list = QApplication::topLevelWidgets();
01114                 w = list->first();
01115             } else {
01116                 w = list->next();
01117             }
01118             while ( w && done.containsRef( w ) )
01119                 w = list->next();
01120         }
01121         delete list;
01122     }
01123 
01124 
01125     if ( !bSessionManagement )
01126         sm.setRestartHint( QSessionManager::RestartNever );
01127     else
01128     sm.setRestartHint( QSessionManager::RestartIfRunning );
01129     d->session_save = false;
01130 }
01131 
01132 void KApplication::saveState( QSessionManager& sm )
01133 {
01134     d->session_save = true;
01135 #ifndef Q_WS_QWS
01136     static bool firstTime = true;
01137     mySmcConnection = (SmcConn) sm.handle();
01138 
01139     if ( !bSessionManagement ) {
01140         sm.setRestartHint( QSessionManager::RestartNever );
01141     d->session_save = false;
01142         return;
01143     }
01144     else
01145         sm.setRestartHint( QSessionManager::RestartIfRunning );
01146 
01147 #if QT_VERSION < 0x030100
01148     {
01149         // generate a new session key
01150         timeval tv;
01151         gettimeofday( &tv, 0 );
01152         d->sessionKey  = QString::number( tv.tv_sec ) + "_" + QString::number(tv.tv_usec);
01153     }
01154 #endif
01155 
01156     if ( firstTime ) {
01157         firstTime = false;
01158     d->session_save = false;
01159         return; // no need to save the state.
01160     }
01161 
01162     // remove former session config if still existing, we want a new
01163     // and fresh one. Note that we do not delete the config file here,
01164     // this is done by the session manager when it executes the
01165     // discard commands. In fact it would be harmful to remove the
01166     // file here, as the session might be stored under a different
01167     // name, meaning the user still might need it eventually.
01168     if ( pSessionConfig ) {
01169         delete pSessionConfig;
01170         pSessionConfig = 0;
01171     }
01172 
01173     // tell the session manager about our new lifecycle
01174     QStringList restartCommand = sm.restartCommand();
01175 #if QT_VERSION < 0x030100
01176     restartCommand.clear();
01177     restartCommand  << argv()[0] << "-session" << sm.sessionId() << "-smkey" << d->sessionKey;
01178     sm.setRestartCommand( restartCommand );
01179 #endif
01180 
01181 
01182     QCString multiHead = getenv("KDE_MULTIHEAD");
01183     if (multiHead.lower() == "true") {
01184         // if multihead is enabled, we save our -display argument so that
01185         // we are restored onto the correct head... one problem with this
01186         // is that the display is hard coded, which means we cannot restore
01187         // to a different display (ie. if we are in a university lab and try,
01188         // try to restore a multihead session, our apps could be started on
01189         // someone else's display instead of our own)
01190         QCString displayname = getenv(DISPLAY);
01191         if (! displayname.isNull()) {
01192             // only store the command if we actually have a DISPLAY
01193             // environment variable
01194             restartCommand.append("-display");
01195             restartCommand.append(displayname);
01196         }
01197         sm.setRestartCommand( restartCommand );
01198     }
01199 
01200 
01201     // finally: do session management
01202     emit saveYourself(); // for compatibility
01203     bool canceled = false;
01204     for (KSessionManaged* it = sessionClients()->first();
01205          it && !canceled;
01206          it = sessionClients()->next() ) {
01207         canceled = !it->saveState( sm );
01208     }
01209 
01210     // if we created a new session config object, register a proper discard command
01211     if ( pSessionConfig ) {
01212         pSessionConfig->sync();
01213         QStringList discard;
01214         discard  << "rm" << locateLocal("config", sessionConfigName());
01215         sm.setDiscardCommand( discard );
01216     } else {
01217     sm.setDiscardCommand( "" );
01218     }
01219 
01220     if ( canceled )
01221         sm.cancel();
01222 #else
01223     // FIXME(E): Implement for Qt Embedded
01224 #endif
01225     d->session_save = false;
01226 }
01227 
01228 bool KApplication::sessionSaving() const
01229 {
01230     return d->session_save;
01231 }
01232 
01233 void KApplication::startKdeinit()
01234 {
01235   // Try to launch kdeinit.
01236   QString srv = KStandardDirs::findExe(QString::fromLatin1("kdeinit"));
01237   if (srv.isEmpty())
01238      srv = KStandardDirs::findExe(QString::fromLatin1("kdeinit"), KDEDIR+QString::fromLatin1("/bin"));
01239   if (srv.isEmpty())
01240      return;
01241   if (kapp && (Tty != kapp->type()))
01242     setOverrideCursor( Qt::waitCursor );
01243   my_system(QFile::encodeName(srv)+" --suicide");
01244   if (kapp && (Tty != kapp->type()))
01245     restoreOverrideCursor();
01246 }
01247 
01248 void KApplication::dcopFailure(const QString &msg)
01249 {
01250   static int failureCount = 0;
01251   failureCount++;
01252   if (failureCount == 1)
01253   {
01254      startKdeinit();
01255      return;
01256   }
01257   if (failureCount == 2)
01258   {
01259      QString msgStr(i18n("There was an error setting up inter-process\n"
01260                       "communications for KDE. The message returned\n"
01261                       "by the system was:\n\n"));
01262      msgStr += msg;
01263      msgStr += i18n("\n\nPlease check that the \"dcopserver\" program is running!");
01264 
01265      if (Tty != kapp->type())
01266      {
01267        QMessageBox::critical
01268          (
01269            kapp->mainWidget(),
01270            i18n("DCOP communications error (%1)").arg(kapp->caption()),
01271            msgStr,
01272            i18n("OK")
01273          );
01274      }
01275      else
01276      {
01277        fprintf(stderr, "%s\n", msgStr.local8Bit().data());
01278      }
01279 
01280      return;
01281   }
01282 }
01283 
01284 static const KCmdLineOptions qt_options[] =
01285 {
01286   //FIXME: Check if other options are specific to Qt/X11
01287 #ifdef Q_WS_X11
01288    { "display <displayname>", I18N_NOOP("Use the X-server display 'displayname'."), 0},
01289 #else
01290    { "display <displayname>", I18N_NOOP("Use the QWS display 'displayname'."), 0},
01291 #endif
01292    { "session <sessionId>", I18N_NOOP("Restore the application for the given 'sessionId'."), 0},
01293    { "cmap", I18N_NOOP("Causes the application to install a private color\nmap on an 8-bit display."), 0},
01294    { "ncols <count>", I18N_NOOP("Limits the number of colors allocated in the color\ncube on an 8-bit display, if the application is\nusing the QApplication::ManyColor color\nspecification."), 0},
01295    { "nograb", I18N_NOOP("tells Qt to never grab the mouse or the keyboard."), 0},
01296    { "dograb", I18N_NOOP("running under a debugger can cause an implicit\n-nograb, use -dograb to override."), 0},
01297    { "sync", I18N_NOOP("switches to synchronous mode for debugging."), 0},
01298    { "fn", 0, 0},
01299    { "font <fontname>", I18N_NOOP("defines the application font."), 0},
01300    { "bg", 0, 0},
01301    { "background <color>", I18N_NOOP("sets the default background color and an\napplication palette (light and dark shades are\ncalculated)."), 0},
01302    { "fg", 0, 0},
01303    { "foreground <color>", I18N_NOOP("sets the default foreground color."), 0},
01304    { "btn", 0, 0},
01305    { "button <color>", I18N_NOOP("sets the default button color."), 0},
01306    { "name <name>", I18N_NOOP("sets the application name."), 0},
01307    { "title <title>", I18N_NOOP("sets the application title (caption)."), 0},
01308 #ifdef Q_WS_X11
01309    { "visual TrueColor", I18N_NOOP("forces the application to use a TrueColor visual on\nan 8-bit display."), 0},
01310    { "inputstyle <inputstyle>", I18N_NOOP("sets XIM (X Input Method) input style. Possible\nvalues are onthespot, overthespot, offthespot and\nroot."), 0 },
01311    { "im <XIM server>", I18N_NOOP("set XIM server."),0},
01312    { "noxim", I18N_NOOP("disable XIM."), 0 },
01313 #endif
01314 #ifdef Q_WS_QWS
01315    { "qws", I18N_NOOP("forces the application to run as QWS Server."), 0},
01316 #endif
01317    { "reverse", I18N_NOOP("mirrors the whole layout of widgets."), 0},
01318    KCmdLineLastOption
01319 };
01320 
01321 static const KCmdLineOptions kde_options[] =
01322 {
01323    { "caption <caption>",       I18N_NOOP("Use 'caption' as name in the titlebar."), 0},
01324    { "icon <icon>",             I18N_NOOP("Use 'icon' as the application icon."), 0},
01325    { "miniicon <icon>",         I18N_NOOP("Use 'icon' as the icon in the titlebar."), 0},
01326    { "config <filename>",       I18N_NOOP("Use alternative configuration file."), 0},
01327    { "dcopserver <server>",     I18N_NOOP("Use the DCOP Server specified by 'server'."), 0},
01328    { "nocrashhandler",          I18N_NOOP("Disable crash handler, to get core dumps."), 0},
01329    { "waitforwm",          I18N_NOOP("Waits for a WM_NET compatible windowmanager."), 0},
01330    { "style <style>", I18N_NOOP("sets the application GUI style."), 0},
01331    { "geometry <geometry>", I18N_NOOP("sets the client geometry of the main widget."), 0},
01332 #if QT_VERSION < 0x030100
01333    { "smkey <sessionKey>", I18N_NOOP("Define a 'sessionKey' for the session id. Only valid with -session"), 0},
01334 #else
01335    { "smkey <sessionKey>", 0, 0}, // this option is obsolete and exists only to allow smooth upgrades from sessions
01336                                   // saved under Qt 3.0.x -- Qt 3.1.x includes the session key now automatically in
01337                   // the session id (Simon)
01338 #endif
01339    KCmdLineLastOption
01340 };
01341 
01342 void
01343 KApplication::addCmdLineOptions()
01344 {
01345    KCmdLineArgs::addCmdLineOptions(qt_options, "Qt", "qt");
01346    KCmdLineArgs::addCmdLineOptions(kde_options, "KDE", "kde");
01347 }
01348 
01349 void KApplication::parseCommandLine( )
01350 {
01351     KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
01352 
01353     if ( !args ) return;
01354 
01355     if (args->isSet("config"))
01356     {
01357         QString config = QString::fromLocal8Bit(args->getOption("config"));
01358         setConfigName(config);
01359     }
01360 
01361     if (args->isSet("style"))
01362     {
01363 
01364        QStringList styles = QStyleFactory::keys();
01365        QString reqStyle(args->getOption("style").lower());
01366 
01367        for (QStringList::ConstIterator it = styles.begin(); it != styles.end(); ++it)
01368            if ((*it).lower() == reqStyle)
01369            {
01370                d->overrideStyle = *it;
01371                break;
01372            }
01373 
01374        if (d->overrideStyle.isEmpty())
01375           fprintf(stderr, "%s", i18n("The style %1 was not found\n").arg(reqStyle).local8Bit().data());
01376     }
01377 
01378     if (args->isSet("caption"))
01379     {
01380        aCaption = QString::fromLocal8Bit(args->getOption("caption"));
01381     }
01382 
01383     if (args->isSet("miniicon"))
01384     {
01385        const char *tmp = args->getOption("miniicon");
01386        aMiniIconPixmap = SmallIcon(tmp);
01387        aMiniIconName = tmp;
01388     }
01389 
01390     if (args->isSet("icon"))
01391     {
01392        const char *tmp = args->getOption("icon");
01393        aIconPixmap = DesktopIcon( tmp );
01394        aIconName = tmp;
01395        if (aMiniIconPixmap.isNull())
01396        {
01397           aMiniIconPixmap = SmallIcon( tmp );
01398           aMiniIconName = tmp;
01399        }
01400     }
01401 
01402     bool nocrashhandler = (getenv("KDE_DEBUG") != NULL);
01403     if (!nocrashhandler && args->isSet("crashhandler"))
01404     {
01405         // set default crash handler / set emergency save function to nothing
01406         KCrash::setCrashHandler(KCrash::defaultCrashHandler);
01407         KCrash::setEmergencySaveFunction(NULL);
01408 
01409         KCrash::setApplicationName(QString(args->appName()));
01410     }
01411 
01412 #ifdef Q_WS_X11
01413     if ( args->isSet( "waitforwm" ) ) {
01414         Atom type;
01415         (void) desktop(); // trigger desktop creation, we need PropertyNotify events for the root window
01416         int format;
01417         unsigned long length, after;
01418         unsigned char *data;
01419         while ( XGetWindowProperty( qt_xdisplay(), qt_xrootwin(), atom_NetSupported,
01420                     0, 1, false, AnyPropertyType, &type, &format,
01421                                     &length, &after, &data ) != Success || !length ) {
01422             if ( data )
01423                 XFree( data );
01424             XEvent event;
01425             XWindowEvent( qt_xdisplay(), qt_xrootwin(), PropertyChangeMask, &event );
01426         }
01427         if ( data )
01428             XFree( data );
01429     }
01430 #else
01431     // FIXME(E): Implement for Qt Embedded
01432 #endif
01433 
01434     if (args->isSet("geometry"))
01435     {
01436         d->geometry_arg = args->getOption("geometry");
01437     }
01438 
01439     if (args->isSet("smkey"))
01440     {
01441         d->sessionKey = args->getOption("smkey");
01442     }
01443 
01444 }
01445 
01446 QString KApplication::geometryArgument() const
01447 {
01448     return d->geometry_arg;
01449 }
01450 
01451 QPixmap KApplication::icon() const
01452 {
01453   if( aIconPixmap.isNull()) {
01454       KApplication *that = const_cast<KApplication *>(this);
01455       that->aIconPixmap = DesktopIcon( instanceName() );
01456   }
01457   return aIconPixmap;
01458 }
01459 
01460 QString KApplication::iconName() const
01461 {
01462   return aIconName.isNull() ? (QString)instanceName() : aIconName;
01463 }
01464 
01465 QPixmap KApplication::miniIcon() const
01466 {
01467   if (aMiniIconPixmap.isNull()) {
01468       KApplication *that = const_cast<KApplication *>(this);
01469       that->aMiniIconPixmap = SmallIcon( instanceName() );
01470   }
01471   return aMiniIconPixmap;
01472 }
01473 
01474 QString KApplication::miniIconName() const
01475 {
01476   return aMiniIconName.isNull() ? (QString)instanceName() : aMiniIconName;
01477 }
01478 
01479 extern void kDebugCleanup();
01480 
01481 KApplication::~KApplication()
01482 {
01483   delete d->m_KAppDCOPInterface;
01484 
01485   // First call the static deleters and then call KLibLoader::cleanup()
01486   // The static deleters may delete libraries for which they need KLibLoader.
01487   // KLibLoader will take care of the remaining ones.
01488   KGlobal::deleteStaticDeleters();
01489   KLibLoader::cleanUp();
01490 
01491   delete smw;
01492 
01493   // close down IPC
01494   delete s_DCOPClient;
01495   s_DCOPClient = 0L;
01496 
01497   KProcessController::deref();
01498 
01499   if ( d->oldXErrorHandler != NULL )
01500       XSetErrorHandler( d->oldXErrorHandler );
01501   if ( d->oldXIOErrorHandler != NULL )
01502       XSetIOErrorHandler( d->oldXIOErrorHandler );
01503   if ( d->oldIceIOErrorHandler != NULL )
01504       IceSetIOErrorHandler( d->oldIceIOErrorHandler );
01505 
01506   delete d;
01507   KApp = 0;
01508 
01509 #ifndef Q_WS_QWS
01510   mySmcConnection = 0;
01511   delete smModificationTime;
01512   smModificationTime = 0;
01513 
01514   // close the temporary smc connection
01515   if (tmpSmcConnection) {
01516       SmcCloseConnection( tmpSmcConnection, 0, 0 );
01517       tmpSmcConnection = 0;
01518   }
01519 #else
01520   // FIXME(E): Implement for Qt Embedded
01521 #endif
01522 }
01523 
01524 
01525 #ifdef Q_WS_X11
01526 class KAppX11HackWidget: public QWidget
01527 {
01528 public:
01529     bool publicx11Event( XEvent * e) { return x11Event( e ); }
01530 };
01531 #endif
01532 
01533 
01534 
01535 static bool kapp_block_user_input = false;
01536 
01537 void KApplication::dcopBlockUserInput( bool b )
01538 {
01539     kapp_block_user_input = b;
01540 }
01541 
01542 #ifdef Q_WS_X11
01543 bool KApplication::x11EventFilter( XEvent *_event )
01544 {
01545     switch ( _event->type ) {
01546         case ButtonPress:
01547         case XKeyPress:
01548         {
01549         if( _event->type == ButtonPress )
01550         qt_x_user_time = _event->xbutton.time;
01551         else // KeyPress
01552         qt_x_user_time = _event->xkey.time;
01553         QWidget* w = activeWindow();
01554         if( w ) {
01555             XChangeProperty( qt_xdisplay(), w->winId(), kde_net_wm_user_time, XA_CARDINAL,
01556                 32, PropModeReplace, (unsigned char*)&qt_x_user_time, 1 );
01557             timeval tv;
01558         gettimeofday( &tv, NULL );
01559         unsigned long now = tv.tv_sec * 10 + tv.tv_usec / 100000;
01560         XChangeProperty(qt_xdisplay(), w->winId(),
01561                 atom_KdeNetUserTime, XA_CARDINAL,
01562                 32, PropModeReplace, (unsigned char *)&now, 1);
01563         }
01564     }
01565     break;
01566         case ClientMessage:
01567         {
01568 #if KDE_IS_VERSION( 3, 2, 91 )
01569 #warning This should be already in Qt, check.
01570 #endif
01571         // Workaround for focus stealing prevention not working when dragging e.g. text from KWrite
01572         // to KDesktop -> the dialog asking for filename doesn't get activated. This is because
01573         // Qt-3.2.x doesn't have concept of qt_x_user_time at all, and Qt-3.3.0b1 passes the timestamp
01574         // in the XdndDrop message in incorrect field (and doesn't update qt_x_user_time either).
01575         // Patch already sent, future Qt version should have this fixed.
01576             if( _event->xclient.message_type == kde_xdnd_drop )
01577                 { // if the message is XdndDrop
01578                 if( _event->xclient.data.l[ 1 ] == 1 << 24     // and it's broken the way it's in Qt-3.2.x
01579                     && _event->xclient.data.l[ 2 ] == 0
01580                     && _event->xclient.data.l[ 4 ] == 0
01581                     && _event->xclient.data.l[ 3 ] != 0 )
01582                     {
01583                     if( qt_x_user_time == 0 
01584                         || ( _event->xclient.data.l[ 3 ] - qt_x_user_time ) < 100000U )
01585                         { // and the timestamp looks reasonable
01586                         qt_x_user_time = _event->xclient.data.l[ 3 ]; // update our qt_x_user_time from it
01587                         }
01588                     }
01589                 else // normal DND, only needed until Qt updates qt_x_user_time from XdndDrop
01590                     {
01591                     if( qt_x_user_time == 0
01592                         || ( _event->xclient.data.l[ 2 ] - qt_x_user_time ) < 100000U )
01593                         { // the timestamp looks reasonable
01594                         qt_x_user_time = _event->xclient.data.l[ 2 ]; // update our qt_x_user_time from it
01595                         }
01596                     }
01597                 }
01598         }
01599     default: break;
01600     }
01601 
01602     if ( kapp_block_user_input ) {
01603         switch ( _event->type  ) {
01604         case ButtonPress:
01605         case ButtonRelease:
01606         case XKeyPress:
01607         case XKeyRelease:
01608         case MotionNotify:
01609             return true;
01610         default:
01611             break;
01612         }
01613     }
01614 
01615     if (x11Filter) {
01616         for (QWidget *w=x11Filter->first(); w; w=x11Filter->next()) {
01617             if (((KAppX11HackWidget*) w)->publicx11Event(_event))
01618                 return true;
01619         }
01620     }
01621 
01622 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
01623     if ((_event->type == ClientMessage) &&
01624             (_event->xclient.message_type == kipcCommAtom))
01625     {
01626         XClientMessageEvent *cme = (XClientMessageEvent *) _event;
01627 
01628         int id = cme->data.l[0];
01629         int arg = cme->data.l[1];
01630         if ((id < 32) && (kipcEventMask & (1 << id)))
01631         {
01632             switch (id)
01633             {
01634             case KIPC::StyleChanged:
01635                 KGlobal::config()->reparseConfiguration();
01636                 kdisplaySetStyle();
01637                 break;
01638 
01639             case KIPC::ToolbarStyleChanged:
01640                 KGlobal::config()->reparseConfiguration();
01641                 if (useStyles)
01642                     emit toolbarAppearanceChanged(arg);
01643                 break;
01644 
01645             case KIPC::PaletteChanged:
01646                 KGlobal::config()->reparseConfiguration();
01647                 kdisplaySetPalette();
01648                 break;
01649 
01650             case KIPC::FontChanged:
01651                 KGlobal::config()->reparseConfiguration();
01652                 KGlobalSettings::rereadFontSettings();
01653                 kdisplaySetFont();
01654                 break;
01655 
01656             case KIPC::BackgroundChanged:
01657                 emit backgroundChanged(arg);
01658                 break;
01659 
01660             case KIPC::SettingsChanged:
01661                 KGlobal::config()->reparseConfiguration();
01662                 if (arg == SETTINGS_PATHS)
01663                     KGlobalSettings::rereadPathSettings();
01664                 else if (arg == SETTINGS_MOUSE)
01665                     KGlobalSettings::rereadMouseSettings();
01666                 propagateSettings((SettingsCategory)arg);
01667                 break;
01668 
01669             case KIPC::IconChanged:
01670                 QPixmapCache::clear();
01671                 KGlobal::config()->reparseConfiguration();
01672                 KGlobal::instance()->newIconLoader();
01673                 emit iconChanged(arg);
01674                 break;
01675 
01676             case KIPC::ClipboardConfigChanged:
01677                 KClipboardSynchronizer::newConfiguration(arg);
01678                 break;
01679             }
01680         }
01681         else if (id >= 32)
01682         {
01683             emit kipcMessage(id, arg);
01684         }
01685         return true;
01686     }
01687 #endif // Q_WS_X11 && ! K_WS_QTONLY
01688     return false;
01689 }
01690 #endif
01691 
01692 void KApplication::updateUserTimestamp( unsigned long time )
01693 {
01694 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
01695     if( time == 0 )
01696     { // get current X timestamp
01697         Window w = XCreateSimpleWindow( qt_xdisplay(), qt_xrootwin(), 0, 0, 1, 1, 0, 0, 0 );
01698         XSelectInput( qt_xdisplay(), w, PropertyChangeMask );
01699         unsigned char data[ 1 ];
01700         XChangeProperty( qt_xdisplay(), w, XA_ATOM, XA_ATOM, 8, PropModeAppend, data, 1 );
01701         XEvent ev;
01702         XWindowEvent( qt_xdisplay(), w, PropertyChangeMask, &ev );
01703         time = ev.xproperty.time;
01704         XDestroyWindow( qt_xdisplay(), w );
01705     }
01706     if( time - qt_x_user_time < 1000000000U ) // check time > qt_x_user_time, handle wrapping
01707         qt_x_user_time = time;
01708 #endif
01709 }
01710 
01711 unsigned long KApplication::userTimestamp() const
01712 {
01713     return qt_x_user_time;
01714 }
01715 
01716 void KApplication::invokeEditSlot( const char *slot )
01717 {
01718   QObject *object = focusWidget();
01719   if( !object )
01720     return;
01721 
01722   QMetaObject *meta = object->metaObject();
01723 
01724   int idx = meta->findSlot( slot + 1, true );
01725   if( idx < 0 )
01726     return;
01727 
01728   object->qt_invoke( idx, 0 );
01729 }
01730 
01731 void KApplication::addKipcEventMask(int id)
01732 {
01733     if (id >= 32)
01734     {
01735         kdDebug(101) << "Cannot use KIPC event mask for message IDs >= 32\n";
01736         return;
01737     }
01738     kipcEventMask |= (1 << id);
01739 }
01740 
01741 void KApplication::removeKipcEventMask(int id)
01742 {
01743     if (id >= 32)
01744     {
01745         kdDebug(101) << "Cannot use KIPC event mask for message IDs >= 32\n";
01746         return;
01747     }
01748     kipcEventMask &= ~(1 << id);
01749 }
01750 
01751 void KApplication::enableStyles()
01752 {
01753     if (!useStyles)
01754     {
01755         useStyles = true;
01756         applyGUIStyle();
01757     }
01758 }
01759 
01760 void KApplication::disableStyles()
01761 {
01762     useStyles = false;
01763 }
01764 
01765 void KApplication::applyGUIStyle()
01766 {
01767     if ( !useStyles ) return;
01768 
01769     KConfigGroup pConfig (KGlobal::config(), "General");
01770     QString defaultStyle = KStyle::defaultStyle();
01771     QString styleStr = pConfig.readEntry("widgetStyle", defaultStyle);
01772 
01773     if (d->overrideStyle.isEmpty()) {
01774       // ### add check wether we already use the correct style to return then
01775       // (workaround for Qt misbehavior to avoid double style initialization)
01776 
01777       QStyle* sp = QStyleFactory::create( styleStr );
01778 
01779       // If there is no default style available, try falling back any available style
01780       if ( !sp && styleStr != defaultStyle)
01781           sp = QStyleFactory::create( defaultStyle );
01782       if ( !sp )
01783           sp = QStyleFactory::create( *(QStyleFactory::keys().begin()) );
01784       setStyle(sp);
01785     }
01786     else
01787         setStyle(d->overrideStyle);
01788     // Reread palette from config file.
01789     kdisplaySetPalette();
01790 }
01791 
01792 QString KApplication::caption() const
01793 {
01794   // Caption set from command line ?
01795   if( !aCaption.isNull() )
01796         return aCaption;
01797   else
01798       // We have some about data ?
01799       if ( KGlobal::instance()->aboutData() )
01800         return KGlobal::instance()->aboutData()->programName();
01801       else
01802         // Last resort : application name
01803         return name();
01804 }
01805 
01806 
01807 //
01808 // 1999-09-20: Espen Sand
01809 // An attempt to simplify consistent captions.
01810 //
01811 QString KApplication::makeStdCaption( const QString &userCaption,
01812                                       bool withAppName, bool modified ) const
01813 {
01814   QString s = userCaption.isEmpty() ? caption() : userCaption;
01815 
01816   // If the document is modified, add '[modified]'.
01817   if (modified)
01818       s += QString::fromUtf8(" [") + i18n("modified") + QString::fromUtf8("]");
01819 
01820   if ( !userCaption.isEmpty() ) {
01821       // Add the application name if:
01822       // User asked for it, it's not a duplication  and the app name (caption()) is not empty
01823       if ( withAppName && !caption().isNull() && !userCaption.endsWith(caption())  )
01824       s += QString::fromUtf8(" - ") + caption();
01825   }
01826 
01827   return s;
01828 }
01829 
01830 QPalette KApplication::createApplicationPalette()
01831 {
01832     KConfig *config = KGlobal::config();
01833     KConfigGroupSaver saver( config, "General" );
01834     return createApplicationPalette( config, KGlobalSettings::contrast() );
01835 }
01836 
01837 QPalette KApplication::createApplicationPalette( KConfig *config, int contrast_ )
01838 {
01839     QColor kde31Background( 238, 238, 230 );
01840     QColor kde31Beige( 255,221,118 );
01841 
01842     QColor kde31Button;
01843     if ( QPixmap::defaultDepth() > 8 )
01844       kde31Button.setRgb( 238, 234, 222 );
01845     else
01846       kde31Button.setRgb( 220, 220, 220 );
01847 
01848     QColor kde31Link( 0, 0, 192 );
01849     QColor kde31VisitedLink( 128, 0,128 );
01850 
01851     QColor background = config->readColorEntry( "background", &kde31Background );
01852     QColor foreground = config->readColorEntry( "foreground", &black );
01853     QColor button = config->readColorEntry( "buttonBackground", &kde31Button );
01854     QColor buttonText = config->readColorEntry( "buttonForeground", &foreground );
01855     QColor highlight = config->readColorEntry( "selectBackground", &kde31Beige );
01856     QColor highlightedText = config->readColorEntry( "selectForeground", &black );
01857     QColor base = config->readColorEntry( "windowBackground", &white );
01858     QColor baseText = config->readColorEntry( "windowForeground", &black );
01859     QColor link = config->readColorEntry( "linkColor", &kde31Link );
01860     QColor visitedLink = config->readColorEntry( "visitedLinkColor", &kde31VisitedLink );
01861 
01862     int highlightVal, lowlightVal;
01863     highlightVal = 100 + (2*contrast_+4)*16/10;
01864     lowlightVal = 100 + (2*contrast_+4)*10;
01865 
01866     QColor disfg = foreground;
01867 
01868     int h, s, v;
01869     disfg.hsv( &h, &s, &v );
01870     if (v > 128)
01871     // dark bg, light fg - need a darker disabled fg
01872     disfg = disfg.dark(lowlightVal);
01873     else if (disfg != black)
01874     // light bg, dark fg - need a lighter disabled fg - but only if !black
01875     disfg = disfg.light(highlightVal);
01876     else
01877     // black fg - use darkgray disabled fg
01878     disfg = Qt::darkGray;
01879 
01880 
01881     QColorGroup disabledgrp(disfg, background,
01882                             background.light(highlightVal),
01883                             background.dark(lowlightVal),
01884                             background.dark(120),
01885                             background.dark(120), base);
01886 
01887     QColorGroup colgrp(foreground, background, background.light(highlightVal),
01888                        background.dark(lowlightVal),
01889                        background.dark(120),
01890                        baseText, base);
01891 
01892     int inlowlightVal = lowlightVal-25;
01893     if(inlowlightVal < 120)
01894         inlowlightVal = 120;
01895 
01896     colgrp.setColor(QColorGroup::Highlight, highlight);
01897     colgrp.setColor(QColorGroup::HighlightedText, highlightedText);
01898     colgrp.setColor(QColorGroup::Button, button);
01899     colgrp.setColor(QColorGroup::ButtonText, buttonText);
01900     colgrp.setColor(QColorGroup::Midlight, background.light(110));
01901     colgrp.setColor(QColorGroup::Link, link);
01902     colgrp.setColor(QColorGroup::LinkVisited, visitedLink);
01903 
01904     disabledgrp.setColor(QColorGroup::Button, button);
01905 
01906     QColor disbtntext = buttonText;
01907     disbtntext.hsv( &h, &s, &v );
01908     if (v > 128)
01909     // dark button, light buttonText - need a darker disabled buttonText
01910     disbtntext = disbtntext.dark(lowlightVal);
01911     else if (disbtntext != black)
01912     // light buttonText, dark button - need a lighter disabled buttonText - but only if !black
01913     disbtntext = disbtntext.light(highlightVal);
01914     else
01915     // black button - use darkgray disabled buttonText
01916     disbtntext = Qt::darkGray;
01917 
01918     disabledgrp.setColor(QColorGroup::ButtonText, disbtntext);
01919     disabledgrp.setColor(QColorGroup::Midlight, background.light(110));
01920     disabledgrp.setColor(QColorGroup::Highlight, highlight.dark(120));
01921     disabledgrp.setColor(QColorGroup::Link, link);
01922     disabledgrp.setColor(QColorGroup::LinkVisited, visitedLink);
01923 
01924     return QPalette(colgrp, disabledgrp, colgrp);
01925 }
01926 
01927 
01928 void KApplication::kdisplaySetPalette()
01929 {
01930     QApplication::setPalette( createApplicationPalette(), true);
01931     emit kdisplayPaletteChanged();
01932     emit appearanceChanged();
01933 }
01934 
01935 
01936 void KApplication::kdisplaySetFont()
01937 {
01938     QApplication::setFont(KGlobalSettings::generalFont(), true);
01939     QApplication::setFont(KGlobalSettings::menuFont(), true, "QMenuBar");
01940     QApplication::setFont(KGlobalSettings::menuFont(), true, "QPopupMenu");
01941     QApplication::setFont(KGlobalSettings::menuFont(), true, "KPopupTitle");
01942 
01943     // "patch" standard QStyleSheet to follow our fonts
01944     QStyleSheet* sheet = QStyleSheet::defaultSheet();
01945     sheet->item ("pre")->setFontFamily (KGlobalSettings::fixedFont().family());
01946     sheet->item ("code")->setFontFamily (KGlobalSettings::fixedFont().family());
01947     sheet->item ("tt")->setFontFamily (KGlobalSettings::fixedFont().family());
01948 
01949     emit kdisplayFontChanged();
01950     emit appearanceChanged();
01951 }
01952 
01953 
01954 void KApplication::kdisplaySetStyle()
01955 {
01956     if (useStyles)
01957     {
01958         applyGUIStyle();
01959         emit kdisplayStyleChanged();
01960         emit appearanceChanged();
01961     }
01962 }
01963 
01964 
01965 void KApplication::propagateSettings(SettingsCategory arg)
01966 {
01967     KConfigBase* config = KGlobal::config();
01968     KConfigGroupSaver saver( config, "KDE" );
01969 
01970     int num = config->readNumEntry("CursorBlinkRate", QApplication::cursorFlashTime());
01971     if (num < 200)
01972         num = 200;
01973     if (num > 2000)
01974         num = 2000;
01975     QApplication::setCursorFlashTime(num);
01976     num = config->readNumEntry("DoubleClickInterval", QApplication::doubleClickInterval());
01977     QApplication::setDoubleClickInterval(num);
01978     num = config->readNumEntry("StartDragTime", QApplication::startDragTime());
01979     QApplication::setStartDragTime(num);
01980     num = config->readNumEntry("StartDragDist", QApplication::startDragDistance());
01981     QApplication::setStartDragDistance(num);
01982     num = config->readNumEntry("WheelScrollLines", QApplication::wheelScrollLines());
01983     QApplication::setWheelScrollLines(num);
01984 
01985     bool b = config->readBoolEntry("EffectAnimateMenu", false);
01986     QApplication::setEffectEnabled( Qt::UI_AnimateMenu, b);
01987     b = config->readBoolEntry("EffectFadeMenu", false);
01988     QApplication::setEffectEnabled( Qt::UI_FadeMenu, b);
01989     b = config->readBoolEntry("EffectAnimateCombo", false);
01990     QApplication::setEffectEnabled( Qt::UI_AnimateCombo, b);
01991     b = config->readBoolEntry("EffectAnimateTooltip", false);
01992     QApplication::setEffectEnabled( Qt::UI_AnimateTooltip, b);
01993     b = config->readBoolEntry("EffectFadeTooltip", false);
01994     QApplication::setEffectEnabled( Qt::UI_FadeTooltip, b);
01995     b = !config->readBoolEntry("EffectNoTooltip", false);
01996     QToolTip::setGloballyEnabled( b );
01997 
01998     emit settingsChanged(arg);
01999 }
02000 
02001 void KApplication::installKDEPropertyMap()
02002 {
02003 #ifndef QT_NO_SQL
02004     static bool installed = false;
02005     if (installed) return;
02006     installed = true;
02013     // QSqlPropertyMap takes ownership of the new default map.
02014     QSqlPropertyMap *kdeMap = new QSqlPropertyMap;
02015     kdeMap->insert( "KColorButton", "color" );
02016     kdeMap->insert( "KComboBox", "currentItem" );
02017     kdeMap->insert( "KDatePicker", "date" );
02018     kdeMap->insert( "KEditListBox", "currentItem" );
02019     kdeMap->insert( "KFontCombo", "family" );
02020     kdeMap->insert( "KFontRequester", "font" );
02021     kdeMap->insert( "KFontChooser", "font" );
02022     kdeMap->insert( "KHistoryCombo", "currentItem" );
02023     kdeMap->insert( "KListBox", "currentItem" );
02024     kdeMap->insert( "KLineEdit", "text" );
02025     kdeMap->insert( "KRestrictedLine", "text" );
02026     kdeMap->insert( "KSqueezedTextLabel", "text" );
02027     kdeMap->insert( "KTextBrowser", "source" );
02028     kdeMap->insert( "KTextEdit", "text" );
02029     kdeMap->insert( "KURLRequester", "url" );
02030     kdeMap->insert( "KPasswordEdit", "password" );
02031     kdeMap->insert( "KIntNumInput", "value" );
02032     kdeMap->insert( "KIntSpinBox", "value" );
02033     kdeMap->insert( "KDoubleNumInput", "value" );
02034     #if QT_VERSION < 0x030200
02035       kdeMap->insert( "QRadioButton", "checked" );
02036     #endif
02037     //#if QT_VERSION < 0x030300
02038       // Temp til fixed in QT then enable ifdef with the correct version num
02039       kdeMap->insert( "QTabWidget", "currentPage" );
02040     //#endif
02041     QSqlPropertyMap::installDefaultMap( kdeMap );
02042 #endif
02043 }
02044 
02045 void KApplication::invokeHelp( const QString& anchor,
02046                                const QString& _appname) const
02047 {
02048     return invokeHelp( anchor, _appname, "" );
02049 }
02050 
02051 void KApplication::invokeHelp( const QString& anchor,
02052                                const QString& _appname,
02053                                const QCString& startup_id ) const
02054 {
02055    QString url;
02056    QString appname;
02057    if (_appname.isEmpty())
02058      appname = name();
02059    else
02060      appname = _appname;
02061 
02062    if (!anchor.isEmpty())
02063      url = QString("help:/%1?anchor=%2").arg(appname).arg(anchor);
02064    else
02065      url = QString("help:/%1/index.html").arg(appname);
02066 
02067    QString error;
02068    if ( !dcopClient()->isApplicationRegistered("khelpcenter") )
02069    {
02070        if (startServiceByDesktopName("khelpcenter", url, &error, 0, 0, startup_id, true))
02071        {
02072            kdWarning() << "Could not launch help:\n" << error << endl;
02073            return;
02074        }
02075    }
02076    else
02077        DCOPRef( "khelpcenter", "KHelpCenterIface" ).send( "openUrl", url, startup_id );
02078 }
02079 
02080 void KApplication::invokeHTMLHelp( const QString& _filename, const QString& topic ) const
02081 {
02082    kdWarning() << "invoking HTML help is deprecated! use docbook and invokeHelp!\n";
02083 
02084    QString filename;
02085 
02086    if( _filename.isEmpty() )
02087      filename = QString(name()) + "/index.html";
02088    else
02089      filename = _filename;
02090 
02091    QString url;
02092    if (!topic.isEmpty())
02093      url = QString("help:/%1#%2").arg(filename).arg(topic);
02094    else
02095      url = QString("help:/%1").arg(filename);
02096 
02097    QString error;
02098    if ( !dcopClient()->isApplicationRegistered("khelpcenter") )
02099    {
02100        if (startServiceByDesktopName("khelpcenter", url, &error, 0, 0, "", true))
02101        {
02102            kdWarning() << "Could not launch help:\n" << error << endl;
02103            return;
02104        }
02105    }
02106    else
02107        DCOPRef( "khelpcenter", "KHelpCenterIface" ).send( "openUrl", url );
02108 }
02109 
02110 
02111 void KApplication::invokeMailer(const QString &address, const QString &subject)
02112 {
02113     return invokeMailer(address,subject,"");
02114 }
02115 
02116 void KApplication::invokeMailer(const QString &address, const QString &subject, const QCString& startup_id)
02117 {
02118    invokeMailer(address, QString::null, QString::null, subject, QString::null, QString::null,
02119        QStringList(), startup_id );
02120 }
02121 
02122 void KApplication::invokeMailer(const KURL &mailtoURL)
02123 {
02124     return invokeMailer( mailtoURL, "" );
02125 }
02126 
02127 void KApplication::invokeMailer(const KURL &mailtoURL, const QCString& startup_id )
02128 {
02129    QString address = KURL::decode_string(mailtoURL.path()), subject, cc, bcc, body, attach;
02130    QStringList queries = QStringList::split('&', mailtoURL.query().mid(1));
02131    for (QStringList::Iterator it = queries.begin(); it != queries.end(); ++it)
02132    {
02133      QString q = (*it).lower();
02134      if (q.startsWith("subject="))
02135        subject = KURL::decode_string((*it).mid(8));
02136      else
02137      if (q.startsWith("cc="))
02138        cc = KURL::decode_string((*it).mid(3));
02139      else
02140      if (q.startsWith("bcc="))
02141        bcc = KURL::decode_string((*it).mid(4));
02142      else
02143      if (q.startsWith("body="))
02144        body = KURL::decode_string((*it).mid(5));
02145      //else
02146      //  if (q.startsWith("attach="))
02147      //    attach = KURL::decode_string((*it).mid(7));
02148    }
02149 
02150    invokeMailer( address, cc, bcc, subject, body, QString::null, QStringList(), startup_id );
02151 }
02152 
02153 void KApplication::invokeMailer(const QString &to, const QString &cc, const QString &bcc,
02154                                 const QString &subject, const QString &body,
02155                                 const QString & messageFile, const QStringList &attachURLs)
02156 {
02157     return invokeMailer(to,cc,bcc,subject,body,messageFile,attachURLs,"");
02158 }
02159 
02160 void KApplication::invokeMailer(const QString &to, const QString &cc, const QString &bcc,
02161                                 const QString &subject, const QString &body,
02162                                 const QString & /*messageFile TODO*/, const QStringList &attachURLs,
02163                                 const QCString& startup_id )
02164 {
02165    KConfig config("emaildefaults");
02166 
02167    config.setGroup("Defaults");
02168    QString group = config.readEntry("Profile","Default");
02169 
02170    config.setGroup( QString("PROFILE_%1").arg(group) );
02171    QString command = config.readPathEntry("EmailClient");
02172 
02173    if (command.isEmpty() || command == QString::fromLatin1("kmail")
02174        || command.endsWith("/kmail"))
02175      command = QString::fromLatin1("kmail --composer -s %s -c %c -b %b --body %B --attach %A %t");
02176 
02177    // TODO: Take care of the preferred terminal app (instead of hardcoding
02178    // Konsole), this will probably require a rewrite of the configurable
02179    // terminal client option because the placeholder for the program which
02180    // has to be executed by the terminal has to be supplied (e.g. something
02181    // like '/opt/kde2/bin/konsole -e %p'). - Frerich
02182    if (config.readBoolEntry("TerminalClient", false))
02183       command = "konsole -e " + command;
02184 
02185    QStringList cmdTokens = KShell::splitArgs(command);
02186    QString cmd = cmdTokens[0];
02187    cmdTokens.remove(cmdTokens.begin());
02188 
02189    QMap<QChar, QString> keyMap;
02190    keyMap.insert('t', to);
02191    keyMap.insert('s', subject);
02192    keyMap.insert('c', cc);
02193    keyMap.insert('b', bcc);
02194    keyMap.insert('B', body);
02195 
02196    for (QStringList::Iterator it = cmdTokens.begin(); it != cmdTokens.end(); )
02197    {
02198      if (*it == "%A")
02199      {
02200          if (it == cmdTokens.begin()) // better safe than sorry ...
02201              continue;
02202          QStringList::ConstIterator urlit = attachURLs.begin();
02203          QStringList::ConstIterator urlend = attachURLs.end();
02204          if ( urlit != urlend )
02205          {
02206              QStringList::Iterator previt = it;
02207              --previt;
02208              *it = *urlit;
02209              ++it;
02210              while ( ++urlit != urlend )
02211              {
02212                  cmdTokens.insert( it, *previt );
02213                  cmdTokens.insert( it, *urlit );
02214              }
02215          } else {
02216              --it;
02217              it = cmdTokens.remove( cmdTokens.remove( it ) );
02218          }
02219      } else {
02220          *it = KMacroExpander::expandMacros(*it, keyMap);
02221          ++it;
02222      }
02223    }
02224 
02225    QString error;
02226    // TODO this should check if cmd has a .desktop file, and use data from it, together
02227    // with sending more ASN data
02228    if (kdeinitExec(cmd, cmdTokens, &error, NULL, startup_id ))
02229       kdWarning() << "Could not launch mail client:\n" << error << endl;
02230 }
02231 
02232 
02233 void KApplication::invokeBrowser( const QString &url )
02234 {
02235     return invokeBrowser( url, "" );
02236 }
02237 
02238 void KApplication::invokeBrowser( const QString &url, const QCString& startup_id )
02239 {
02240    QString error;
02241 
02242    if (startServiceByDesktopName("kfmclient", url, &error, 0, 0, startup_id, true))
02243    {
02244       kdWarning() << "Could not launch browser:\n" << error << endl;
02245       return;
02246    }
02247 }
02248 
02249 void KApplication::cut()
02250 {
02251   invokeEditSlot( SLOT( cut() ) );
02252 }
02253 
02254 void KApplication::copy()
02255 {
02256   invokeEditSlot( SLOT( copy() ) );
02257 }
02258 
02259 void KApplication::paste()
02260 {
02261   invokeEditSlot( SLOT( paste() ) );
02262 }
02263 
02264 void KApplication::clear()
02265 {
02266   invokeEditSlot( SLOT( clear() ) );
02267 }
02268 
02269 void KApplication::selectAll()
02270 {
02271   invokeEditSlot( SLOT( selectAll() ) );
02272 }
02273 
02274 QCString
02275 KApplication::launcher()
02276 {
02277    return "klauncher";
02278 }
02279 
02280 static int
02281 startServiceInternal( const QCString &function,
02282               const QString& _name, const QStringList &URLs,
02283               QString *error, QCString *dcopService, int *pid, const QCString& startup_id, bool noWait )
02284 {
02285    struct serviceResult
02286    {
02287       int result;
02288       QCString dcopName;
02289       QString error;
02290       pid_t pid;
02291    };
02292 
02293    // Register app as able to send DCOP messages
02294    DCOPClient *dcopClient;
02295    if (kapp)
02296       dcopClient = kapp->dcopClient();
02297    else
02298       dcopClient = new DCOPClient;
02299 
02300    if (!dcopClient->isAttached())
02301    {
02302       if (!dcopClient->attach())
02303       {
02304          if (error)
02305             *error = i18n("Could not register with DCOP.\n");
02306          return -1;
02307       }
02308    }
02309    QByteArray params;
02310    QDataStream stream(params, IO_WriteOnly);
02311    stream << _name << URLs;
02312    QCString replyType;
02313    QByteArray replyData;
02314    QCString _launcher = KApplication::launcher();
02315    QValueList<QCString> envs;
02316 #ifdef Q_WS_X11
02317    if (qt_xdisplay()) {
02318        QCString dpystring(XDisplayString(qt_xdisplay()));
02319        envs.append( QCString("DISPLAY=") + dpystring );
02320    } else if( getenv( "DISPLAY" )) {
02321        QCString dpystring( getenv( "DISPLAY" ));
02322        envs.append( QCString("DISPLAY=") + dpystring );
02323    }
02324 #endif
02325    stream << envs << startup_id;
02326    if( function.left( 12 ) != "kdeinit_exec" )
02327        stream << noWait;
02328 
02329    if (!dcopClient->call(_launcher, _launcher,
02330         function, params, replyType, replyData))
02331    {
02332         if (error)
02333            *error = i18n("KLauncher could not be reached via DCOP.\n");
02334         if (!kapp)
02335            delete dcopClient;
02336         return -1;
02337    }
02338    if (!kapp)
02339       delete dcopClient;
02340 
02341    if (noWait)
02342       return 0;
02343 
02344    QDataStream stream2(replyData, IO_ReadOnly);
02345    serviceResult result;
02346    stream2 >> result.result >> result.dcopName >> result.error >> result.pid;
02347    if (dcopService)
02348       *dcopService = result.dcopName;
02349    if (error)
02350       *error = result.error;
02351    if (pid)
02352       *pid = result.pid;
02353    return result.result;
02354 }
02355 
02356 int
02357 KApplication::startServiceByName( const QString& _name, const QString &URL,
02358                   QString *error, QCString *dcopService, int *pid, const QCString& startup_id, bool noWait )
02359 {
02360    QStringList URLs;
02361    if (!URL.isEmpty())
02362       URLs.append(URL);
02363    return startServiceInternal(
02364                       "start_service_by_name(QString,QStringList,QValueList<QCString>,QCString,bool)",
02365                       _name, URLs, error, dcopService, pid, startup_id, noWait);
02366 }
02367 
02368 int
02369 KApplication::startServiceByName( const QString& _name, const QStringList &URLs,
02370                   QString *error, QCString *dcopService, int *pid, const QCString& startup_id, bool noWait )
02371 {
02372    return startServiceInternal(
02373                       "start_service_by_name(QString,QStringList,QValueList<QCString>,QCString,bool)",
02374                       _name, URLs, error, dcopService, pid, startup_id, noWait);
02375 }
02376 
02377 int
02378 KApplication::startServiceByDesktopPath( const QString& _name, const QString &URL,
02379                   QString *error, QCString *dcopService, int *pid, const QCString& startup_id, bool noWait )
02380 {
02381    QStringList URLs;
02382    if (!URL.isEmpty())
02383       URLs.append(URL);
02384    return startServiceInternal(
02385                       "start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString,bool)",
02386                       _name, URLs, error, dcopService, pid, startup_id, noWait);
02387 }
02388 
02389 int
02390 KApplication::startServiceByDesktopPath( const QString& _name, const QStringList &URLs,
02391                   QString *error, QCString *dcopService, int *pid, const QCString& startup_id, bool noWait )
02392 {
02393    return startServiceInternal(
02394                       "start_service_by_desktop_path(QString,QStringList,QValueList<QCString>,QCString,bool)",
02395                       _name, URLs, error, dcopService, pid, startup_id, noWait);
02396 }
02397 
02398 int
02399 KApplication::startServiceByDesktopName( const QString& _name, const QString &URL,
02400                   QString *error, QCString *dcopService, int *pid, const QCString& startup_id, bool noWait )
02401 {
02402    QStringList URLs;
02403    if (!URL.isEmpty())
02404       URLs.append(URL);
02405    return startServiceInternal(
02406                       "start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString,bool)",
02407                       _name, URLs, error, dcopService, pid, startup_id, noWait);
02408 }
02409 
02410 int
02411 KApplication::startServiceByDesktopName( const QString& _name, const QStringList &URLs,
02412                   QString *error, QCString *dcopService, int *pid, const QCString& startup_id, bool noWait )
02413 {
02414    return startServiceInternal(
02415                       "start_service_by_desktop_name(QString,QStringList,QValueList<QCString>,QCString,bool)",
02416                       _name, URLs, error, dcopService, pid, startup_id, noWait);
02417 }
02418 
02419 int
02420 KApplication::kdeinitExec( const QString& name, const QStringList &args,
02421                            QString *error, int *pid )
02422 {
02423     return kdeinitExec( name, args, error, pid, "" );
02424 }
02425 
02426 int
02427 KApplication::kdeinitExec( const QString& name, const QStringList &args,
02428                            QString *error, int *pid, const QCString& startup_id )
02429 {
02430    return startServiceInternal("kdeinit_exec(QString,QStringList,QValueList<QCString>,QCString)",
02431         name, args, error, 0, pid, startup_id, false);
02432 }
02433 
02434 int
02435 KApplication::kdeinitExecWait( const QString& name, const QStringList &args,
02436                            QString *error, int *pid )
02437 {
02438     return kdeinitExecWait( name, args, error, pid, "" );
02439 }
02440 
02441 int
02442 KApplication::kdeinitExecWait( const QString& name, const QStringList &args,
02443                            QString *error, int *pid, const QCString& startup_id )
02444 {
02445    return startServiceInternal("kdeinit_exec_wait(QString,QStringList,QValueList<QCString>,QCString)",
02446         name, args, error, 0, pid, startup_id, false);
02447 }
02448 
02449 QString KApplication::tempSaveName( const QString& pFilename ) const
02450 {
02451   QString aFilename;
02452 
02453   if( pFilename[0] != '/' )
02454     {
02455       kdWarning(101) << "Relative filename passed to KApplication::tempSaveName" << endl;
02456       aFilename = QFileInfo( QDir( "." ), pFilename ).absFilePath();
02457     }
02458   else
02459     aFilename = pFilename;
02460 
02461   QDir aAutosaveDir( QDir::homeDirPath() + "/autosave/" );
02462   if( !aAutosaveDir.exists() )
02463     {
02464       if( !aAutosaveDir.mkdir( aAutosaveDir.absPath() ) )
02465         {
02466           // Last chance: use temp dir
02467           aAutosaveDir.setPath( KGlobal::dirs()->saveLocation("tmp") );
02468         }
02469     }
02470 
02471   aFilename.replace( "/", "\\!" ).prepend( "#" ).append( "#" ).prepend( "/" ).prepend( aAutosaveDir.absPath() );
02472 
02473   return aFilename;
02474 }
02475 
02476 
02477 QString KApplication::checkRecoverFile( const QString& pFilename,
02478         bool& bRecover ) const
02479 {
02480   QString aFilename;
02481 
02482   if( pFilename[0] != '/' )
02483     {
02484       kdWarning(101) << "Relative filename passed to KApplication::tempSaveName" << endl;
02485       aFilename = QFileInfo( QDir( "." ), pFilename ).absFilePath();
02486     }
02487   else
02488     aFilename = pFilename;
02489 
02490   QDir aAutosaveDir( QDir::homeDirPath() + "/autosave/" );
02491   if( !aAutosaveDir.exists() )
02492     {
02493       if( !aAutosaveDir.mkdir( aAutosaveDir.absPath() ) )
02494         {
02495           // Last chance: use temp dir
02496           aAutosaveDir.setPath( KGlobal::dirs()->saveLocation("tmp") );
02497         }
02498     }
02499 
02500   aFilename.replace( "/", "\\!" ).prepend( "#" ).append( "#" ).prepend( "/" ).prepend( aAutosaveDir.absPath() );
02501 
02502   if( QFile( aFilename ).exists() )
02503     {
02504       bRecover = true;
02505       return aFilename;
02506     }
02507   else
02508     {
02509       bRecover = false;
02510       return pFilename;
02511     }
02512 }
02513 
02514 
02515 bool checkAccess(const QString& pathname, int mode)
02516 {
02517   int accessOK = access( QFile::encodeName(pathname), mode );
02518   if ( accessOK == 0 )
02519     return true;  // OK, I can really access the file
02520 
02521   // else
02522   // if we want to write the file would be created. Check, if the
02523   // user may write to the directory to create the file.
02524   if ( (mode & W_OK) == 0 )
02525     return false;   // Check for write access is not part of mode => bail out
02526 
02527 
02528   if (!access( QFile::encodeName(pathname), F_OK)) // if it already exists
02529       return false;
02530 
02531   //strip the filename (everything until '/' from the end
02532   QString dirName(pathname);
02533   int pos = dirName.findRev('/');
02534   if ( pos == -1 )
02535     return false;   // No path in argument. This is evil, we won't allow this
02536   else if ( pos == 0 ) // don't turn e.g. /root into an empty string
02537       pos = 1;
02538 
02539   dirName.truncate(pos); // strip everything starting from the last '/'
02540 
02541   accessOK = access( QFile::encodeName(dirName), W_OK );
02542   // -?- Can I write to the accessed diretory
02543   if ( accessOK == 0 )
02544     return true;  // Yes
02545   else
02546     return false; // No
02547 }
02548 
02549 void KApplication::setTopWidget( QWidget *topWidget )
02550 {
02551   if( topWidget != 0 )
02552   {
02553 #ifdef Q_WS_X11 // FIXME(E): Implement for Qt/Embedded
02554     Window leader = topWidget->winId();
02555     char* argv = const_cast< char* >( KCmdLineArgs::appName());
02556     XSetCommand(display, leader, &argv, 1);
02557     // this hints thing may go after Qt always sets window_group
02558     XWMHints *hints = XGetWMHints(display, topWidget->winId());
02559     if (hints)
02560     {
02561         if (!(hints->flags & WindowGroupHint))
02562         {
02563             hints->window_group = leader;
02564             hints->flags |= WindowGroupHint;
02565         }
02566         if (!(hints->flags & InputHint))
02567         {
02568             hints->input = True;
02569             hints->flags |= InputHint;
02570         }
02571         XSetWMHints(display, topWidget->winId(), hints);
02572         XFree(reinterpret_cast<char *>(hints));
02573     }
02574 
02575 #endif
02576     // set the specified caption
02577     if ( !topWidget->inherits("KMainWindow") ) { // KMainWindow does this already for us
02578         topWidget->setCaption( caption() );
02579 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
02580 //#ifndef Q_WS_QWS // FIXME(E): Implement for Qt/Embedded
02581         NETWinInfo info(qt_xdisplay(), topWidget->winId(), qt_xrootwin(), NET::WMName );
02582         info.setName( caption().utf8().data() );
02583 #endif
02584     }
02585 
02586     // set the specified icons
02587     topWidget->setIcon( icon() ); //standard X11
02588 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
02589 //#ifdef Q_WS_X11 // FIXME(E): Implement for Qt/Embedded
02590     KWin::setIcons(topWidget->winId(), icon(), miniIcon() ); // NET_WM hints for KWin
02591 
02592     // set the app startup notification window property
02593     KStartupInfo::setWindowStartupId( topWidget->winId(), startupId());
02594 #endif
02595   }
02596 }
02597 
02598 QCString KApplication::startupId() const
02599 {
02600     return d->startup_id;
02601 }
02602 
02603 void KApplication::setStartupId( const QCString& startup_id )
02604 {
02605     if( startup_id.isEmpty())
02606         d->startup_id = "0";
02607     else
02608         d->startup_id = startup_id;
02609 }
02610 
02611 // read the startup notification env variable, save it and unset it in order
02612 // not to propagate it to processes started from this app
02613 void KApplication::read_app_startup_id()
02614 {
02615 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
02616     KStartupInfoId id = KStartupInfo::currentStartupIdEnv();
02617     KStartupInfo::resetStartupEnv();
02618     d->startup_id = id.id();
02619 #endif
02620 }
02621 
02622 int KApplication::random()
02623 {
02624    static int init = false;
02625    if (!init)
02626    {
02627       unsigned int seed;
02628       init = true;
02629       int fd = open("/dev/urandom", O_RDONLY);
02630       if (fd <= 0 || ::read(fd, &seed, sizeof(seed)) != sizeof(seed))
02631       {
02632             // No /dev/urandom... try something else.
02633             srand(getpid());
02634             seed = rand()+time(0);
02635       }
02636       if (fd >= 0) close(fd);
02637       srand(seed);
02638    }
02639    return rand();
02640 }
02641 
02642 QString KApplication::randomString(int length)
02643 {
02644    if (length <=0 ) return QString::null;
02645 
02646    QString str; str.setLength( length );
02647    int i = 0;
02648    while (length--)
02649    {
02650       int r=random() % 62;
02651       r+=48;
02652       if (r>57) r+=7;
02653       if (r>90) r+=6;
02654       str[i++] =  char(r);
02655       // so what if I work backwards?
02656    }
02657    return str;
02658 }
02659 
02660 bool KApplication::authorize(const QString &genericAction)
02661 {
02662    if (!d->actionRestrictions)
02663       return true;
02664 
02665    KConfig *config = KGlobal::config();
02666    KConfigGroupSaver saver( config, "KDE Action Restrictions" );
02667    return config->readBoolEntry(genericAction, true);
02668 }
02669 
02670 bool KApplication::authorizeKAction(const char *action)
02671 {
02672    if (!d->actionRestrictions || !action)
02673       return true;
02674 
02675    static const QString &action_prefix = KGlobal::staticQString( "action/" );
02676 
02677    return authorize(action_prefix + action);
02678 }
02679 
02680 bool KApplication::authorizeControlModule(const QString &menuId)
02681 {
02682    if (menuId.isEmpty())
02683       return true;
02684    KConfig *config = KGlobal::config();
02685    KConfigGroupSaver saver( config, "KDE Control Module Restrictions" );
02686    return config->readBoolEntry(menuId, true);
02687 }
02688 
02689 QStringList KApplication::authorizeControlModules(const QStringList &menuIds)
02690 {
02691    KConfig *config = KGlobal::config();
02692    KConfigGroupSaver saver( config, "KDE Control Module Restrictions" );
02693    QStringList result;
02694    for(QStringList::ConstIterator it = menuIds.begin();
02695        it != menuIds.end(); ++it)
02696    {
02697       if (config->readBoolEntry(*it, true))
02698          result.append(*it);
02699    }
02700    return result;
02701 }
02702 
02703 void KApplication::initUrlActionRestrictions()
02704 {
02705   d->urlActionRestrictions.setAutoDelete(true);
02706   d->urlActionRestrictions.clear();
02707   d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
02708   ("open", QString::null, QString::null, QString::null, QString::null, QString::null, QString::null, true));
02709   d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
02710   ("list", QString::null, QString::null, QString::null, QString::null, QString::null, QString::null, true));
02711 // TEST:
02712 //  d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
02713 //  ("list", QString::null, QString::null, QString::null, QString::null, QString::null, QString::null, false));
02714 //  d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
02715 //  ("list", QString::null, QString::null, QString::null, "file", QString::null, QDir::homeDirPath(), true));
02716   d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
02717   ("link", QString::null, QString::null, QString::null, ":internet", QString::null, QString::null, true));
02718   d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
02719   ("redirect", QString::null, QString::null, QString::null, ":internet", QString::null, QString::null, true));
02720 
02721   // We allow redirections to file: but not from internet protocols, redirecting to file:
02722   // is very popular among io-slaves and we don't want to break them
02723   d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
02724   ("redirect", QString::null, QString::null, QString::null, "file", QString::null, QString::null, true));
02725   d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
02726   ("redirect", ":internet", QString::null, QString::null, "file", QString::null, QString::null, false));
02727 
02728   // local protocols may redirect everywhere
02729   d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
02730   ("redirect", ":local", QString::null, QString::null, QString::null, QString::null, QString::null, true));
02731 
02732   // Anyone may redirect to about:
02733   d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
02734   ("redirect", QString::null, QString::null, QString::null, "about", QString::null, QString::null, true));
02735 
02736   // Anyone may redirect to itself, cq. within it's own group
02737   d->urlActionRestrictions.append( new KApplicationPrivate::URLActionRule
02738   ("redirect", QString::null, QString::null, QString::null, "=", QString::null, QString::null, true));
02739 
02740   KConfig *config = KGlobal::config();
02741   KConfigGroupSaver saver( config, "KDE URL Restrictions" );
02742   int count = config->readNumEntry("rule_count");
02743   QString keyFormat = QString("rule_%1");
02744   for(int i = 1; i <= count; i++)
02745   {
02746     QString key = keyFormat.arg(i);
02747     QStringList rule = config->readListEntry(key);
02748     if (rule.count() != 8)
02749       continue;
02750     QString action = rule[0];
02751     QString refProt = rule[1];
02752     QString refHost = rule[2];
02753     QString refPath = rule[3];
02754     QString urlProt = rule[4];
02755     QString urlHost = rule[5];
02756     QString urlPath = rule[6];
02757     QString strEnabled = rule[7].lower();
02758 
02759     bool bEnabled = (strEnabled == "true");
02760 
02761     if (refPath.startsWith("$HOME"))
02762        refPath.replace(0, 5, QDir::homeDirPath());
02763     else if (refPath.startsWith("~"))
02764        refPath.replace(0, 1, QDir::homeDirPath());
02765     if (urlPath.startsWith("$HOME"))
02766        urlPath.replace(0, 5, QDir::homeDirPath());
02767     else if (urlPath.startsWith("~"))
02768        urlPath.replace(0, 1, QDir::homeDirPath());
02769 
02770     if (refPath.startsWith("$TMP"))
02771        refPath.replace(0, 4, KGlobal::dirs()->saveLocation("tmp"));
02772     if (urlPath.startsWith("$TMP"))
02773        urlPath.replace(0, 4, KGlobal::dirs()->saveLocation("tmp"));
02774 
02775     d->urlActionRestrictions.append(new KApplicationPrivate::URLActionRule
02776         ( action, refProt, refHost, refPath, urlProt, urlHost, urlPath, bEnabled));
02777   }
02778 }
02779 
02780 void KApplication::allowURLAction(const QString &action, const KURL &_baseURL, const KURL &_destURL)
02781 {
02782   if (authorizeURLAction(action, _baseURL, _destURL))
02783      return;
02784      
02785   d->urlActionRestrictions.append(new KApplicationPrivate::URLActionRule
02786         ( action, _baseURL.protocol(), _baseURL.host(), _baseURL.path(-1),
02787                   _destURL.protocol(), _destURL.host(), _destURL.path(-1), true));
02788 }
02789 
02790 bool KApplication::authorizeURLAction(const QString &action, const KURL &_baseURL, const KURL &_destURL)
02791 {
02792   if (_destURL.isEmpty())
02793      return true;
02794 
02795   bool result = false;
02796   if (d->urlActionRestrictions.isEmpty())
02797      initUrlActionRestrictions();
02798 
02799   KURL baseURL(_baseURL);
02800   baseURL.setPath(QDir::cleanDirPath(baseURL.path()));
02801   QString baseClass = KProtocolInfo::protocolClass(baseURL.protocol());
02802   KURL destURL(_destURL);
02803   destURL.setPath(QDir::cleanDirPath(destURL.path()));
02804   QString destClass = KProtocolInfo::protocolClass(destURL.protocol());
02805 
02806   for(KApplicationPrivate::URLActionRule *rule = d->urlActionRestrictions.first();
02807       rule; rule = d->urlActionRestrictions.next())
02808   {
02809      if ((result != rule->permission) && // No need to check if it doesn't make a difference
02810          (action == rule->action) &&
02811          rule->baseMatch(baseURL, baseClass) &&
02812          rule->destMatch(destURL, destClass, baseURL, baseClass))
02813      {
02814         result = rule->permission;
02815      }
02816   }
02817   return result;
02818 }
02819 
02820 
02821 uint KApplication::keyboardModifiers()
02822 {
02823     Window root;
02824     Window child;
02825     int root_x, root_y, win_x, win_y;
02826     uint keybstate;
02827     XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child,
02828                    &root_x, &root_y, &win_x, &win_y, &keybstate );
02829     return keybstate & 0x00ff;
02830 }
02831 
02832 uint KApplication::mouseState()
02833 {
02834     Window root;
02835     Window child;
02836     int root_x, root_y, win_x, win_y;
02837     uint keybstate;
02838     XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child,
02839                    &root_x, &root_y, &win_x, &win_y, &keybstate );
02840     return keybstate & 0xff00;
02841 }
02842 
02843 void KApplication::installSigpipeHandler()
02844 {
02845     struct sigaction act;
02846     act.sa_handler = SIG_IGN;
02847     sigemptyset( &act.sa_mask );
02848     act.sa_flags = 0;
02849     sigaction( SIGPIPE, &act, 0 );
02850 }
02851 
02852 void KApplication::sigpipeHandler(int)
02853 {
02854     int saved_errno = errno;
02855     // Using kdDebug from a signal handler is not a good idea.
02856 #ifndef NDEBUG
02857     char msg[1000];
02858     sprintf(msg, "*** SIGPIPE *** (ignored, pid = %ld)\n", (long) getpid());
02859     write(2, msg, strlen(msg));
02860 #endif
02861 
02862     // Do nothing.
02863     errno = saved_errno;
02864 }
02865 
02866 bool KApplication::guiEnabled()
02867 {
02868     return kapp && kapp->d->guiEnabled;
02869 }
02870 
02871 void KApplication::virtual_hook( int id, void* data )
02872 { KInstance::virtual_hook( id, data ); }
02873 
02874 void KSessionManaged::virtual_hook( int, void* )
02875 { /*BASE::virtual_hook( id, data );*/ }
02876 
02877 #include "kapplication.moc"
KDE Logo
This file is part of the documentation for kdecore Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun May 16 22:01:17 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003