00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kapplication.h"
00022
00023 #include <config.h>
00024
00025 #include <QtCore/QDir>
00026 #include <QtCore/QFile>
00027 #include <QtGui/QSessionManager>
00028 #include <QtGui/QStyleFactory>
00029 #include <QtCore/QTimer>
00030 #include <QtGui/QWidget>
00031 #include <QtCore/QList>
00032 #include <QtDBus/QtDBus>
00033 #include <QtCore/QMetaType>
00034
00035 #include "kauthorized.h"
00036 #include "kaboutdata.h"
00037 #include "kcheckaccelerators.h"
00038 #include "kcrash.h"
00039 #include "kconfig.h"
00040 #include "kcmdlineargs.h"
00041 #include "kclipboard.h"
00042 #include "kglobalsettings.h"
00043 #include "kdebug.h"
00044 #include "kglobal.h"
00045 #include "kicon.h"
00046 #include "klocale.h"
00047 #include "ksessionmanager.h"
00048 #include "kstandarddirs.h"
00049 #include "kstandardshortcut.h"
00050 #include "ktoolinvocation.h"
00051 #include "kgesturemap.h"
00052 #include "kurl.h"
00053 #include "kmessage.h"
00054 #include "kmessageboxmessagehandler.h"
00055
00056 #if defined Q_WS_X11
00057 #include <QtGui/qx11info_x11.h>
00058 #include <kstartupinfo.h>
00059 #endif
00060
00061 #include <sys/types.h>
00062 #ifdef HAVE_SYS_STAT_H
00063 #include <sys/stat.h>
00064 #endif
00065 #include <sys/wait.h>
00066
00067 #ifndef Q_WS_WIN
00068 #include "kwindowsystem.h"
00069 #endif
00070
00071 #include <fcntl.h>
00072 #include <stdlib.h>
00073 #include <unistd.h>
00074 #if defined Q_WS_X11
00075
00076 #include <netwm.h>
00077 #endif
00078
00079 #ifdef HAVE_PATHS_H
00080 #include <paths.h>
00081 #endif
00082
00083 #ifdef Q_WS_X11
00084 #include <X11/Xlib.h>
00085 #include <X11/Xutil.h>
00086 #include <X11/Xatom.h>
00087 #include <X11/SM/SMlib.h>
00088 #include <fixx11h.h>
00089
00090 #include <QX11Info>
00091 #endif
00092
00093 #ifdef Q_WS_MACX
00094
00095 #undef Status
00096 #include <Carbon/Carbon.h>
00097 #include <QImage>
00098 #include <ksystemtrayicon.h>
00099 #include <kkernel_mac.h>
00100 #endif
00101
00102 #ifdef Q_OS_UNIX
00103 #include <signal.h>
00104 #endif
00105
00106 #include <QtGui/QActionEvent>
00107 #include <kcomponentdata.h>
00108
00109 KApplication* KApplication::KApp = 0L;
00110 bool KApplication::loadedByKdeinit = false;
00111
00112 #ifdef Q_WS_X11
00113 static Atom atom_DesktopWindow;
00114 static Atom atom_NetSupported;
00115 static Atom kde_xdnd_drop;
00116 static QByteArray* startup_id_tmp;
00117 #endif
00118
00119 template class QList<KSessionManager*>;
00120
00121 #ifdef Q_WS_X11
00122 extern "C" {
00123 static int kde_xio_errhandler( Display * dpy )
00124 {
00125 return kapp->xioErrhandler( dpy );
00126 }
00127
00128 static int kde_x_errhandler( Display *dpy, XErrorEvent *err )
00129 {
00130 return kapp->xErrhandler( dpy, err );
00131 }
00132
00133 }
00134 #endif
00135
00136 #ifdef Q_WS_WIN
00137 void KApplication_init_windows();
00138 #endif
00139
00140
00141
00142
00143 class KApplicationPrivate
00144 {
00145 public:
00146 KApplicationPrivate(KApplication* q, const QByteArray &cName)
00147 : q(q)
00148 , componentData(cName)
00149 , startup_id("0")
00150 , app_started_timer(0)
00151 , session_save(false)
00152 #ifdef Q_WS_X11
00153 , oldIceIOErrorHandler(0)
00154 , oldXErrorHandler(0)
00155 , oldXIOErrorHandler(0)
00156 #endif
00157 , pSessionConfig( 0 )
00158 , bSessionManagement( true )
00159 {
00160 }
00161
00162 KApplicationPrivate(KApplication* q, const KComponentData &cData)
00163 : q(q)
00164 , componentData(cData)
00165 , startup_id("0")
00166 , app_started_timer(0)
00167 , session_save(false)
00168 #ifdef Q_WS_X11
00169 , oldIceIOErrorHandler(0)
00170 , oldXErrorHandler(0)
00171 , oldXIOErrorHandler(0)
00172 #endif
00173 , pSessionConfig( 0 )
00174 , bSessionManagement( true )
00175 {
00176 }
00177
00178 KApplicationPrivate(KApplication *q)
00179 : q(q)
00180 , componentData(KCmdLineArgs::aboutData())
00181 , startup_id( "0" )
00182 , app_started_timer( 0 )
00183 , session_save( false )
00184 #ifdef Q_WS_X11
00185 , oldIceIOErrorHandler( 0 )
00186 , oldXErrorHandler( 0 )
00187 , oldXIOErrorHandler( 0 )
00188 #endif
00189 , pSessionConfig( 0 )
00190 , bSessionManagement( true )
00191 {
00192 }
00193
00194 ~KApplicationPrivate()
00195 {
00196 }
00197
00198 #ifndef KDE3_SUPPORT
00199 KConfig *config() { return KGlobal::config().data(); }
00200 #endif
00201
00202 void _k_x11FilterDestroyed();
00203 void _k_checkAppStartedSlot();
00204 void _k_slot_KToolInvocation_hook(QStringList&, QByteArray&);
00205
00206 QString sessionConfigName() const;
00207 void init(bool GUIenabled=true);
00208 void parseCommandLine( );
00209 static void preqapplicationhack();
00210 static void preread_app_startup_id();
00211 void read_app_startup_id();
00212
00213 KApplication *q;
00214 KComponentData componentData;
00215 QByteArray startup_id;
00216 QTimer* app_started_timer;
00217 bool session_save;
00218
00219 #ifdef Q_WS_X11
00220 IceIOErrorHandler oldIceIOErrorHandler;
00221 int (*oldXErrorHandler)(Display*,XErrorEvent*);
00222 int (*oldXIOErrorHandler)(Display*);
00223 #endif
00224
00225 QString sessionKey;
00226 QString pSessionConfigFile;
00227
00228 KConfig* pSessionConfig;
00229 bool bSessionManagement;
00230 };
00231
00232
00233 static QList<const QWidget*> *x11Filter = 0;
00234
00242 static void installSigpipeHandler()
00243 {
00244 #ifdef Q_OS_UNIX
00245 struct sigaction act;
00246 act.sa_handler = SIG_IGN;
00247 sigemptyset( &act.sa_mask );
00248 act.sa_flags = 0;
00249 sigaction( SIGPIPE, &act, 0 );
00250 #endif
00251 }
00252
00253 void KApplication::installX11EventFilter( QWidget* filter )
00254 {
00255 if ( !filter )
00256 return;
00257 if (!x11Filter)
00258 x11Filter = new QList<const QWidget *>;
00259 connect ( filter, SIGNAL( destroyed() ), this, SLOT( _k_x11FilterDestroyed() ) );
00260 x11Filter->append( filter );
00261 }
00262
00263 void KApplicationPrivate::_k_x11FilterDestroyed()
00264 {
00265 q->removeX11EventFilter( static_cast< const QWidget* >(q->sender()));
00266 }
00267
00268 void KApplication::removeX11EventFilter( const QWidget* filter )
00269 {
00270 if ( !x11Filter || !filter )
00271 return;
00272 x11Filter->removeAll( filter );
00273 if ( x11Filter->isEmpty() ) {
00274 delete x11Filter;
00275 x11Filter = 0;
00276 }
00277 }
00278
00279 bool KApplication::notify(QObject *receiver, QEvent *event)
00280 {
00281 QEvent::Type t = event->type();
00282 if( t == QEvent::Show && receiver->isWidgetType())
00283 {
00284 QWidget* w = static_cast< QWidget* >( receiver );
00285 #if defined Q_WS_X11
00286 if( w->isTopLevel() && !startupId().isEmpty())
00287 KStartupInfo::setWindowStartupId( w->winId(), startupId());
00288 #endif
00289 if( w->isTopLevel() && !( w->windowFlags() & Qt::X11BypassWindowManagerHint ) && w->windowType() != Qt::Popup && !event->spontaneous())
00290 {
00291 if( d->app_started_timer == NULL )
00292 {
00293 d->app_started_timer = new QTimer( this );
00294 connect( d->app_started_timer, SIGNAL( timeout()), SLOT( _k_checkAppStartedSlot()));
00295 }
00296 if( !d->app_started_timer->isActive()) {
00297 d->app_started_timer->setSingleShot( true );
00298 d->app_started_timer->start( 0 );
00299 }
00300 }
00301 }
00302 return QApplication::notify(receiver, event);
00303 }
00304
00305 void KApplicationPrivate::_k_checkAppStartedSlot()
00306 {
00307 #if defined Q_WS_X11
00308 KStartupInfo::handleAutoAppStartedSending();
00309 #endif
00310 }
00311
00312
00313
00314
00315
00316
00317 QString KApplicationPrivate::sessionConfigName() const
00318 {
00319 #ifdef QT_NO_SESSIONMANAGER
00320 #error QT_NO_SESSIONMANAGER was set, this will not compile. Reconfigure Qt with Session management support.
00321 #endif
00322 QString sessKey = q->sessionKey();
00323 if ( sessKey.isEmpty() && !sessionKey.isEmpty() )
00324 sessKey = sessionKey;
00325 return QString(QLatin1String("session/%1_%2_%3")).arg(q->applicationName()).arg(q->sessionId()).arg(sessKey);
00326 }
00327
00328 #ifdef Q_WS_X11
00329 static SmcConn mySmcConnection = 0;
00330 #else
00331
00332
00333 #endif
00334
00335 KApplication::KApplication(bool GUIenabled)
00336 : QApplication((KApplicationPrivate::preqapplicationhack(),KCmdLineArgs::qtArgc()), KCmdLineArgs::qtArgv(), GUIenabled),
00337 d(new KApplicationPrivate(this))
00338 {
00339 d->read_app_startup_id();
00340 setApplicationName(d->componentData.componentName());
00341 setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
00342 installSigpipeHandler();
00343 d->init(GUIenabled);
00344 }
00345
00346 #ifdef Q_WS_X11
00347 KApplication::KApplication(Display *dpy, Qt::HANDLE visual, Qt::HANDLE colormap)
00348 : QApplication((KApplicationPrivate::preqapplicationhack(),dpy), KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv(), visual, colormap),
00349 d(new KApplicationPrivate(this))
00350 {
00351 d->read_app_startup_id();
00352 setApplicationName(d->componentData.componentName());
00353 setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
00354 installSigpipeHandler();
00355 d->init();
00356 }
00357
00358 KApplication::KApplication(Display *dpy, Qt::HANDLE visual, Qt::HANDLE colormap, const KComponentData &cData)
00359 : QApplication((KApplicationPrivate::preqapplicationhack(),dpy), KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv(), visual, colormap),
00360 d (new KApplicationPrivate(this, cData))
00361 {
00362 d->read_app_startup_id();
00363 setApplicationName(d->componentData.componentName());
00364 setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
00365 installSigpipeHandler();
00366 d->init();
00367 }
00368 #endif
00369
00370 KApplication::KApplication(bool GUIenabled, const KComponentData &cData)
00371 : QApplication((KApplicationPrivate::preqapplicationhack(),KCmdLineArgs::qtArgc()), KCmdLineArgs::qtArgv(), GUIenabled),
00372 d (new KApplicationPrivate(this, cData))
00373 {
00374 d->read_app_startup_id();
00375 setApplicationName(d->componentData.componentName());
00376 setOrganizationDomain(d->componentData.aboutData()->organizationDomain());
00377 installSigpipeHandler();
00378 d->init(GUIenabled);
00379 }
00380
00381 #ifdef Q_WS_X11
00382 KApplication::KApplication(Display *display, int& argc, char** argv, const QByteArray& rAppName,
00383 bool GUIenabled)
00384 : QApplication((KApplicationPrivate::preqapplicationhack(),display)),
00385 d(new KApplicationPrivate(this, rAppName))
00386 {
00387 Q_UNUSED(GUIenabled);
00388 d->read_app_startup_id();
00389 setApplicationName(QLatin1String(rAppName));
00390 installSigpipeHandler();
00391 KCmdLineArgs::initIgnore(argc, argv, rAppName.data());
00392 d->init();
00393 }
00394 #endif
00395
00396
00397
00398 void KApplicationPrivate::preqapplicationhack()
00399 {
00400 preread_app_startup_id();
00401 }
00402
00403 int KApplication::xioErrhandler( Display* dpy )
00404 {
00405 if(kapp)
00406 {
00407 #ifdef Q_WS_X11
00408 d->oldXIOErrorHandler( dpy );
00409 #else
00410 Q_UNUSED(dpy);
00411 #endif
00412 }
00413 exit( 1 );
00414 return 0;
00415 }
00416
00417 int KApplication::xErrhandler( Display* dpy, void* err_ )
00418 {
00419 #ifdef Q_WS_X11
00420 XErrorEvent* err = static_cast< XErrorEvent* >( err_ );
00421 if(kapp)
00422 {
00423
00424 d->oldXErrorHandler( dpy, err );
00425 }
00426 const QByteArray fatalXError = qgetenv("KDE_FATAL_X_ERROR");
00427 if (!fatalXError.isEmpty()) {
00428 abort();
00429 }
00430 #endif
00431 return 0;
00432 }
00433
00434 void KApplication::iceIOErrorHandler( _IceConn *conn )
00435 {
00436 emit aboutToQuit();
00437
00438 #ifdef Q_WS_X11
00439 if ( d->oldIceIOErrorHandler != NULL )
00440 (*d->oldIceIOErrorHandler)( conn );
00441 #endif
00442 exit( 1 );
00443 }
00444
00445 void KApplicationPrivate::init(bool GUIenabled)
00446 {
00447 if ((getuid() != geteuid()) ||
00448 (getgid() != getegid()))
00449 {
00450 fprintf(stderr, "The KDE libraries are not designed to run with suid privileges.\n");
00451 ::exit(127);
00452 }
00453
00454 #ifdef Q_WS_MAC
00455 mac_initialize_dbus();
00456 #endif
00457
00458 KApplication::KApp = q;
00459
00460 parseCommandLine();
00461
00462 if(GUIenabled)
00463 (void) KClipboardSynchronizer::self();
00464
00465 extern KDECORE_EXPORT bool kde_kdebug_enable_dbus_interface;
00466 kde_kdebug_enable_dbus_interface = true;
00467
00468 QApplication::setDesktopSettingsAware( false );
00469
00470 #ifdef Q_WS_X11 //FIXME(E)
00471
00472 if ( q->type() == KApplication::GuiClient ) {
00473 const int max = 20;
00474 Atom* atoms[max];
00475 char* names[max];
00476 Atom atoms_return[max];
00477 int n = 0;
00478
00479 atoms[n] = &atom_DesktopWindow;
00480 names[n++] = (char *) "KDE_DESKTOP_WINDOW";
00481
00482 atoms[n] = &atom_NetSupported;
00483 names[n++] = (char *) "_NET_SUPPORTED";
00484
00485 atoms[n] = &kde_xdnd_drop;
00486 names[n++] = (char *) "XdndDrop";
00487
00488 XInternAtoms( QX11Info::display(), names, n, false, atoms_return );
00489
00490 for (int i = 0; i < n; i++ )
00491 *atoms[i] = atoms_return[i];
00492 }
00493 #endif
00494
00495
00496
00497 extern void qDBusBindToApplication();
00498 qDBusBindToApplication();
00499 QDBusConnectionInterface *bus = 0;
00500 if (!QDBusConnection::sessionBus().isConnected() || !(bus = QDBusConnection::sessionBus().interface())) {
00501 kFatal(101) << "Session bus not found" << endl;
00502 ::exit(125);
00503 }
00504
00505 extern bool s_kuniqueapplication_startCalled;
00506 if ( bus && !s_kuniqueapplication_startCalled )
00507 {
00508 QStringList parts = q->organizationDomain().split(QLatin1Char('.'), QString::SkipEmptyParts);
00509 QString reversedDomain;
00510 if (parts.isEmpty())
00511 reversedDomain = QLatin1String("local.");
00512 else
00513 foreach (const QString& s, parts)
00514 {
00515 reversedDomain.prepend(QLatin1Char('.'));
00516 reversedDomain.prepend(s);
00517 }
00518 const QString pidSuffix = QString::number( getpid() ).prepend( QLatin1String("-") );
00519 const QString serviceName = reversedDomain + q->applicationName() + pidSuffix;
00520 if ( bus->registerService(serviceName) == QDBusConnectionInterface::ServiceNotRegistered ) {
00521 kError(101) << "Couldn't register name '" << serviceName << "' with DBUS - another process owns it already!" << endl;
00522 ::exit(126);
00523 }
00524 }
00525 QDBusConnection::sessionBus().registerObject(QLatin1String("/MainApplication"), q,
00526 QDBusConnection::ExportScriptableSlots |
00527 QDBusConnection::ExportScriptableProperties |
00528 QDBusConnection::ExportAdaptors);
00529
00530
00531 (void) KGlobal::locale();
00532
00533 KSharedConfig::Ptr config = componentData.config();
00534 QByteArray readOnly = qgetenv("KDE_HOME_READONLY");
00535 if (readOnly.isEmpty() && q->applicationName() != QLatin1String("kdialog"))
00536 {
00537 if (KAuthorized::authorize(QLatin1String("warn_unwritable_config")))
00538 config->isConfigWritable(true);
00539 }
00540
00541 if (q->type() == KApplication::GuiClient)
00542 {
00543 #ifdef Q_WS_X11
00544
00545 fcntl(ConnectionNumber(QX11Info::display()), F_SETFD, FD_CLOEXEC);
00546
00547 oldXErrorHandler = XSetErrorHandler( kde_x_errhandler );
00548 oldXIOErrorHandler = XSetIOErrorHandler( kde_xio_errhandler );
00549 #endif
00550
00551
00552 KGlobalSettings::self()->activate();
00553
00554 KMessage::setMessageHandler( new KMessageBoxMessageHandler(0) );
00555
00556 KCheckAccelerators::initiateIfNeeded(q);
00557 KGestureMap::self()->installEventFilterOnMe( q );
00558
00559 q->connect(KToolInvocation::self(), SIGNAL(kapplication_hook(QStringList&, QByteArray&)),
00560 q, SLOT(_k_slot_KToolInvocation_hook(QStringList&,QByteArray&)));
00561 }
00562
00563 #ifdef Q_WS_MAC
00564 if (q->type() == KApplication::GuiClient) {
00565
00566 QSystemTrayIcon *trayIcon;
00567 if (QSystemTrayIcon::isSystemTrayAvailable())
00568 {
00569 trayIcon = new QSystemTrayIcon(q);
00570 trayIcon->setIcon(q->windowIcon());
00571
00572
00573
00574 }
00575 }
00576 #endif
00577
00578 qRegisterMetaType<KUrl>();
00579 qRegisterMetaType<KUrl::List>();
00580
00581 #ifdef Q_WS_WIN
00582 KApplication_init_windows();
00583 #endif
00584 }
00585
00586 KApplication* KApplication::kApplication()
00587 {
00588 return KApp;
00589 }
00590
00591 KConfig* KApplication::sessionConfig()
00592 {
00593 if (!d->pSessionConfig)
00594 d->pSessionConfig = new KConfig( d->sessionConfigName(), KConfig::SimpleConfig );
00595 return d->pSessionConfig;
00596 }
00597
00598 void KApplication::reparseConfiguration()
00599 {
00600 KGlobal::config()->reparseConfiguration();
00601 }
00602
00603 void KApplication::quit()
00604 {
00605 QApplication::quit();
00606 }
00607
00608 void KApplication::disableSessionManagement() {
00609 d->bSessionManagement = false;
00610 }
00611
00612 void KApplication::enableSessionManagement() {
00613 d->bSessionManagement = true;
00614 #ifdef Q_WS_X11
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624 if( mySmcConnection ) {
00625 SmcRequestSaveYourself( mySmcConnection, SmSaveLocal, False,
00626 SmInteractStyleAny,
00627 False, False );
00628
00629
00630 IceFlush(SmcGetIceConnection(mySmcConnection));
00631 }
00632 #endif
00633 }
00634
00635 void KApplication::commitData( QSessionManager& sm )
00636 {
00637 d->session_save = true;
00638 bool canceled = false;
00639
00640 foreach (KSessionManager *it, KSessionManager::sessionClients()) {
00641 if ( ( canceled = !it->commitData( sm ) ) )
00642 break;
00643 }
00644
00645 if ( canceled )
00646 sm.cancel();
00647
00648 if ( sm.allowsInteraction() ) {
00649 QWidgetList donelist, todolist;
00650 QWidget* w;
00651
00652 commitDataRestart:
00653 todolist = QApplication::topLevelWidgets();
00654
00655 for ( int i = 0; i < todolist.size(); ++i ) {
00656 w = todolist.at( i );
00657 if( !w )
00658 break;
00659
00660 if ( donelist.contains( w ) )
00661 continue;
00662
00663 if ( !w->isHidden() && !w->inherits( "KMainWindow" ) ) {
00664 QCloseEvent e;
00665 sendEvent( w, &e );
00666 if ( !e.isAccepted() )
00667 break;
00668
00669 donelist.append( w );
00670
00671
00672 goto commitDataRestart;
00673 }
00674 }
00675 }
00676
00677 if ( !d->bSessionManagement )
00678 sm.setRestartHint( QSessionManager::RestartNever );
00679 else
00680 sm.setRestartHint( QSessionManager::RestartIfRunning );
00681 d->session_save = false;
00682 }
00683
00684 #ifdef Q_WS_X11
00685 static void checkRestartVersion( QSessionManager& sm )
00686 {
00687 Display* dpy = QX11Info::display();
00688 Atom type;
00689 int format;
00690 unsigned long nitems, after;
00691 unsigned char* data;
00692 if( dpy != NULL && XGetWindowProperty( dpy, RootWindow( dpy, 0 ), XInternAtom( dpy, "KDE_SESSION_VERSION", False ),
00693 0, 1, False, AnyPropertyType, &type, &format, &nitems, &after, &data ) == Success ) {
00694 if( type == XA_CARDINAL && format == 32 ) {
00695 int version = *( long* ) data;
00696 if( version == KDE_VERSION_MAJOR ) {
00697 XFree( data );
00698 return;
00699 }
00700 }
00701 XFree( data );
00702 }
00703 if( getenv( "KDE_SESSION_VERSION" ) != NULL && atoi( getenv( "KDE_SESSION_VERSION" )) == KDE_VERSION_MAJOR )
00704 return;
00705 #define NUM_TO_STRING2( num ) #num
00706 #define NUM_TO_STRING( num ) NUM_TO_STRING2( num )
00707 QString wrapper = KStandardDirs::findExe( "kde" NUM_TO_STRING( KDE_VERSION_MAJOR ) );
00708 #undef NUM_TO_STRING
00709 #undef NUM_TO_STRING2
00710 if( !wrapper.isEmpty()) {
00711 QStringList restartCommand = sm.restartCommand();
00712 restartCommand.prepend( wrapper );
00713 sm.setRestartCommand( restartCommand );
00714 }
00715 }
00716 #endif // Q_WS_X11
00717
00718 void KApplication::saveState( QSessionManager& sm )
00719 {
00720 d->session_save = true;
00721 #ifdef Q_WS_X11
00722 static bool firstTime = true;
00723 mySmcConnection = (SmcConn) sm.handle();
00724
00725 if ( !d->bSessionManagement ) {
00726 sm.setRestartHint( QSessionManager::RestartNever );
00727 d->session_save = false;
00728 return;
00729 }
00730 else
00731 sm.setRestartHint( QSessionManager::RestartIfRunning );
00732
00733 if ( firstTime ) {
00734 firstTime = false;
00735 d->session_save = false;
00736 return;
00737 }
00738
00739
00740
00741
00742
00743
00744
00745 if ( d->pSessionConfig ) {
00746 delete d->pSessionConfig;
00747 d->pSessionConfig = 0;
00748 }
00749
00750
00751 QStringList restartCommand = sm.restartCommand();
00752
00753 QByteArray multiHead = qgetenv("KDE_MULTIHEAD");
00754 if (multiHead.toLower() == "true") {
00755
00756
00757
00758
00759
00760
00761 QByteArray displayname = qgetenv("DISPLAY");
00762 if (! displayname.isNull()) {
00763
00764
00765 restartCommand.append(QLatin1String("-display"));
00766 restartCommand.append(QLatin1String(displayname));
00767 }
00768 sm.setRestartCommand( restartCommand );
00769 }
00770
00771 #ifdef Q_WS_X11
00772 checkRestartVersion( sm );
00773 #endif
00774
00775
00776 emit saveYourself();
00777 bool canceled = false;
00778 foreach(KSessionManager* it, KSessionManager::sessionClients()) {
00779 if(canceled) break;
00780 canceled = !it->saveState( sm );
00781 }
00782
00783
00784 if ( d->pSessionConfig ) {
00785 d->pSessionConfig->sync();
00786 QStringList discard;
00787 discard << QLatin1String("rm") << KStandardDirs::locateLocal("config", d->sessionConfigName());
00788 sm.setDiscardCommand( discard );
00789 } else {
00790 sm.setDiscardCommand( QStringList( QLatin1String("") ) );
00791 }
00792
00793 if ( canceled )
00794 sm.cancel();
00795 #else
00796
00797 #endif
00798 d->session_save = false;
00799 }
00800
00801 bool KApplication::sessionSaving() const
00802 {
00803 return d->session_save;
00804 }
00805
00806 void KApplicationPrivate::parseCommandLine( )
00807 {
00808 KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
00809
00810 if (args && args->isSet("style"))
00811 {
00812 extern QString kde_overrideStyle;
00813 QString reqStyle(args->getOption("style").toLower());
00814 if (QStyleFactory::keys().contains(reqStyle, Qt::CaseInsensitive))
00815 kde_overrideStyle = reqStyle;
00816 else
00817 qWarning() << i18n("The style '%1' was not found", reqStyle);
00818 }
00819
00820 if ( q->type() != KApplication::Tty ) {
00821 if (args && args->isSet("icon"))
00822 {
00823 q->setWindowIcon(KIcon(args->getOption("icon")));
00824 }
00825 else {
00826 q->setWindowIcon(KIcon(componentData.aboutData()->programIconName()));
00827 }
00828 }
00829
00830 if (!args)
00831 return;
00832
00833 if (args->isSet("config"))
00834 {
00835 QString config = args->getOption("config");
00836 componentData.setConfigName(config);
00837 }
00838
00839 bool nocrashhandler = (!qgetenv("KDE_DEBUG").isEmpty());
00840 if (!nocrashhandler && args->isSet("crashhandler"))
00841 {
00842
00843 KCrash::setCrashHandler(KCrash::defaultCrashHandler);
00844 }
00845
00846 KCrash::setApplicationName(args->appName());
00847 if (!QCoreApplication::applicationDirPath().isEmpty()) {
00848 KCrash::setApplicationPath(QCoreApplication::applicationDirPath());
00849 }
00850
00851 #ifdef Q_WS_X11
00852 if ( args->isSet( "waitforwm" ) ) {
00853 Atom type;
00854 (void) q->desktop();
00855 int format;
00856 unsigned long length, after;
00857 unsigned char *data;
00858 while ( XGetWindowProperty( QX11Info::display(), QX11Info::appRootWindow(), atom_NetSupported,
00859 0, 1, false, AnyPropertyType, &type, &format,
00860 &length, &after, &data ) != Success || !length ) {
00861 if ( data )
00862 XFree( data );
00863 XEvent event;
00864 XWindowEvent( QX11Info::display(), QX11Info::appRootWindow(), PropertyChangeMask, &event );
00865 }
00866 if ( data )
00867 XFree( data );
00868 }
00869 #else
00870
00871 #endif
00872
00873 #ifndef Q_WS_WIN
00874 if (args->isSet("smkey"))
00875 {
00876 sessionKey = args->getOption("smkey");
00877 }
00878 #endif
00879 }
00880
00881 extern void kDebugCleanup();
00882
00883 KApplication::~KApplication()
00884 {
00885 #ifdef Q_WS_X11
00886 if ( d->oldXErrorHandler != NULL )
00887 XSetErrorHandler( d->oldXErrorHandler );
00888 if ( d->oldXIOErrorHandler != NULL )
00889 XSetIOErrorHandler( d->oldXIOErrorHandler );
00890 if ( d->oldIceIOErrorHandler != NULL )
00891 IceSetIOErrorHandler( d->oldIceIOErrorHandler );
00892 #endif
00893
00894 delete d;
00895 KApp = 0;
00896
00897 #ifdef Q_WS_X11
00898 mySmcConnection = 0;
00899 #else
00900
00901 #endif
00902 }
00903
00904
00905 #ifdef Q_WS_X11
00906 class KAppX11HackWidget: public QWidget
00907 {
00908 public:
00909 bool publicx11Event( XEvent * e) { return x11Event( e ); }
00910 };
00911 #endif
00912
00913
00914
00915 #ifdef Q_WS_X11
00916 bool KApplication::x11EventFilter( XEvent *_event )
00917 {
00918 switch ( _event->type ) {
00919 case ClientMessage:
00920 {
00921 #if KDE_IS_VERSION( 3, 90, 90 )
00922 #ifdef __GNUC__
00923 #warning This should be already in Qt, check.
00924 #endif
00925 #endif
00926
00927
00928
00929
00930
00931 if( _event->xclient.message_type == kde_xdnd_drop )
00932 {
00933 if( _event->xclient.data.l[ 1 ] == 1 << 24
00934 && _event->xclient.data.l[ 2 ] == 0
00935 && _event->xclient.data.l[ 4 ] == 0
00936 && _event->xclient.data.l[ 3 ] != 0 )
00937 {
00938 if( QX11Info::appUserTime() == 0
00939 || NET::timestampCompare( _event->xclient.data.l[ 3 ], QX11Info::appUserTime() ) > 0 )
00940 {
00941 QX11Info::setAppUserTime(_event->xclient.data.l[ 3 ]);
00942 }
00943 }
00944 else
00945 {
00946 if( QX11Info::appUserTime() == 0
00947 || NET::timestampCompare( _event->xclient.data.l[ 2 ], QX11Info::appUserTime() ) > 0 )
00948 {
00949 QX11Info::setAppUserTime(_event->xclient.data.l[ 2 ]);
00950 }
00951 }
00952 }
00953 }
00954 default: break;
00955 }
00956
00957 if (x11Filter) {
00958 foreach (const QWidget *w, *x11Filter) {
00959 if (((KAppX11HackWidget*) w)->publicx11Event(_event))
00960 return true;
00961 }
00962 }
00963
00964 return false;
00965 }
00966 #endif // Q_WS_X11
00967
00968 void KApplication::updateUserTimestamp( int time )
00969 {
00970 #if defined Q_WS_X11
00971 if( time == 0 )
00972 {
00973 Window w = XCreateSimpleWindow( QX11Info::display(), QX11Info::appRootWindow(), 0, 0, 1, 1, 0, 0, 0 );
00974 XSelectInput( QX11Info::display(), w, PropertyChangeMask );
00975 unsigned char data[ 1 ];
00976 XChangeProperty( QX11Info::display(), w, XA_ATOM, XA_ATOM, 8, PropModeAppend, data, 1 );
00977 XEvent ev;
00978 XWindowEvent( QX11Info::display(), w, PropertyChangeMask, &ev );
00979 time = ev.xproperty.time;
00980 XDestroyWindow( QX11Info::display(), w );
00981 }
00982 if( QX11Info::appUserTime() == 0
00983 || NET::timestampCompare( time, QX11Info::appUserTime()) > 0 )
00984 QX11Info::setAppUserTime(time);
00985 if( QX11Info::appTime() == 0
00986 || NET::timestampCompare( time, QX11Info::appTime()) > 0 )
00987 QX11Info::setAppTime(time);
00988 #endif
00989 }
00990
00991 unsigned long KApplication::userTimestamp() const
00992 {
00993 #if defined Q_WS_X11
00994 return QX11Info::appUserTime();
00995 #else
00996 return 0;
00997 #endif
00998 }
00999
01000 void KApplication::updateRemoteUserTimestamp( const QString& service, int time )
01001 {
01002 #if defined Q_WS_X11
01003 Q_ASSERT(service.contains('.'));
01004 if( time == 0 )
01005 time = QX11Info::appUserTime();
01006 QDBusInterface(service, QLatin1String("/MainApplication"),
01007 QString(QLatin1String("org.kde.KApplication")))
01008 .call(QLatin1String("updateUserTimestamp"), time);
01009 #endif
01010 }
01011
01012
01013 QString KApplication::tempSaveName( const QString& pFilename )
01014 {
01015 QString aFilename;
01016
01017 if( QDir::isRelativePath(pFilename) )
01018 {
01019 kWarning(101) << "Relative filename passed to KApplication::tempSaveName";
01020 aFilename = QFileInfo( QDir( QLatin1String(".") ), pFilename ).absoluteFilePath();
01021 }
01022 else
01023 aFilename = pFilename;
01024
01025 QDir aAutosaveDir( QDir::homePath() + QLatin1String("/autosave/") );
01026 if( !aAutosaveDir.exists() )
01027 {
01028 if( !aAutosaveDir.mkdir( aAutosaveDir.absolutePath() ) )
01029 {
01030
01031 aAutosaveDir.setPath( KGlobal::dirs()->saveLocation("tmp") );
01032 }
01033 }
01034
01035 aFilename.replace( '/', QLatin1String("\\!") )
01036 .prepend( QLatin1Char('#') )
01037 .append( QLatin1Char('#') )
01038 .prepend( QLatin1Char('/') ).prepend( aAutosaveDir.absolutePath() );
01039
01040 return aFilename;
01041 }
01042
01043
01044 QString KApplication::checkRecoverFile( const QString& pFilename,
01045 bool& bRecover )
01046 {
01047 QString aFilename;
01048
01049 if( QDir::isRelativePath(pFilename) )
01050 {
01051 kWarning(101) << "Relative filename passed to KApplication::tempSaveName";
01052 aFilename = QFileInfo( QDir( QLatin1String(".") ), pFilename ).absoluteFilePath();
01053 }
01054 else
01055 aFilename = pFilename;
01056
01057 QDir aAutosaveDir( QDir::homePath() + QLatin1String("/autosave/") );
01058 if( !aAutosaveDir.exists() )
01059 {
01060 if( !aAutosaveDir.mkdir( aAutosaveDir.absolutePath() ) )
01061 {
01062
01063 aAutosaveDir.setPath( KGlobal::dirs()->saveLocation("tmp") );
01064 }
01065 }
01066
01067 aFilename.replace( QLatin1String("/"), QLatin1String("\\!") )
01068 .prepend( QLatin1Char('#') )
01069 .append( QLatin1Char('#') )
01070 .prepend( QLatin1Char('/') )
01071 .prepend( aAutosaveDir.absolutePath() );
01072
01073 if( QFile( aFilename ).exists() )
01074 {
01075 bRecover = true;
01076 return aFilename;
01077 }
01078 else
01079 {
01080 bRecover = false;
01081 return pFilename;
01082 }
01083 }
01084
01085
01086 void KApplication::setTopWidget( QWidget *topWidget )
01087 {
01088 if( !topWidget )
01089 return;
01090
01091
01092 if ( !topWidget->inherits("KMainWindow") ) {
01093 topWidget->setWindowTitle(KGlobal::caption());
01094 }
01095
01096 #if defined Q_WS_X11
01097
01098
01099 KStartupInfo::setWindowStartupId( topWidget->winId(), startupId());
01100 #endif
01101 }
01102
01103 QByteArray KApplication::startupId() const
01104 {
01105 return d->startup_id;
01106 }
01107
01108 void KApplication::setStartupId( const QByteArray& startup_id )
01109 {
01110 if( startup_id == d->startup_id )
01111 return;
01112 #if defined Q_WS_X11
01113 KStartupInfo::handleAutoAppStartedSending();
01114 #endif
01115 if( startup_id.isEmpty())
01116 d->startup_id = "0";
01117 else
01118 {
01119 d->startup_id = startup_id;
01120 #if defined Q_WS_X11
01121 KStartupInfoId id;
01122 id.initId( startup_id );
01123 long timestamp = id.timestamp();
01124 if( timestamp != 0 )
01125 updateUserTimestamp( timestamp );
01126 #endif
01127 }
01128 }
01129
01130 void KApplication::clearStartupId()
01131 {
01132 d->startup_id = "0";
01133 }
01134
01135
01136
01137
01138 void KApplicationPrivate::preread_app_startup_id()
01139 {
01140 #if defined Q_WS_X11
01141 KStartupInfoId id = KStartupInfo::currentStartupIdEnv();
01142 KStartupInfo::resetStartupEnv();
01143 startup_id_tmp = new QByteArray( id.id());
01144 #endif
01145 }
01146
01147
01148
01149 void KApplicationPrivate::read_app_startup_id()
01150 {
01151 #if defined Q_WS_X11
01152 startup_id = *startup_id_tmp;
01153 delete startup_id_tmp;
01154 startup_id_tmp = NULL;
01155 #endif
01156 }
01157
01158
01159 void KApplicationPrivate::_k_slot_KToolInvocation_hook(QStringList& envs,QByteArray& startup_id)
01160 {
01161 #ifdef Q_WS_X11
01162 if (QX11Info::display()) {
01163 QByteArray dpystring(XDisplayString(QX11Info::display()));
01164 envs << QString::fromLatin1( QByteArray("DISPLAY=") + dpystring );
01165 } else {
01166 const QByteArray dpystring( qgetenv( "DISPLAY" ));
01167 if(!dpystring.isEmpty())
01168 envs << QString::fromLatin1( QByteArray("DISPLAY=") + dpystring );
01169 }
01170
01171 if(startup_id.isEmpty())
01172 startup_id = KStartupInfo::createNewStartupId();
01173 #else
01174 Q_UNUSED(envs);
01175 Q_UNUSED(startup_id);
01176 #endif
01177 }
01178
01179 void KApplication::setSynchronizeClipboard(bool synchronize)
01180 {
01181 KClipboardSynchronizer::self()->setSynchronizing(synchronize);
01182 KClipboardSynchronizer::self()->setReverseSynchronizing(synchronize);
01183 }
01184
01185 #include "kapplication.moc"
01186