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