kdecore Library API Documentation

kstartupinfo.cpp

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