kdecore Library API Documentation

kstartupinfo.cpp

00001 /****************************************************************************
00002 
00003  $Id: kstartupinfo.cpp,v 1.50.2.2 2004/03/11 12:10:32 lunakl Exp $
00004 
00005  Copyright (C) 2001-2003 Lubos Lunak        <l.lunak@kde.org>
00006 
00007 Permission is hereby granted, free of charge, to any person obtaining a
00008 copy of this software and associated documentation files (the "Software"),
00009 to deal in the Software without restriction, including without limitation
00010 the rights to use, copy, modify, merge, publish, distribute, sublicense,
00011 and/or sell copies of the Software, and to permit persons to whom the
00012 Software is furnished to do so, subject to the following conditions:
00013 
00014 The above copyright notice and this permission notice shall be included in
00015 all copies or substantial portions of the Software.
00016 
00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
00020 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00021 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00022 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00023 DEALINGS IN THE SOFTWARE.
00024 
00025 ****************************************************************************/
00026 
00027 // kdDebug() can't be turned off in kdeinit
00028 #if 0
00029 #define KSTARTUPINFO_ALL_DEBUG
00030 #warning Extra KStartupInfo debug messages enabled.
00031 #endif
00032 
00033 #include <qwidget.h>
00034 
00035 #include "config.h"
00036 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00037 //#ifdef Q_WS_X11 // FIXME(E): Re-implement in a less X11 specific way
00038 #include <qglobal.h>
00039 #ifdef HAVE_CONFIG_H
00040 #include <config.h>
00041 #endif
00042 
00043 // need to resolve INT32(qglobal.h)<>INT32(Xlibint.h) conflict
00044 #ifndef QT_CLEAN_NAMESPACE
00045 #define QT_CLEAN_NAMESPACE
00046 #endif
00047 
00048 #include "kstartupinfo.h"
00049 
00050 #include <unistd.h>
00051 #include <sys/time.h>
00052 #include <stdlib.h>
00053 #include <qtimer.h>
00054 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00055 #include <netwm.h> // schroder
00056 #endif
00057 #include <kdebug.h>
00058 #include <kapplication.h>
00059 #include <signal.h>
00060 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00061 #include <kwinmodule.h> // schroder
00062 #include <kxmessages.h> // schroder
00063 #include <kwin.h>
00064 extern Time qt_x_time;
00065 #endif
00066 
00067 static const char* const NET_STARTUP_MSG = "_NET_STARTUP_INFO";
00068 static const char* const NET_STARTUP_WINDOW = "_NET_STARTUP_ID";
00069 // DESKTOP_STARTUP_ID is used also in kinit/wrapper.c
00070 static const char* const NET_STARTUP_ENV = "DESKTOP_STARTUP_ID";
00071 
00072 static bool auto_app_started_sending = true;
00073 
00074 static long get_num( const QString& item_P );
00075 static unsigned long get_unum( const QString& item_P );
00076 static QString get_str( const QString& item_P );
00077 static QCString get_cstr( const QString& item_P );
00078 static QStringList get_fields( const QString& txt_P );
00079 static QString escape_str( const QString& str_P );
00080 
00081 static Atom utf8_string_atom = None;
00082 
00083 class KStartupInfo::Data
00084     : public KStartupInfoData
00085     {
00086     public:
00087         Data() {}; // just because it's in a QMap
00088         Data( const QString& txt_P )
00089             : KStartupInfoData( txt_P ), age( 0 ) {};
00090         unsigned int age;
00091     };
00092 
00093 struct KStartupInfoPrivate
00094     {
00095     public:
00096         QMap< KStartupInfoId, KStartupInfo::Data > startups;
00097     // contains silenced ASN's only if !AnnounceSilencedChanges
00098         QMap< KStartupInfoId, KStartupInfo::Data > silent_startups;
00099 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00100         KWinModule* wm_module;
00101         KXMessages msgs;
00102 #endif
00103     QTimer* cleanup;
00104     int flags;
00105     KStartupInfoPrivate( int flags_P )
00106             :
00107 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00108         msgs( NET_STARTUP_MSG, NULL, false ),
00109 #endif
00110           flags( flags_P ) {}
00111     };
00112 
00113 KStartupInfo::KStartupInfo( int flags_P, QObject* parent_P, const char* name_P )
00114     : QObject( parent_P, name_P ),
00115         timeout( 60 ), d( NULL )
00116     {
00117     init( flags_P );
00118     }
00119 
00120 KStartupInfo::KStartupInfo( bool clean_on_cantdetect_P, QObject* parent_P, const char* name_P )
00121     : QObject( parent_P, name_P ),
00122         timeout( 60 ), d( NULL )
00123     {
00124     init( clean_on_cantdetect_P ? CleanOnCantDetect : 0 );
00125     }
00126 
00127 void KStartupInfo::init( int flags_P )
00128     {
00129     // d == NULL means "disabled"
00130     if( !KApplication::kApplication())
00131         return;
00132     if( !KApplication::kApplication()->getDisplay())
00133         return;
00134 
00135     d = new KStartupInfoPrivate( flags_P );
00136 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00137     if( !( d->flags & DisableKWinModule ))
00138         {
00139         d->wm_module = new KWinModule( this );
00140         connect( d->wm_module, SIGNAL( windowAdded( WId )), SLOT( slot_window_added( WId )));
00141         connect( d->wm_module, SIGNAL( systemTrayWindowAdded( WId )), SLOT( slot_window_added( WId )));
00142         }
00143     else
00144         d->wm_module = NULL;
00145     connect( &d->msgs, SIGNAL( gotMessage( const QString& )), SLOT( got_message( const QString& )));
00146 #endif
00147     d->cleanup = new QTimer( this );
00148     connect( d->cleanup, SIGNAL( timeout()), SLOT( startups_cleanup()));
00149     }
00150 
00151 KStartupInfo::~KStartupInfo()
00152     {
00153     delete d;
00154     }
00155 
00156 void KStartupInfo::got_message( const QString& msg_P )
00157     {
00158 // TODO do something with SCREEN= ?
00159     kdDebug( 172 ) << "got:" << msg_P << endl;
00160     QString msg = msg_P.stripWhiteSpace();
00161     if( msg.startsWith( "new:" )) // must match length below
00162         got_startup_info( msg.mid( 4 ), false );
00163     else if( msg.startsWith( "change:" )) // must match length below
00164         got_startup_info( msg.mid( 7 ), true );
00165     else if( msg.startsWith( "remove:" )) // must match length below
00166         got_remove_startup_info( msg.mid( 7 ));
00167     }
00168 
00169 // if the application stops responding for a while, KWinModule may get
00170 // the information about the already mapped window before KXMessages
00171 // actually gets the info about the started application (depends
00172 // on their order in X11 event filter in KApplication)
00173 // simply delay info from KWinModule a bit
00174 // SELI???
00175 namespace
00176 {
00177 class DelayedWindowEvent
00178     : public QCustomEvent
00179     {
00180     public:
00181     DelayedWindowEvent( WId w_P )
00182         : QCustomEvent( QEvent::User + 15 ), w( w_P ) {}
00183     Window w;
00184     };
00185 }
00186 
00187 void KStartupInfo::slot_window_added( WId w_P )
00188     {
00189     kapp->postEvent( this, new DelayedWindowEvent( w_P ));
00190     }
00191 
00192 void KStartupInfo::customEvent( QCustomEvent* e_P )
00193     {
00194     if( e_P->type() == QEvent::User + 15 )
00195     window_added( static_cast< DelayedWindowEvent* >( e_P )->w );
00196     else
00197     QObject::customEvent( e_P );
00198     }
00199 
00200 void KStartupInfo::window_added( WId w_P )
00201     {
00202     KStartupInfoId id;
00203     KStartupInfoData data;
00204     startup_t ret = check_startup_internal( w_P, &id, &data );
00205     switch( ret )
00206         {
00207         case Match:
00208             kdDebug( 172 ) << "new window match" << endl;
00209           break;
00210         case NoMatch:
00211           break; // nothing
00212         case CantDetect:
00213             if( d->flags & CleanOnCantDetect )
00214                 clean_all_noncompliant();
00215           break;
00216         }
00217     }
00218 
00219 void KStartupInfo::got_startup_info( const QString& msg_P, bool update_only_P )
00220     {
00221     KStartupInfoId id( msg_P );
00222     if( id.none())
00223         return;
00224     KStartupInfo::Data data( msg_P );
00225     new_startup_info_internal( id, data, update_only_P );
00226     }
00227 
00228 void KStartupInfo::new_startup_info_internal( const KStartupInfoId& id_P,
00229     Data& data_P, bool update_only_P )
00230     {
00231     if( d == NULL )
00232         return;
00233     if( id_P.none())
00234         return;
00235     if( d->startups.contains( id_P ))
00236         { // already reported, update
00237         d->startups[ id_P ].update( data_P );
00238         d->startups[ id_P ].age = 0; // CHECKME
00239         kdDebug( 172 ) << "updating" << endl;
00240     if( d->startups[ id_P ].silent() == Data::Yes
00241         && !( d->flags & AnnounceSilenceChanges ))
00242         {
00243         d->silent_startups[ id_P ] = d->startups[ id_P ];
00244         d->startups.remove( id_P );
00245         emit gotRemoveStartup( id_P, d->silent_startups[ id_P ] );
00246         return;
00247         }
00248         emit gotStartupChange( id_P, d->startups[ id_P ] );
00249         return;
00250         }
00251     if( d->silent_startups.contains( id_P ))
00252         { // already reported, update
00253         d->silent_startups[ id_P ].update( data_P );
00254         d->silent_startups[ id_P ].age = 0; // CHECKME
00255         kdDebug( 172 ) << "updating silenced" << endl;
00256     if( d->silent_startups[ id_P ].silent() != Data::Yes )
00257         {
00258         d->startups[ id_P ] = d->silent_startups[ id_P ];
00259         d->silent_startups.remove( id_P );
00260         emit gotNewStartup( id_P, d->startups[ id_P ] );
00261         return;
00262         }
00263         emit gotStartupChange( id_P, d->startups[ id_P ] );
00264         return;
00265         }
00266     if( update_only_P )
00267         return;
00268     if( data_P.silent() != Data::Yes || d->flags & AnnounceSilenceChanges )
00269     {
00270         kdDebug( 172 ) << "adding" << endl;
00271         d->startups.insert( id_P, data_P );
00272     emit gotNewStartup( id_P, data_P );
00273     }
00274     else // new silenced, and silent shouldn't be announced
00275     {
00276         kdDebug( 172 ) << "adding silent" << endl;
00277     d->silent_startups.insert( id_P, data_P );
00278     }
00279     d->cleanup->start( 1000 ); // 1 sec
00280     }
00281 
00282 void KStartupInfo::got_remove_startup_info( const QString& msg_P )
00283     {
00284     KStartupInfoId id( msg_P );
00285     KStartupInfoData data( msg_P );
00286     if( data.pids().count() > 0 )
00287         {
00288         if( !id.none())
00289             remove_startup_pids( id, data );
00290         else
00291             remove_startup_pids( data );
00292         return;
00293         }
00294     remove_startup_info_internal( id );
00295     }
00296 
00297 void KStartupInfo::remove_startup_info_internal( const KStartupInfoId& id_P )
00298     {
00299     if( d == NULL )
00300         return;
00301     if( d->startups.contains( id_P ))
00302         {
00303     kdDebug( 172 ) << "removing" << endl;
00304     emit gotRemoveStartup( id_P, d->startups[ id_P ]);
00305     d->startups.remove( id_P );
00306     }
00307     else if( d->silent_startups.contains( id_P ))
00308     {
00309     kdDebug( 172 ) << "removing silent" << endl;
00310     d->silent_startups.remove( id_P );
00311     }
00312     return;
00313     }
00314 
00315 void KStartupInfo::remove_startup_pids( const KStartupInfoData& data_P )
00316     { // first find the matching info
00317     if( d == NULL )
00318         return;
00319     for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin();
00320          it != d->startups.end();
00321          ++it )
00322         {
00323         if( ( *it ).hostname() != data_P.hostname())
00324             continue;
00325         if( !( *it ).is_pid( data_P.pids().first()))
00326             continue; // not the matching info
00327         remove_startup_pids( it.key(), data_P );
00328         break;
00329         }
00330     }
00331 
00332 void KStartupInfo::remove_startup_pids( const KStartupInfoId& id_P,
00333     const KStartupInfoData& data_P )
00334     {
00335     if( d == NULL )
00336         return;
00337     kdFatal( data_P.pids().count() == 0, 172 );
00338     Data* data = NULL;
00339     if( d->startups.contains( id_P ))
00340     data = &d->startups[ id_P ];
00341     else if( d->silent_startups.contains( id_P ))
00342     data = &d->silent_startups[ id_P ];
00343     else
00344     return;
00345     for( QValueList< pid_t >::ConstIterator it2 = data_P.pids().begin();
00346          it2 != data_P.pids().end();
00347          ++it2 )
00348     data->remove_pid( *it2 ); // remove all pids from the info
00349     if( data->pids().count() == 0 ) // all pids removed -> remove info
00350         remove_startup_info_internal( id_P );
00351     }
00352 
00353 bool KStartupInfo::sendStartup( const KStartupInfoId& id_P, const KStartupInfoData& data_P )
00354     {
00355     if( id_P.none())
00356         return false;
00357     KXMessages msgs;
00358     QString msg = QString::fromLatin1( "new: %1 %2" )
00359         .arg( id_P.to_text()).arg( data_P.to_text());
00360     msg = check_required_startup_fields( msg, data_P, qt_xscreen());
00361     kdDebug( 172 ) << "sending " << msg << endl;
00362     msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
00363     return true;
00364     }
00365 
00366 bool KStartupInfo::sendStartupX( Display* disp_P, const KStartupInfoId& id_P,
00367     const KStartupInfoData& data_P )
00368     {
00369     if( id_P.none())
00370         return false;
00371     QString msg = QString::fromLatin1( "new: %1 %2" )
00372         .arg( id_P.to_text()).arg( data_P.to_text());
00373     msg = check_required_startup_fields( msg, data_P, DefaultScreen( disp_P ));
00374 #ifdef KSTARTUPINFO_ALL_DEBUG
00375     kdDebug( 172 ) << "sending " << msg << endl;
00376 #endif
00377     return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
00378     }
00379 
00380 QString KStartupInfo::check_required_startup_fields( const QString& msg, const KStartupInfoData& data_P,
00381     int screen )
00382     {
00383     QString ret = msg;
00384     if( data_P.name().isEmpty())
00385         {
00386 //        kdWarning( 172 ) << "NAME not specified in initial startup message" << endl;
00387         QString name = data_P.bin();
00388         if( name.isEmpty())
00389             name = "UNKNOWN";
00390         ret += QString( " NAME=\"%1\"" ).arg( escape_str( name ));
00391         }
00392     if( data_P.screen() == -1 ) // add automatically if needed
00393         ret += QString( " SCREEN=%1" ).arg( screen );
00394     return ret;
00395     }
00396 
00397 bool KStartupInfo::sendChange( const KStartupInfoId& id_P, const KStartupInfoData& data_P )
00398     {
00399     if( id_P.none())
00400         return false;
00401     KXMessages msgs;
00402     QString msg = QString::fromLatin1( "change: %1 %2" )
00403         .arg( id_P.to_text()).arg( data_P.to_text());
00404     kdDebug( 172 ) << "sending " << msg << endl;
00405     msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
00406     return true;
00407     }
00408 
00409 bool KStartupInfo::sendChangeX( Display* disp_P, const KStartupInfoId& id_P,
00410     const KStartupInfoData& data_P )
00411     {
00412     if( id_P.none())
00413         return false;
00414     QString msg = QString::fromLatin1( "change: %1 %2" )
00415         .arg( id_P.to_text()).arg( data_P.to_text());
00416 #ifdef KSTARTUPINFO_ALL_DEBUG
00417     kdDebug( 172 ) << "sending " << msg << endl;
00418 #endif
00419     return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
00420     }
00421 
00422 bool KStartupInfo::sendFinish( const KStartupInfoId& id_P )
00423     {
00424     if( id_P.none())
00425         return false;
00426     KXMessages msgs;
00427     QString msg = QString::fromLatin1( "remove: %1" ).arg( id_P.to_text());
00428     kdDebug( 172 ) << "sending " << msg << endl;
00429     msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
00430     return true;
00431     }
00432 
00433 bool KStartupInfo::sendFinishX( Display* disp_P, const KStartupInfoId& id_P )
00434     {
00435     if( id_P.none())
00436         return false;
00437     QString msg = QString::fromLatin1( "remove: %1" ).arg( id_P.to_text());
00438 #ifdef KSTARTUPINFO_ALL_DEBUG
00439     kdDebug( 172 ) << "sending " << msg << endl;
00440 #endif
00441     return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
00442     }
00443 
00444 bool KStartupInfo::sendFinish( const KStartupInfoId& id_P, const KStartupInfoData& data_P )
00445     {
00446 //    if( id_P.none()) // id may be none, the pids and hostname matter then
00447 //        return false;
00448     KXMessages msgs;
00449     QString msg = QString::fromLatin1( "remove: %1 %2" )
00450         .arg( id_P.to_text()).arg( data_P.to_text());
00451     kdDebug( 172 ) << "sending " << msg << endl;
00452     msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
00453     return true;
00454     }
00455 
00456 bool KStartupInfo::sendFinishX( Display* disp_P, const KStartupInfoId& id_P,
00457     const KStartupInfoData& data_P )
00458     {
00459 //    if( id_P.none()) // id may be none, the pids and hostname matter then
00460 //        return false;
00461     QString msg = QString::fromLatin1( "remove: %1 %2" )
00462         .arg( id_P.to_text()).arg( data_P.to_text());
00463 #ifdef KSTARTUPINFO_ALL_DEBUG
00464     kdDebug( 172 ) << "sending " << msg << endl;
00465 #endif
00466     return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
00467     }
00468 
00469 void KStartupInfo::appStarted()
00470     {
00471     if( kapp != NULL )  // KApplication constructor unsets the env. variable
00472         appStarted( kapp->startupId());
00473     else
00474         appStarted( KStartupInfo::currentStartupIdEnv().id());
00475     }
00476 
00477 void KStartupInfo::appStarted( const QCString& startup_id )
00478     {
00479     KStartupInfoId id;
00480     id.initId( startup_id );
00481     if( id.none())
00482         return;
00483     if( kapp != NULL )
00484         KStartupInfo::sendFinish( id );
00485     else if( getenv( "DISPLAY" ) != NULL ) // don't rely on qt_xdisplay()
00486         {
00487 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00488         Display* disp = XOpenDisplay( NULL );
00489         if( disp != NULL )
00490             {
00491             KStartupInfo::sendFinishX( disp, id );
00492             XCloseDisplay( disp );
00493             }
00494 #endif
00495         }
00496     }
00497 
00498 void KStartupInfo::disableAutoAppStartedSending( bool disable )
00499     {
00500     auto_app_started_sending = !disable;
00501     }
00502 
00503 void KStartupInfo::silenceStartup( bool silence )
00504     {
00505     KStartupInfoId id;
00506     id.initId( kapp->startupId());
00507     if( id.none())
00508         return;
00509     KStartupInfoData data;
00510     data.setSilent( silence ? KStartupInfoData::Yes : KStartupInfoData::No );
00511     sendChange( id, data );
00512     }
00513 
00514 void KStartupInfo::handleAutoAppStartedSending()
00515     {
00516     if( auto_app_started_sending )
00517         appStarted();
00518     }
00519 
00520 void KStartupInfo::setNewStartupId( QWidget* window, const QCString& startup_id )
00521     {
00522     long activate = true;
00523     kapp->setStartupId( startup_id );
00524     if( window != NULL )
00525         {
00526         if( !startup_id.isEmpty() && startup_id != "0" )
00527             {
00528             NETRootInfo i( qt_xdisplay(), NET::Supported );
00529             if( i.isSupported( NET::WM2StartupId ))
00530                 {
00531                 KStartupInfo::setWindowStartupId( window->winId(), startup_id );
00532                 activate = false; // WM will take care of it
00533                 }
00534             }
00535         if( activate )
00536         // This is not very nice, but there's no way how to get any
00537         // usable timestamp without ASN, so force activating the window.
00538         // And even with ASN, it's not possible to get the timestamp here,
00539         // so if the WM doesn't have support for ASN, it can't be used either.
00540             KWin::forceActiveWindow( window->winId());
00541         }
00542     KStartupInfo::handleAutoAppStartedSending();
00543     }
00544 
00545 KStartupInfo::startup_t KStartupInfo::checkStartup( WId w_P, KStartupInfoId& id_O,
00546     KStartupInfoData& data_O )
00547     {
00548     return check_startup_internal( w_P, &id_O, &data_O );
00549     }
00550 
00551 KStartupInfo::startup_t KStartupInfo::checkStartup( WId w_P, KStartupInfoId& id_O )
00552     {
00553     return check_startup_internal( w_P, &id_O, NULL );
00554     }
00555 
00556 KStartupInfo::startup_t KStartupInfo::checkStartup( WId w_P, KStartupInfoData& data_O )
00557     {
00558     return check_startup_internal( w_P, NULL, &data_O );
00559     }
00560 
00561 KStartupInfo::startup_t KStartupInfo::checkStartup( WId w_P )
00562     {
00563     return check_startup_internal( w_P, NULL, NULL );
00564     }
00565 
00566 KStartupInfo::startup_t KStartupInfo::check_startup_internal( WId w_P, KStartupInfoId* id_O,
00567     KStartupInfoData* data_O )
00568     {
00569     if( d == NULL )
00570         return NoMatch;
00571     if( d->startups.count() == 0 )
00572         return NoMatch; // no startups
00573 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00574 // SELI ???
00575     NETWinInfo info( qt_xdisplay(),  w_P, qt_xrootwin(),
00576         NET::WMWindowType | NET::WMPid | NET::WMState );
00577     // ignore NET::Tool and other special window types
00578     NET::WindowType type = info.windowType( NET::NormalMask | NET::DesktopMask
00579         | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
00580         | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask );
00581     if( type != NET::Normal
00582         && type != NET::Override
00583         && type != NET::Unknown
00584         && type != NET::Dialog
00585         && type != NET::Utility )
00586 //        && type != NET::Dock ) why did I put this here?
00587     return NoMatch;
00588     // lets see if this is a transient
00589     Window transient_for;
00590     if( XGetTransientForHint( qt_xdisplay(), static_cast< Window >( w_P ), &transient_for )
00591         && static_cast< WId >( transient_for ) != qt_xrootwin()
00592         && transient_for != None )
00593     return NoMatch;
00594 #endif
00595     // Strategy:
00596     //
00597     // Is this a compliant app ?
00598     //  - Yes - test for match
00599     //  - No - Is this a NET_WM compliant app ?
00600     //           - Yes - test for pid match
00601     //           - No - test for WM_CLASS match
00602     kdDebug( 172 ) << "check_startup" << endl;
00603     QCString id = windowStartupId( w_P );
00604     if( !id.isNull())
00605         {
00606         if( id.isEmpty() || id == "0" ) // means ignore this window
00607             {
00608             kdDebug( 172 ) << "ignore" << endl;
00609             return NoMatch;
00610             }
00611         return find_id( id, id_O, data_O ) ? Match : NoMatch;
00612         }
00613 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00614     pid_t pid = info.pid();
00615     if( pid > 0 )
00616         {
00617         QCString hostname = get_window_hostname( w_P );
00618         if( !hostname.isEmpty()
00619             && find_pid( pid, hostname, id_O, data_O ))
00620             return Match;
00621         // try XClass matching , this PID stuff sucks :(
00622         }
00623     XClassHint hint;
00624     if( XGetClassHint( qt_xdisplay(), w_P, &hint ) != 0 )
00625         { // We managed to read the class hint
00626         QCString res_name = hint.res_name;
00627         QCString res_class = hint.res_class;
00628         XFree( hint.res_name );
00629         XFree( hint.res_class );
00630         if( find_wclass( res_name, res_class, id_O, data_O ))
00631             return Match;
00632         }
00633 #endif
00634     kdDebug( 172 ) << "check_startup:cantdetect" << endl;
00635     return CantDetect;
00636     }
00637 
00638 bool KStartupInfo::find_id( const QCString& id_P, KStartupInfoId* id_O,
00639     KStartupInfoData* data_O )
00640     {
00641     if( d == NULL )
00642         return false;
00643     kdDebug( 172 ) << "find_id:" << id_P << endl;
00644     KStartupInfoId id;
00645     id.initId( id_P );
00646     if( d->startups.contains( id ))
00647         {
00648         if( id_O != NULL )
00649             *id_O = id;
00650         if( data_O != NULL )
00651             *data_O = d->startups[ id ];
00652         kdDebug( 172 ) << "check_startup_id:match" << endl;
00653         return true;
00654         }
00655     return false;
00656     }
00657 
00658 bool KStartupInfo::find_pid( pid_t pid_P, const QCString& hostname_P,
00659     KStartupInfoId* id_O, KStartupInfoData* data_O )
00660     {
00661     if( d == NULL )
00662         return false;
00663     kdDebug( 172 ) << "find_pid:" << pid_P << endl;
00664     for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin();
00665          it != d->startups.end();
00666          ++it )
00667         {
00668         if( ( *it ).is_pid( pid_P ) && ( *it ).hostname() == hostname_P )
00669             { // Found it !
00670             if( id_O != NULL )
00671                 *id_O = it.key();
00672             if( data_O != NULL )
00673                 *data_O = *it;
00674             // non-compliant, remove on first match
00675             remove_startup_info_internal( it.key());
00676             kdDebug( 172 ) << "check_startup_pid:match" << endl;
00677             return true;
00678             }
00679         }
00680     return false;
00681     }
00682 
00683 bool KStartupInfo::find_wclass( QCString res_name, QCString res_class,
00684     KStartupInfoId* id_O, KStartupInfoData* data_O )
00685     {
00686     if( d == NULL )
00687         return false;
00688     res_name = res_name.lower();
00689     res_class = res_class.lower();
00690     kdDebug( 172 ) << "find_wclass:" << res_name << ":" << res_class << endl;
00691     for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin();
00692          it != d->startups.end();
00693          ++it )
00694         {
00695         const QCString wmclass = ( *it ).findWMClass();
00696         if( wmclass.lower() == res_name || wmclass.lower() == res_class )
00697             { // Found it !
00698             if( id_O != NULL )
00699                 *id_O = it.key();
00700             if( data_O != NULL )
00701                 *data_O = *it;
00702             // non-compliant, remove on first match
00703             remove_startup_info_internal( it.key());
00704             kdDebug( 172 ) << "check_startup_wclass:match" << endl;
00705             return true;
00706             }
00707         }
00708     return false;
00709     }
00710 
00711 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00712 static Atom net_startup_atom = None;
00713 #endif
00714 
00715 QCString KStartupInfo::windowStartupId( WId w_P )
00716     {
00717 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00718     if( net_startup_atom == None )
00719         net_startup_atom = XInternAtom( qt_xdisplay(), NET_STARTUP_WINDOW, False );
00720     if( utf8_string_atom == None )
00721         utf8_string_atom = XInternAtom( qt_xdisplay(), "UTF8_STRING", False );
00722     unsigned char *name_ret;
00723     QCString ret;
00724     Atom type_ret;
00725     int format_ret;
00726     unsigned long nitems_ret = 0, after_ret = 0;
00727     if( XGetWindowProperty( qt_xdisplay(), w_P, net_startup_atom, 0l, 4096,
00728             False, utf8_string_atom, &type_ret, &format_ret, &nitems_ret, &after_ret, &name_ret )
00729         == Success )
00730         {
00731     if( type_ret == utf8_string_atom && format_ret == 8 && name_ret != NULL )
00732         ret = reinterpret_cast< char* >( name_ret );
00733         if ( name_ret != NULL )
00734             XFree( name_ret );
00735         }
00736     return ret;
00737 #else
00738     return QCString();
00739 #endif
00740     }
00741 
00742 void KStartupInfo::setWindowStartupId( WId w_P, const QCString& id_P )
00743     {
00744 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00745     if( id_P.isNull())
00746         return;
00747     if( net_startup_atom == None )
00748         net_startup_atom = XInternAtom( qt_xdisplay(), NET_STARTUP_WINDOW, False );
00749     if( utf8_string_atom == None )
00750         utf8_string_atom = XInternAtom( qt_xdisplay(), "UTF8_STRING", False );
00751     XChangeProperty( qt_xdisplay(), w_P, net_startup_atom, utf8_string_atom, 8,
00752         PropModeReplace, reinterpret_cast< unsigned char* >( id_P.data()), id_P.length());
00753 #endif
00754     }
00755 
00756 QCString KStartupInfo::get_window_hostname( WId w_P )
00757     {
00758 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00759     XTextProperty tp;
00760     char** hh;
00761     int cnt;
00762     if( XGetWMClientMachine( qt_xdisplay(), w_P, &tp ) != 0
00763         && XTextPropertyToStringList( &tp, &hh, &cnt ) != 0 )
00764         {
00765         if( cnt == 1 )
00766             {
00767             QCString hostname = hh[ 0 ];
00768             XFreeStringList( hh );
00769             return hostname;
00770             }
00771         XFreeStringList( hh );
00772         }
00773 #endif
00774     // no hostname
00775     return QCString();
00776     }
00777 
00778 void KStartupInfo::setTimeout( unsigned int secs_P )
00779     {
00780     timeout = secs_P;
00781  // schedule removing entries that are older than the new timeout
00782     QTimer::singleShot( 0, this, SLOT( startups_cleanup_no_age()));
00783     }
00784 
00785 void KStartupInfo::startups_cleanup_no_age()
00786     {
00787     startups_cleanup_internal( false );
00788     }
00789 
00790 void KStartupInfo::startups_cleanup()
00791     {
00792     if( d == NULL )
00793         return;
00794     if( d->startups.count() == 0 && d->silent_startups.count() == 0 )
00795         {
00796         d->cleanup->stop();
00797         return;
00798         }
00799     startups_cleanup_internal( true );
00800     }
00801 
00802 void KStartupInfo::startups_cleanup_internal( bool age_P )
00803     {
00804     if( d == NULL )
00805         return;
00806     for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin();
00807          it != d->startups.end();
00808          )
00809         {
00810         if( age_P )
00811             ( *it ).age++;
00812     int tout = timeout;
00813     if( ( *it ).silent() == Data::Yes ) // TODO
00814         tout *= 20;
00815         if( ( *it ).age >= timeout )
00816             {
00817             const KStartupInfoId& key = it.key();
00818             ++it;
00819             kdDebug( 172 ) << "entry timeout:" << key.id() << endl;
00820             remove_startup_info_internal( key );
00821             }
00822         else
00823             ++it;
00824         }
00825     for( QMap< KStartupInfoId, Data >::Iterator it = d->silent_startups.begin();
00826          it != d->silent_startups.end();
00827          )
00828         {
00829         if( age_P )
00830             ( *it ).age++;
00831     int tout = timeout;
00832     if( ( *it ).silent() == Data::Yes ) // TODO
00833         tout *= 20;
00834         if( ( *it ).age >= timeout )
00835             {
00836             const KStartupInfoId& key = it.key();
00837             ++it;
00838             kdDebug( 172 ) << "entry timeout:" << key.id() << endl;
00839             remove_startup_info_internal( key );
00840             }
00841         else
00842             ++it;
00843         }
00844     }
00845 
00846 void KStartupInfo::clean_all_noncompliant()
00847     {
00848     if( d == NULL )
00849         return;
00850     for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin();
00851          it != d->startups.end();
00852          )
00853         {
00854         if( ( *it ).WMClass() != "0" )
00855             {
00856             ++it;
00857             continue;
00858             }
00859         const KStartupInfoId& key = it.key();
00860         ++it;
00861         kdDebug( 172 ) << "entry cleaning:" << key.id() << endl;
00862         remove_startup_info_internal( key );
00863         }
00864     }
00865 
00866 struct KStartupInfoIdPrivate
00867     {
00868     KStartupInfoIdPrivate() : id( "" ) {};
00869     QCString id; // id
00870     };
00871 
00872 const QCString& KStartupInfoId::id() const
00873     {
00874     return d->id;
00875     }
00876 
00877 
00878 QString KStartupInfoId::to_text() const
00879     {
00880     return QString::fromLatin1( " ID=\"%1\" " ).arg( escape_str( id()));
00881     }
00882 
00883 KStartupInfoId::KStartupInfoId( const QString& txt_P )
00884     {
00885     d = new KStartupInfoIdPrivate;
00886     QStringList items = get_fields( txt_P );
00887     const QString id_str = QString::fromLatin1( "ID=" );
00888     for( QStringList::Iterator it = items.begin();
00889          it != items.end();
00890          ++it )
00891         {
00892         if( ( *it ).startsWith( id_str ))
00893             d->id = get_cstr( *it );
00894         }
00895     }
00896 
00897 void KStartupInfoId::initId( const QCString& id_P )
00898     {
00899     if( !id_P.isEmpty())
00900         {
00901         d->id = id_P;
00902 #ifdef KSTARTUPINFO_ALL_DEBUG
00903         kdDebug( 172 ) << "using: " << d->id << endl;
00904 #endif
00905         return;
00906         }
00907     const char* startup_env = getenv( NET_STARTUP_ENV );
00908     if( startup_env != NULL && *startup_env != '\0' )
00909         { // already has id
00910         d->id = startup_env;
00911 #ifdef KSTARTUPINFO_ALL_DEBUG
00912         kdDebug( 172 ) << "reusing: " << d->id << endl;
00913 #endif
00914         return;
00915         }
00916     // assign a unique id  CHECKME
00917     // use hostname+time+pid, that should be 200% unique
00918     // hmm, probably something 99.9% unique and much shorter would be enough
00919     struct timeval tm;
00920     gettimeofday( &tm, NULL );
00921     char hostname[ 256 ];
00922     hostname[ 0 ] = '\0';
00923     if (!gethostname( hostname, 255 ))
00924     hostname[sizeof(hostname)-1] = '\0';
00925     d->id = QString( "%1;%2;%3;%4" ).arg( hostname ).arg( tm.tv_sec )
00926         .arg( tm.tv_usec ).arg( getpid()).utf8();
00927 #ifdef KSTARTUPINFO_ALL_DEBUG
00928     kdDebug( 172 ) << "creating: " << d->id << endl;
00929 #endif
00930     }
00931 
00932 bool KStartupInfoId::setupStartupEnv() const
00933     {
00934     if( id().isEmpty())
00935         {
00936         unsetenv( NET_STARTUP_ENV );
00937         return false;
00938         }
00939     return setenv( NET_STARTUP_ENV, id(), true ) == 0;
00940     }
00941 
00942 KStartupInfoId KStartupInfo::currentStartupIdEnv()
00943     {
00944     const char* startup_env = getenv( NET_STARTUP_ENV );
00945     KStartupInfoId id;
00946     if( startup_env != NULL && *startup_env != '\0' )
00947         id.d->id = startup_env;
00948     else
00949         id.d->id = "0";
00950     return id;
00951     }
00952 
00953 void KStartupInfo::resetStartupEnv()
00954     {
00955     unsetenv( NET_STARTUP_ENV );
00956     }
00957 
00958 KStartupInfoId::KStartupInfoId()
00959     {
00960     d = new KStartupInfoIdPrivate;
00961     }
00962 
00963 KStartupInfoId::~KStartupInfoId()
00964     {
00965     delete d;
00966     }
00967 
00968 KStartupInfoId::KStartupInfoId( const KStartupInfoId& id_P )
00969     {
00970     d = new KStartupInfoIdPrivate( *id_P.d );
00971     }
00972 
00973 KStartupInfoId& KStartupInfoId::operator=( const KStartupInfoId& id_P )
00974     {
00975     if( &id_P == this )
00976         return *this;
00977     delete d;
00978     d = new KStartupInfoIdPrivate( *id_P.d );
00979     return *this;
00980     }
00981 
00982 bool KStartupInfoId::operator==( const KStartupInfoId& id_P ) const
00983     {
00984     return id() == id_P.id();
00985     }
00986 
00987 bool KStartupInfoId::operator!=( const KStartupInfoId& id_P ) const
00988     {
00989     return !(*this == id_P );
00990     }
00991 
00992 // needed for QMap
00993 bool KStartupInfoId::operator<( const KStartupInfoId& id_P ) const
00994     {
00995     return id() < id_P.id();
00996     }
00997 
00998 bool KStartupInfoId::none() const
00999     {
01000     return d->id.isEmpty() || d->id == "0";
01001     }
01002 
01003 struct KStartupInfoDataPrivate
01004     {
01005     KStartupInfoDataPrivate() : desktop( 0 ), wmclass( "" ), hostname( "" ),
01006     silent( KStartupInfoData::Unknown ), timestamp( -1U ), screen( -1 ) {};
01007     QString bin;
01008     QString name;
01009     QString description;
01010     QString icon;
01011     int desktop;
01012     QValueList< pid_t > pids;
01013     QCString wmclass;
01014     QCString hostname;
01015     KStartupInfoData::TriState silent;
01016     unsigned long timestamp;
01017     int screen;
01018     };
01019 
01020 QString KStartupInfoData::to_text() const
01021     {
01022     QString ret = "";
01023     if( !d->bin.isEmpty())
01024         ret += QString::fromLatin1( " BIN=\"%1\"" ).arg( escape_str( d->bin ));
01025     if( !d->name.isEmpty())
01026         ret += QString::fromLatin1( " NAME=\"%1\"" ).arg( escape_str( d->name ));
01027     if( !d->description.isEmpty())
01028         ret += QString::fromLatin1( " DESCRIPTION=\"%1\"" ).arg( escape_str( d->description ));
01029     if( !d->icon.isEmpty())
01030         ret += QString::fromLatin1( " ICON=%1" ).arg( d->icon );
01031     if( d->desktop != 0 )
01032         ret += QString::fromLatin1( " DESKTOP=%1" )
01033             .arg( d->desktop == NET::OnAllDesktops ? NET::OnAllDesktops : d->desktop - 1 ); // spec counts from 0
01034     if( !d->wmclass.isEmpty())
01035         ret += QString::fromLatin1( " WMCLASS=%1" ).arg( d->wmclass );
01036     if( !d->hostname.isEmpty())
01037         ret += QString::fromLatin1( " HOSTNAME=%1" ).arg( d->hostname );
01038     for( QValueList< pid_t >::ConstIterator it = d->pids.begin();
01039          it != d->pids.end();
01040          ++it )
01041         ret += QString::fromLatin1( " PID=%1" ).arg( *it );
01042     if( d->silent != Unknown )
01043     ret += QString::fromLatin1( " SILENT=%1" ).arg( d->silent == Yes ? 1 : 0 );
01044     if( d->timestamp != -1U )
01045         ret += QString::fromLatin1( " TIMESTAMP=%1" ).arg( d->timestamp );
01046     if( d->screen != -1 )
01047         ret += QString::fromLatin1( " SCREEN=%1" ).arg( d->screen );
01048     return ret;
01049     }
01050 
01051 KStartupInfoData::KStartupInfoData( const QString& txt_P )
01052     {
01053     d = new KStartupInfoDataPrivate;
01054     QStringList items = get_fields( txt_P );
01055     const QString bin_str = QString::fromLatin1( "BIN=" );
01056     const QString name_str = QString::fromLatin1( "NAME=" );
01057     const QString description_str = QString::fromLatin1( "DESCRIPTION=" );
01058     const QString icon_str = QString::fromLatin1( "ICON=" );
01059     const QString desktop_str = QString::fromLatin1( "DESKTOP=" );
01060     const QString wmclass_str = QString::fromLatin1( "WMCLASS=" );
01061     const QString hostname_str = QString::fromLatin1( "HOSTNAME=" ); // SELI nonstd
01062     const QString pid_str = QString::fromLatin1( "PID=" );  // SELI nonstd
01063     const QString silent_str = QString::fromLatin1( "SILENT=" );
01064     const QString timestamp_str = QString::fromLatin1( "TIMESTAMP=" );
01065     const QString screen_str = QString::fromLatin1( "SCREEN=" );
01066     for( QStringList::Iterator it = items.begin();
01067          it != items.end();
01068          ++it )
01069         {
01070         if( ( *it ).startsWith( bin_str ))
01071             d->bin = get_str( *it );
01072         else if( ( *it ).startsWith( name_str ))
01073             d->name = get_str( *it );
01074         else if( ( *it ).startsWith( description_str ))
01075             d->description = get_str( *it );
01076         else if( ( *it ).startsWith( icon_str ))
01077             d->icon = get_str( *it );
01078         else if( ( *it ).startsWith( desktop_str ))
01079             {
01080             d->desktop = get_num( *it );
01081             if( d->desktop != NET::OnAllDesktops )
01082                 ++d->desktop; // spec counts from 0
01083             }
01084         else if( ( *it ).startsWith( wmclass_str ))
01085             d->wmclass = get_cstr( *it );
01086         else if( ( *it ).startsWith( hostname_str ))
01087             d->hostname = get_cstr( *it );
01088         else if( ( *it ).startsWith( pid_str ))
01089             addPid( get_num( *it ));
01090         else if( ( *it ).startsWith( silent_str ))
01091             d->silent = get_num( *it ) != 0 ? Yes : No;
01092         else if( ( *it ).startsWith( timestamp_str ))
01093             d->timestamp = get_unum( *it );
01094         else if( ( *it ).startsWith( screen_str ))
01095             d->screen = get_num( *it );
01096         }
01097     }
01098 
01099 KStartupInfoData::KStartupInfoData( const KStartupInfoData& data )
01100 {
01101     d = new KStartupInfoDataPrivate( *data.d );
01102 }
01103 
01104 KStartupInfoData& KStartupInfoData::operator=( const KStartupInfoData& data )
01105 {
01106     if( &data == this )
01107         return *this;
01108     delete d;
01109     d = new KStartupInfoDataPrivate( *data.d );
01110     return *this;
01111 }
01112 
01113 void KStartupInfoData::update( const KStartupInfoData& data_P )
01114     {
01115     if( !data_P.bin().isEmpty())
01116         d->bin = data_P.bin();
01117     if( !data_P.name().isEmpty() && name().isEmpty()) // don't overwrite
01118         d->name = data_P.name();
01119     if( !data_P.description().isEmpty() && description().isEmpty()) // don't overwrite
01120         d->description = data_P.description();
01121     if( !data_P.icon().isEmpty() && icon().isEmpty()) // don't overwrite
01122         d->icon = data_P.icon();
01123     if( data_P.desktop() != 0 && desktop() == 0 ) // don't overwrite
01124         d->desktop = data_P.desktop();
01125     if( !data_P.d->wmclass.isEmpty())
01126         d->wmclass = data_P.d->wmclass;
01127     if( !data_P.d->hostname.isEmpty())
01128         d->hostname = data_P.d->hostname;
01129     for( QValueList< pid_t >::ConstIterator it = data_P.d->pids.begin();
01130          it != data_P.d->pids.end();
01131          ++it )
01132         addPid( *it );
01133     if( data_P.silent() != Unknown )
01134     d->silent = data_P.silent();
01135     if( data_P.timestamp() != -1U && timestamp() == -1U ) // don't overwrite
01136         d->timestamp = data_P.timestamp();
01137     if( data_P.screen() != -1 )
01138         d->screen = data_P.screen();
01139     }
01140 
01141 KStartupInfoData::KStartupInfoData()
01142 {
01143     d = new KStartupInfoDataPrivate;
01144 }
01145 
01146 KStartupInfoData::~KStartupInfoData()
01147 {
01148     delete d;
01149 }
01150 
01151 void KStartupInfoData::setBin( const QString& bin_P )
01152     {
01153     d->bin = bin_P;
01154     }
01155 
01156 const QString& KStartupInfoData::bin() const
01157     {
01158     return d->bin;
01159     }
01160 
01161 void KStartupInfoData::setName( const QString& name_P )
01162     {
01163     d->name = name_P;
01164     }
01165 
01166 const QString& KStartupInfoData::name() const
01167     {
01168     return d->name;
01169     }
01170 
01171 const QString& KStartupInfoData::findName() const
01172     {
01173     if( !name().isEmpty())
01174         return name();
01175     return bin();
01176     }
01177 
01178 void KStartupInfoData::setDescription( const QString& desc_P )
01179     {
01180     d->description = desc_P;
01181     }
01182 
01183 const QString& KStartupInfoData::description() const
01184     {
01185     return d->description;
01186     }
01187 
01188 const QString& KStartupInfoData::findDescription() const
01189     {
01190     if( !description().isEmpty())
01191         return description();
01192     return name();
01193     }
01194 
01195 void KStartupInfoData::setIcon( const QString& icon_P )
01196     {
01197     d->icon = icon_P;
01198     }
01199 
01200 const QString& KStartupInfoData::findIcon() const
01201     {
01202     if( !icon().isEmpty())
01203         return icon();
01204     return bin();
01205     }
01206 
01207 const QString& KStartupInfoData::icon() const
01208     {
01209     return d->icon;
01210     }
01211 
01212 void KStartupInfoData::setDesktop( int desktop_P )
01213     {
01214     d->desktop = desktop_P;
01215     }
01216 
01217 int KStartupInfoData::desktop() const
01218     {
01219     return d->desktop;
01220     }
01221 
01222 void KStartupInfoData::setWMClass( const QCString& wmclass_P )
01223     {
01224     d->wmclass = wmclass_P;
01225     }
01226 
01227 const QCString KStartupInfoData::findWMClass() const
01228     {
01229     if( !WMClass().isEmpty() && WMClass() != "0" )
01230         return WMClass();
01231     return bin().utf8();
01232     }
01233 
01234 const QCString& KStartupInfoData::WMClass() const
01235     {
01236     return d->wmclass;
01237     }
01238 
01239 void KStartupInfoData::setHostname( const QCString& hostname_P )
01240     {
01241     if( !hostname_P.isNull())
01242         d->hostname = hostname_P;
01243     else
01244         {
01245         char tmp[ 256 ];
01246         tmp[ 0 ] = '\0';
01247         if (!gethostname( tmp, 255 ))
01248         tmp[sizeof(tmp)-1] = '\0';
01249         d->hostname = tmp;
01250         }
01251     }
01252 
01253 const QCString& KStartupInfoData::hostname() const
01254     {
01255     return d->hostname;
01256     }
01257 
01258 void KStartupInfoData::addPid( pid_t pid_P )
01259     {
01260     if( !d->pids.contains( pid_P ))
01261         d->pids.append( pid_P );
01262     }
01263 
01264 void KStartupInfoData::remove_pid( pid_t pid_P )
01265     {
01266     d->pids.remove( pid_P );
01267     }
01268 
01269 const QValueList< pid_t >& KStartupInfoData::pids() const
01270     {
01271     return d->pids;
01272     }
01273 
01274 bool KStartupInfoData::is_pid( pid_t pid_P ) const
01275     {
01276     return d->pids.contains( pid_P );
01277     }
01278 
01279 void KStartupInfoData::setSilent( TriState state_P )
01280     {
01281     d->silent = state_P;
01282     }
01283 
01284 KStartupInfoData::TriState KStartupInfoData::silent() const
01285     {
01286     return d->silent;
01287     }
01288 
01289 void KStartupInfoData::setTimestamp( unsigned long time )
01290     {
01291     d->timestamp = time;
01292     }
01293 
01294 unsigned long KStartupInfoData::timestamp() const
01295     {
01296     return d->timestamp;
01297     }
01298 
01299 void KStartupInfoData::setScreen( int screen )
01300     {
01301     d->screen = screen;
01302     }
01303 
01304 int KStartupInfoData::screen() const
01305     {
01306     return d->screen;
01307     }
01308 
01309 static
01310 long get_num( const QString& item_P )
01311     {
01312     unsigned int pos = item_P.find( '=' );
01313     return item_P.mid( pos + 1 ).toLong();
01314     }
01315 
01316 static
01317 unsigned long get_unum( const QString& item_P )
01318     {
01319     unsigned int pos = item_P.find( '=' );
01320     return item_P.mid( pos + 1 ).toULong();
01321     }
01322 
01323 static
01324 QString get_str( const QString& item_P )
01325     {
01326     unsigned int pos = item_P.find( '=' );
01327     if( item_P.length() > pos + 2 && item_P[ pos + 1 ] == '\"' )
01328         {
01329         int pos2 = item_P.left( pos + 2 ).find( '\"' );
01330         if( pos2 < 0 )
01331             return QString::null;                      // 01234
01332         return item_P.mid( pos + 2, pos2 - 2 - pos );  // A="C"
01333         }
01334     return item_P.mid( pos + 1 );
01335     }
01336 
01337 static
01338 QCString get_cstr( const QString& item_P )
01339     {
01340     return get_str( item_P ).utf8();
01341     }
01342 
01343 static
01344 QStringList get_fields( const QString& txt_P )
01345     {
01346     QString txt = txt_P.simplifyWhiteSpace();
01347     QStringList ret;
01348     QString item = "";
01349     bool in = false;
01350     bool escape = false;
01351     for( unsigned int pos = 0;
01352          pos < txt.length();
01353          ++pos )
01354         {
01355         if( escape )
01356             {
01357             item += txt[ pos ];
01358             escape = false;
01359             }
01360         else if( txt[ pos ] == '\\' )
01361             escape = true;
01362         else if( txt[ pos ] == '\"' )
01363             in = !in;
01364         else if( txt[ pos ] == ' ' && !in )
01365             {
01366             ret.append( item );
01367             item = "";
01368             }
01369         else
01370             item += txt[ pos ];
01371         }
01372     ret.append( item );
01373     return ret;
01374     }
01375 
01376 static QString escape_str( const QString& str_P )
01377     {
01378     QString ret = "";
01379     for( unsigned int pos = 0;
01380      pos < str_P.length();
01381      ++pos )
01382     {
01383     if( str_P[ pos ] == '\\'
01384         || str_P[ pos ] == '"' )
01385         ret += '\\';
01386     ret += str_P[ pos ];
01387     }
01388     return ret;
01389     }
01390 
01391 #include "kstartupinfo.moc"
01392 #endif
KDE Logo
This file is part of the documentation for kdecore Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed May 5 07:19:40 2004 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003