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