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 }
00502
00503 extern bool s_kuniqueapplication_startCalled;
00504 if ( bus && !s_kuniqueapplication_startCalled )
00505 {
00506 QStringList parts = q->organizationDomain().split(QLatin1Char('.'), QString::SkipEmptyParts);
00507 QString reversedDomain;
00508 if (parts.isEmpty())
00509 reversedDomain = QLatin1String("local.");
00510 else
00511 foreach (const QString& s, parts)
00512 {
00513 reversedDomain.prepend(QLatin1Char('.'));
00514 reversedDomain.prepend(s);
00515 }
00516 const QString pidSuffix = QString::number( getpid() ).prepend( QLatin1String("-") );
00517 const QString serviceName = reversedDomain + q->applicationName() + pidSuffix;
00518 if ( bus->registerService(serviceName) == QDBusConnectionInterface::ServiceNotRegistered ) {
00519 kError(101) << "Couldn't register name '" << serviceName << "' with DBUS - another process owns it already!" << endl;
00520 ::exit(126);
00521 }
00522 }
00523 QDBusConnection::sessionBus().registerObject(QLatin1String("/MainApplication"), q,
00524 QDBusConnection::ExportScriptableSlots |
00525 QDBusConnection::ExportScriptableProperties |
00526 QDBusConnection::ExportAdaptors);
00527
00528
00529 (void) KGlobal::locale();
00530
00531 KSharedConfig::Ptr config = componentData.config();
00532 QByteArray readOnly = qgetenv("KDE_HOME_READONLY");
00533 if (readOnly.isEmpty() && q->applicationName() != QLatin1String("kdialog"))
00534 {
00535 if (KAuthorized::authorize(QLatin1String("warn_unwritable_config")))
00536 config->isConfigWritable(true);
00537 }
00538
00539 if (q->type() == KApplication::GuiClient)
00540 {
00541 #ifdef Q_WS_X11
00542
00543 fcntl(ConnectionNumber(QX11Info::display()), F_SETFD, FD_CLOEXEC);
00544
00545 oldXErrorHandler = XSetErrorHandler( kde_x_errhandler );
00546 oldXIOErrorHandler = XSetIOErrorHandler( kde_xio_errhandler );
00547 #endif
00548
00549
00550 KGlobalSettings::self()->activate();
00551
00552 KMessage::setMessageHandler( new KMessageBoxMessageHandler(0) );
00553
00554 KCheckAccelerators::initiateIfNeeded(q);
00555 KGestureMap::self()->installEventFilterOnMe( q );
00556
00557 q->connect(KToolInvocation::self(), SIGNAL(kapplication_hook(QStringList&, QByteArray&)),
00558 q, SLOT(_k_slot_KToolInvocation_hook(QStringList&,QByteArray&)));
00559 }
00560
00561 #ifdef Q_WS_MAC
00562 if (q->type() == KApplication::GuiClient) {
00563
00564 QSystemTrayIcon *trayIcon;
00565 if (QSystemTrayIcon::isSystemTrayAvailable())
00566 {
00567 trayIcon = new QSystemTrayIcon(q);
00568 trayIcon->setIcon(q->windowIcon());
00569
00570
00571
00572 }
00573 }
00574 #endif
00575
00576 qRegisterMetaType<KUrl>();
00577 qRegisterMetaType<KUrl::List>();
00578
00579 #ifdef Q_WS_WIN
00580 KApplication_init_windows();
00581 #endif
00582 }
00583
00584 KApplication* KApplication::kApplication()
00585 {
00586 return KApp;
00587 }
00588
00589 KConfig* KApplication::sessionConfig()
00590 {
00591 if (!d->pSessionConfig)
00592 d->pSessionConfig = new KConfig( d->sessionConfigName(), KConfig::SimpleConfig );
00593 return d->pSessionConfig;
00594 }
00595
00596 void KApplication::reparseConfiguration()
00597 {
00598 KGlobal::config()->reparseConfiguration();
00599 }
00600
00601 void KApplication::quit()
00602 {
00603 QApplication::quit();
00604 }
00605
00606 void KApplication::disableSessionManagement() {
00607 d->bSessionManagement = false;
00608 }
00609
00610 void KApplication::enableSessionManagement() {
00611 d->bSessionManagement = true;
00612 #ifdef Q_WS_X11
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622 if( mySmcConnection ) {
00623 SmcRequestSaveYourself( mySmcConnection, SmSaveLocal, False,
00624 SmInteractStyleAny,
00625 False, False );
00626
00627
00628 IceFlush(SmcGetIceConnection(mySmcConnection));
00629 }
00630 #endif
00631 }
00632
00633 void KApplication::commitData( QSessionManager& sm )
00634 {
00635 d->session_save = true;
00636 bool canceled = false;
00637
00638 foreach (KSessionManager *it, KSessionManager::sessionClients()) {
00639 if ( ( canceled = !it->commitData( sm ) ) )
00640 break;
00641 }
00642
00643 if ( canceled )
00644 sm.cancel();
00645
00646 if ( sm.allowsInteraction() ) {
00647 QWidgetList donelist, todolist;
00648 QWidget* w;
00649
00650 commitDataRestart:
00651 todolist = QApplication::topLevelWidgets();
00652
00653 for ( int i = 0; i < todolist.size(); ++i ) {
00654 w = todolist.at( i );
00655 if( !w )
00656 break;
00657
00658 if ( donelist.contains( w ) )
00659 continue;
00660
00661 if ( !w->isHidden() && !w->inherits( "KMainWindow" ) ) {
00662 QCloseEvent e;
00663 sendEvent( w, &e );
00664 if ( !e.isAccepted() )
00665 break;
00666
00667 donelist.append( w );
00668
00669
00670 goto commitDataRestart;
00671 }
00672 }
00673 }
00674
00675 if ( !d->bSessionManagement )
00676 sm.setRestartHint( QSessionManager::RestartNever );
00677 else
00678 sm.setRestartHint( QSessionManager::RestartIfRunning );
00679 d->session_save = false;
00680 }
00681
00682 #ifdef Q_WS_X11
00683 static void checkRestartVersion( QSessionManager& sm )
00684 {
00685 Display* dpy = QX11Info::display();
00686 Atom type;
00687 int format;
00688 unsigned long nitems, after;
00689 unsigned char* data;
00690 if( XGetWindowProperty( dpy, RootWindow( dpy, 0 ), XInternAtom( dpy, "KDE_SESSION_VERSION", False ),
00691 0, 1, False, AnyPropertyType, &type, &format, &nitems, &after, &data ) == Success ) {
00692 if( type == XA_CARDINAL && format == 32 ) {
00693 int version = *( long* ) data;
00694 if( version == KDE_VERSION_MAJOR ) {
00695 XFree( data );
00696 return;
00697 }
00698 }
00699 XFree( data );
00700 }
00701 #define NUM_TO_STRING2( num ) #num
00702 #define NUM_TO_STRING( num ) NUM_TO_STRING2( num )
00703 QString wrapper = KStandardDirs::findExe( "kde" NUM_TO_STRING( KDE_VERSION_MAJOR ) );
00704 #undef NUM_TO_STRING
00705 #undef NUM_TO_STRING2
00706 QStringList restartCommand = sm.restartCommand();
00707 restartCommand.prepend( wrapper );
00708 sm.setRestartCommand( restartCommand );
00709 }
00710 #endif // Q_WS_X11
00711
00712 void KApplication::saveState( QSessionManager& sm )
00713 {
00714 d->session_save = true;
00715 #ifdef Q_WS_X11
00716 static bool firstTime = true;
00717 mySmcConnection = (SmcConn) sm.handle();
00718
00719 if ( !d->bSessionManagement ) {
00720 sm.setRestartHint( QSessionManager::RestartNever );
00721 d->session_save = false;
00722 return;
00723 }
00724 else
00725 sm.setRestartHint( QSessionManager::RestartIfRunning );
00726
00727 if ( firstTime ) {
00728 firstTime = false;
00729 d->session_save = false;
00730 return;
00731 }
00732
00733
00734
00735
00736
00737
00738
00739 if ( d->pSessionConfig ) {
00740 delete d->pSessionConfig;
00741 d->pSessionConfig = 0;
00742 }
00743
00744
00745 QStringList restartCommand = sm.restartCommand();
00746
00747 QByteArray multiHead = qgetenv("KDE_MULTIHEAD");
00748 if (multiHead.toLower() == "true") {
00749
00750
00751
00752
00753
00754
00755 QByteArray displayname = qgetenv("DISPLAY");
00756 if (! displayname.isNull()) {
00757
00758
00759 restartCommand.append(QLatin1String("-display"));
00760 restartCommand.append(QLatin1String(displayname));
00761 }
00762 sm.setRestartCommand( restartCommand );
00763 }
00764
00765 #ifdef Q_WS_X11
00766 checkRestartVersion( sm );
00767 #endif
00768
00769
00770 emit saveYourself();
00771 bool canceled = false;
00772 foreach(KSessionManager* it, KSessionManager::sessionClients()) {
00773 if(canceled) break;
00774 canceled = !it->saveState( sm );
00775 }
00776
00777
00778 if ( d->pSessionConfig ) {
00779 d->pSessionConfig->sync();
00780 QStringList discard;
00781 discard << QLatin1String("rm") << KStandardDirs::locateLocal("config", d->sessionConfigName());
00782 sm.setDiscardCommand( discard );
00783 } else {
00784 sm.setDiscardCommand( QStringList( QLatin1String("") ) );
00785 }
00786
00787 if ( canceled )
00788 sm.cancel();
00789 #else
00790
00791 #endif
00792 d->session_save = false;
00793 }
00794
00795 bool KApplication::sessionSaving() const
00796 {
00797 return d->session_save;
00798 }
00799
00800 void KApplicationPrivate::parseCommandLine( )
00801 {
00802 KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde");
00803
00804 if (args && args->isSet("style"))
00805 {
00806 extern QString kde_overrideStyle;
00807 QString reqStyle(args->getOption("style").toLower());
00808 if (QStyleFactory::keys().contains(reqStyle, Qt::CaseInsensitive))
00809 kde_overrideStyle = reqStyle;
00810 else
00811 qWarning() << i18n("The style '%1' was not found", reqStyle);
00812 }
00813
00814 if ( q->type() != KApplication::Tty ) {
00815 if (args && args->isSet("icon"))
00816 {
00817 q->setWindowIcon(KIcon(args->getOption("icon")));
00818 }
00819 else {
00820 q->setWindowIcon(KIcon(componentData.aboutData()->programIconName()));
00821 }
00822 }
00823
00824 if (!args)
00825 return;
00826
00827 if (args->isSet("config"))
00828 {
00829 QString config = args->getOption("config");
00830 componentData.setConfigName(config);
00831 }
00832
00833 bool nocrashhandler = (!qgetenv("KDE_DEBUG").isEmpty());
00834 if (!nocrashhandler && args->isSet("crashhandler"))
00835 {
00836
00837 KCrash::setCrashHandler(KCrash::defaultCrashHandler);
00838 }
00839
00840 KCrash::setApplicationName(args->appName());
00841
00842 #ifdef Q_WS_X11
00843 if ( args->isSet( "waitforwm" ) ) {
00844 Atom type;
00845 (void) q->desktop();
00846 int format;
00847 unsigned long length, after;
00848 unsigned char *data;
00849 while ( XGetWindowProperty( QX11Info::display(), QX11Info::appRootWindow(), atom_NetSupported,
00850 0, 1, false, AnyPropertyType, &type, &format,
00851 &length, &after, &data ) != Success || !length ) {
00852 if ( data )
00853 XFree( data );
00854 XEvent event;
00855 XWindowEvent( QX11Info::display(), QX11Info::appRootWindow(), PropertyChangeMask, &event );
00856 }
00857 if ( data )
00858 XFree( data );
00859 }
00860 #else
00861
00862 #endif
00863
00864 #ifndef Q_WS_WIN
00865 if (args->isSet("smkey"))
00866 {
00867 sessionKey = args->getOption("smkey");
00868 }
00869 #endif
00870 }
00871
00872 extern void kDebugCleanup();
00873
00874 KApplication::~KApplication()
00875 {
00876 #ifdef Q_WS_X11
00877 if ( d->oldXErrorHandler != NULL )
00878 XSetErrorHandler( d->oldXErrorHandler );
00879 if ( d->oldXIOErrorHandler != NULL )
00880 XSetIOErrorHandler( d->oldXIOErrorHandler );
00881 if ( d->oldIceIOErrorHandler != NULL )
00882 IceSetIOErrorHandler( d->oldIceIOErrorHandler );
00883 #endif
00884
00885 delete d;
00886 KApp = 0;
00887
00888 #ifdef Q_WS_X11
00889 mySmcConnection = 0;
00890 #else
00891
00892 #endif
00893 }
00894
00895
00896 #ifdef Q_WS_X11
00897 class KAppX11HackWidget: public QWidget
00898 {
00899 public:
00900 bool publicx11Event( XEvent * e) { return x11Event( e ); }
00901 };
00902 #endif
00903
00904
00905
00906 #ifdef Q_WS_X11
00907 bool KApplication::x11EventFilter( XEvent *_event )
00908 {
00909 switch ( _event->type ) {
00910 case ClientMessage:
00911 {
00912 #if KDE_IS_VERSION( 3, 90, 90 )
00913 #ifdef __GNUC__
00914 #warning This should be already in Qt, check.
00915 #endif
00916 #endif
00917
00918
00919
00920
00921
00922 if( _event->xclient.message_type == kde_xdnd_drop )
00923 {
00924 if( _event->xclient.data.l[ 1 ] == 1 << 24
00925 && _event->xclient.data.l[ 2 ] == 0
00926 && _event->xclient.data.l[ 4 ] == 0
00927 && _event->xclient.data.l[ 3 ] != 0 )
00928 {
00929 if( QX11Info::appUserTime() == 0
00930 || NET::timestampCompare( _event->xclient.data.l[ 3 ], QX11Info::appUserTime() ) > 0 )
00931 {
00932 QX11Info::setAppUserTime(_event->xclient.data.l[ 3 ]);
00933 }
00934 }
00935 else
00936 {
00937 if( QX11Info::appUserTime() == 0
00938 || NET::timestampCompare( _event->xclient.data.l[ 2 ], QX11Info::appUserTime() ) > 0 )
00939 {
00940 QX11Info::setAppUserTime(_event->xclient.data.l[ 2 ]);
00941 }
00942 }
00943 }
00944 }
00945 default: break;
00946 }
00947
00948 if (x11Filter) {
00949 foreach (const QWidget *w, *x11Filter) {
00950 if (((KAppX11HackWidget*) w)->publicx11Event(_event))
00951 return true;
00952 }
00953 }
00954
00955 return false;
00956 }
00957 #endif // Q_WS_X11
00958
00959 void KApplication::updateUserTimestamp( int time )
00960 {
00961 #if defined Q_WS_X11
00962 if( time == 0 )
00963 {
00964 Window w = XCreateSimpleWindow( QX11Info::display(), QX11Info::appRootWindow(), 0, 0, 1, 1, 0, 0, 0 );
00965 XSelectInput( QX11Info::display(), w, PropertyChangeMask );
00966 unsigned char data[ 1 ];
00967 XChangeProperty( QX11Info::display(), w, XA_ATOM, XA_ATOM, 8, PropModeAppend, data, 1 );
00968 XEvent ev;
00969 XWindowEvent( QX11Info::display(), w, PropertyChangeMask, &ev );
00970 time = ev.xproperty.time;
00971 XDestroyWindow( QX11Info::display(), w );
00972 }
00973 if( QX11Info::appUserTime() == 0
00974 || NET::timestampCompare( time, QX11Info::appUserTime()) > 0 )
00975 QX11Info::setAppUserTime(time);
00976 if( QX11Info::appTime() == 0
00977 || NET::timestampCompare( time, QX11Info::appTime()) > 0 )
00978 QX11Info::setAppTime(time);
00979 #endif
00980 }
00981
00982 unsigned long KApplication::userTimestamp() const
00983 {
00984 #if defined Q_WS_X11
00985 return QX11Info::appUserTime();
00986 #else
00987 return 0;
00988 #endif
00989 }
00990
00991 void KApplication::updateRemoteUserTimestamp( const QString& service, int time )
00992 {
00993 #if defined Q_WS_X11
00994 Q_ASSERT(service.contains('.'));
00995 if( time == 0 )
00996 time = QX11Info::appUserTime();
00997 QDBusInterface(service, QLatin1String("/MainApplication"),
00998 QString(QLatin1String("org.kde.KApplication")))
00999 .call(QLatin1String("updateUserTimestamp"), time);
01000 #endif
01001 }
01002
01003
01004 QString KApplication::tempSaveName( const QString& pFilename )
01005 {
01006 QString aFilename;
01007
01008 if( QDir::isRelativePath(pFilename) )
01009 {
01010 kWarning(101) << "Relative filename passed to KApplication::tempSaveName";
01011 aFilename = QFileInfo( QDir( QLatin1String(".") ), pFilename ).absoluteFilePath();
01012 }
01013 else
01014 aFilename = pFilename;
01015
01016 QDir aAutosaveDir( QDir::homePath() + QLatin1String("/autosave/") );
01017 if( !aAutosaveDir.exists() )
01018 {
01019 if( !aAutosaveDir.mkdir( aAutosaveDir.absolutePath() ) )
01020 {
01021
01022 aAutosaveDir.setPath( KGlobal::dirs()->saveLocation("tmp") );
01023 }
01024 }
01025
01026 aFilename.replace( '/', QLatin1String("\\!") )
01027 .prepend( QLatin1Char('#') )
01028 .append( QLatin1Char('#') )
01029 .prepend( QLatin1Char('/') ).prepend( aAutosaveDir.absolutePath() );
01030
01031 return aFilename;
01032 }
01033
01034
01035 QString KApplication::checkRecoverFile( const QString& pFilename,
01036 bool& bRecover )
01037 {
01038 QString aFilename;
01039
01040 if( QDir::isRelativePath(pFilename) )
01041 {
01042 kWarning(101) << "Relative filename passed to KApplication::tempSaveName";
01043 aFilename = QFileInfo( QDir( QLatin1String(".") ), pFilename ).absoluteFilePath();
01044 }
01045 else
01046 aFilename = pFilename;
01047
01048 QDir aAutosaveDir( QDir::homePath() + QLatin1String("/autosave/") );
01049 if( !aAutosaveDir.exists() )
01050 {
01051 if( !aAutosaveDir.mkdir( aAutosaveDir.absolutePath() ) )
01052 {
01053
01054 aAutosaveDir.setPath( KGlobal::dirs()->saveLocation("tmp") );
01055 }
01056 }
01057
01058 aFilename.replace( QLatin1String("/"), QLatin1String("\\!") )
01059 .prepend( QLatin1Char('#') )
01060 .append( QLatin1Char('#') )
01061 .prepend( QLatin1Char('/') )
01062 .prepend( aAutosaveDir.absolutePath() );
01063
01064 if( QFile( aFilename ).exists() )
01065 {
01066 bRecover = true;
01067 return aFilename;
01068 }
01069 else
01070 {
01071 bRecover = false;
01072 return pFilename;
01073 }
01074 }
01075
01076
01077 void KApplication::setTopWidget( QWidget *topWidget )
01078 {
01079 if( !topWidget )
01080 return;
01081
01082
01083 if ( !topWidget->inherits("KMainWindow") ) {
01084 topWidget->setWindowTitle(KGlobal::caption());
01085 }
01086
01087 #if defined Q_WS_X11
01088
01089
01090 KStartupInfo::setWindowStartupId( topWidget->winId(), startupId());
01091 #endif
01092 }
01093
01094 QByteArray KApplication::startupId() const
01095 {
01096 return d->startup_id;
01097 }
01098
01099 void KApplication::setStartupId( const QByteArray& startup_id )
01100 {
01101 if( startup_id == d->startup_id )
01102 return;
01103 #if defined Q_WS_X11
01104 KStartupInfo::handleAutoAppStartedSending();
01105 #endif
01106 if( startup_id.isEmpty())
01107 d->startup_id = "0";
01108 else
01109 {
01110 d->startup_id = startup_id;
01111 #if defined Q_WS_X11
01112 KStartupInfoId id;
01113 id.initId( startup_id );
01114 long timestamp = id.timestamp();
01115 if( timestamp != 0 )
01116 updateUserTimestamp( timestamp );
01117 #endif
01118 }
01119 }
01120
01121 void KApplication::clearStartupId()
01122 {
01123 d->startup_id = "0";
01124 }
01125
01126
01127
01128
01129 void KApplicationPrivate::preread_app_startup_id()
01130 {
01131 #if defined Q_WS_X11
01132 KStartupInfoId id = KStartupInfo::currentStartupIdEnv();
01133 KStartupInfo::resetStartupEnv();
01134 startup_id_tmp = new QByteArray( id.id());
01135 #endif
01136 }
01137
01138
01139
01140 void KApplicationPrivate::read_app_startup_id()
01141 {
01142 #if defined Q_WS_X11
01143 startup_id = *startup_id_tmp;
01144 delete startup_id_tmp;
01145 startup_id_tmp = NULL;
01146 #endif
01147 }
01148
01149
01150 void KApplicationPrivate::_k_slot_KToolInvocation_hook(QStringList& envs,QByteArray& startup_id)
01151 {
01152 #ifdef Q_WS_X11
01153 if (QX11Info::display()) {
01154 QByteArray dpystring(XDisplayString(QX11Info::display()));
01155 envs << QString::fromLatin1( QByteArray("DISPLAY=") + dpystring );
01156 } else {
01157 const QByteArray dpystring( qgetenv( "DISPLAY" ));
01158 if(!dpystring.isEmpty())
01159 envs << QString::fromLatin1( QByteArray("DISPLAY=") + dpystring );
01160 }
01161
01162 if(startup_id.isEmpty())
01163 startup_id = KStartupInfo::createNewStartupId();
01164 #else
01165 Q_UNUSED(envs);
01166 Q_UNUSED(startup_id);
01167 #endif
01168 }
01169
01170 void KApplication::setSynchronizeClipboard(bool synchronize)
01171 {
01172 KClipboardSynchronizer::self()->setSynchronizing(synchronize);
01173 KClipboardSynchronizer::self()->setReverseSynchronizing(synchronize);
01174 }
01175
01176 #include "kapplication.moc"
01177