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