kdecore Library API Documentation

kstartupinfo.cpp

00001 /****************************************************************************
00002 
00003  $Id: kstartupinfo.cpp,v 1.50 2004/01/01 10:46:42 mueller 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( !startup_id.isEmpty() && startup_id != "0" )
00525         {
00526         NETRootInfo i( qt_xdisplay(), NET::Supported );
00527         if( i.isSupported( NET::WM2StartupId ))
00528             {
00529             KStartupInfo::setWindowStartupId( window->winId(), startup_id );
00530             activate = false; // WM will take care of it
00531             }
00532         }
00533     if( activate )
00534     // This is not very nice, but there's no way how to get any
00535     // usable timestamp without ASN, so force activating the window.
00536     // And even with ASN, it's not possible to get the timestamp here,
00537     // so if the WM doesn't have support for ASN, it can't be used either.
00538         KWin::forceActiveWindow( window->winId());
00539     KStartupInfo::handleAutoAppStartedSending();
00540     }
00541 
00542 KStartupInfo::startup_t KStartupInfo::checkStartup( WId w_P, KStartupInfoId& id_O,
00543     KStartupInfoData& data_O )
00544     {
00545     return check_startup_internal( w_P, &id_O, &data_O );
00546     }
00547 
00548 KStartupInfo::startup_t KStartupInfo::checkStartup( WId w_P, KStartupInfoId& id_O )
00549     {
00550     return check_startup_internal( w_P, &id_O, NULL );
00551     }
00552 
00553 KStartupInfo::startup_t KStartupInfo::checkStartup( WId w_P, KStartupInfoData& data_O )
00554     {
00555     return check_startup_internal( w_P, NULL, &data_O );
00556     }
00557 
00558 KStartupInfo::startup_t KStartupInfo::checkStartup( WId w_P )
00559     {
00560     return check_startup_internal( w_P, NULL, NULL );
00561     }
00562 
00563 KStartupInfo::startup_t KStartupInfo::check_startup_internal( WId w_P, KStartupInfoId* id_O,
00564     KStartupInfoData* data_O )
00565     {
00566     if( d == NULL )
00567         return NoMatch;
00568     if( d->startups.count() == 0 )
00569         return NoMatch; // no startups
00570 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00571 // SELI ???
00572     NETWinInfo info( qt_xdisplay(),  w_P, qt_xrootwin(),
00573         NET::WMWindowType | NET::WMPid | NET::WMState );
00574     // ignore NET::Tool and other special window types
00575     NET::WindowType type = info.windowType( NET::NormalMask | NET::DesktopMask
00576         | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
00577         | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask );
00578     if( type != NET::Normal
00579         && type != NET::Override
00580         && type != NET::Unknown
00581         && type != NET::Dialog
00582         && type != NET::Utility )
00583 //        && type != NET::Dock ) why did I put this here?
00584     return NoMatch;
00585     // lets see if this is a transient
00586     Window transient_for;
00587     if( XGetTransientForHint( qt_xdisplay(), static_cast< Window >( w_P ), &transient_for )
00588         && static_cast< WId >( transient_for ) != qt_xrootwin()
00589         && transient_for != None )
00590     return NoMatch;
00591 #endif
00592     // Strategy:
00593     //
00594     // Is this a compliant app ?
00595     //  - Yes - test for match
00596     //  - No - Is this a NET_WM compliant app ?
00597     //           - Yes - test for pid match
00598     //           - No - test for WM_CLASS match
00599     kdDebug( 172 ) << "check_startup" << endl;
00600     QCString id = windowStartupId( w_P );
00601     if( !id.isNull())
00602         {
00603         if( id.isEmpty() || id == "0" ) // means ignore this window
00604             {
00605             kdDebug( 172 ) << "ignore" << endl;
00606             return NoMatch;
00607             }
00608         return find_id( id, id_O, data_O ) ? Match : NoMatch;
00609         }
00610 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00611     pid_t pid = info.pid();
00612     if( pid > 0 )
00613         {
00614         QCString hostname = get_window_hostname( w_P );
00615         if( !hostname.isEmpty()
00616             && find_pid( pid, hostname, id_O, data_O ))
00617             return Match;
00618         // try XClass matching , this PID stuff sucks :(
00619         }
00620     XClassHint hint;
00621     if( XGetClassHint( qt_xdisplay(), w_P, &hint ) != 0 )
00622         { // We managed to read the class hint
00623         QCString res_name = hint.res_name;
00624         QCString res_class = hint.res_class;
00625         XFree( hint.res_name );
00626         XFree( hint.res_class );
00627         if( find_wclass( res_name, res_class, id_O, data_O ))
00628             return Match;
00629         }
00630 #endif
00631     kdDebug( 172 ) << "check_startup:cantdetect" << endl;
00632     return CantDetect;
00633     }
00634 
00635 bool KStartupInfo::find_id( const QCString& id_P, KStartupInfoId* id_O,
00636     KStartupInfoData* data_O )
00637     {
00638     if( d == NULL )
00639         return false;
00640     kdDebug( 172 ) << "find_id:" << id_P << endl;
00641     KStartupInfoId id;
00642     id.initId( id_P );
00643     if( d->startups.contains( id ))
00644         {
00645         if( id_O != NULL )
00646             *id_O = id;
00647         if( data_O != NULL )
00648             *data_O = d->startups[ id ];
00649         kdDebug( 172 ) << "check_startup_id:match" << endl;
00650         return true;
00651         }
00652     return false;
00653     }
00654 
00655 bool KStartupInfo::find_pid( pid_t pid_P, const QCString& hostname_P,
00656     KStartupInfoId* id_O, KStartupInfoData* data_O )
00657     {
00658     if( d == NULL )
00659         return false;
00660     kdDebug( 172 ) << "find_pid:" << pid_P << endl;
00661     for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin();
00662          it != d->startups.end();
00663          ++it )
00664         {
00665         if( ( *it ).is_pid( pid_P ) && ( *it ).hostname() == hostname_P )
00666             { // Found it !
00667             if( id_O != NULL )
00668                 *id_O = it.key();
00669             if( data_O != NULL )
00670                 *data_O = *it;
00671             // non-compliant, remove on first match
00672             remove_startup_info_internal( it.key());
00673             kdDebug( 172 ) << "check_startup_pid:match" << endl;
00674             return true;
00675             }
00676         }
00677     return false;
00678     }
00679 
00680 bool KStartupInfo::find_wclass( QCString res_name, QCString res_class,
00681     KStartupInfoId* id_O, KStartupInfoData* data_O )
00682     {
00683     if( d == NULL )
00684         return false;
00685     res_name = res_name.lower();
00686     res_class = res_class.lower();
00687     kdDebug( 172 ) << "find_wclass:" << res_name << ":" << res_class << endl;
00688     for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin();
00689          it != d->startups.end();
00690          ++it )
00691         {
00692         const QCString wmclass = ( *it ).findWMClass();
00693         if( wmclass.lower() == res_name || wmclass.lower() == res_class )
00694             { // Found it !
00695             if( id_O != NULL )
00696                 *id_O = it.key();
00697             if( data_O != NULL )
00698                 *data_O = *it;
00699             // non-compliant, remove on first match
00700             remove_startup_info_internal( it.key());
00701             kdDebug( 172 ) << "check_startup_wclass:match" << endl;
00702             return true;
00703             }
00704         }
00705     return false;
00706     }
00707 
00708 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00709 static Atom net_startup_atom = None;
00710 #endif
00711 
00712 QCString KStartupInfo::windowStartupId( WId w_P )
00713     {
00714 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00715     if( net_startup_atom == None )
00716         net_startup_atom = XInternAtom( qt_xdisplay(), NET_STARTUP_WINDOW, False );
00717     if( utf8_string_atom == None )
00718         utf8_string_atom = XInternAtom( qt_xdisplay(), "UTF8_STRING", False );
00719     unsigned char *name_ret;
00720     QCString ret;
00721     Atom type_ret;
00722     int format_ret;
00723     unsigned long nitems_ret = 0, after_ret = 0;
00724     if( XGetWindowProperty( qt_xdisplay(), w_P, net_startup_atom, 0l, 4096,
00725             False, utf8_string_atom, &type_ret, &format_ret, &nitems_ret, &after_ret, &name_ret )
00726         == Success )
00727         {
00728     if( type_ret == utf8_string_atom && format_ret == 8 && name_ret != NULL )
00729         ret = reinterpret_cast< char* >( name_ret );
00730         if ( name_ret != NULL )
00731             XFree( name_ret );
00732         }
00733     return ret;
00734 #else
00735     return QCString();
00736 #endif
00737     }
00738 
00739 void KStartupInfo::setWindowStartupId( WId w_P, const QCString& id_P )
00740     {
00741 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00742     if( id_P.isNull())
00743         return;
00744     if( net_startup_atom == None )
00745         net_startup_atom = XInternAtom( qt_xdisplay(), NET_STARTUP_WINDOW, False );
00746     if( utf8_string_atom == None )
00747         utf8_string_atom = XInternAtom( qt_xdisplay(), "UTF8_STRING", False );
00748     XChangeProperty( qt_xdisplay(), w_P, net_startup_atom, utf8_string_atom, 8,
00749         PropModeReplace, reinterpret_cast< unsigned char* >( id_P.data()), id_P.length());
00750 #endif
00751     }
00752 
00753 QCString KStartupInfo::get_window_hostname( WId w_P )
00754     {
00755 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00756     XTextProperty tp;
00757     char** hh;
00758     int cnt;
00759     if( XGetWMClientMachine( qt_xdisplay(), w_P, &tp ) != 0
00760         && XTextPropertyToStringList( &tp, &hh, &cnt ) != 0 )
00761         {
00762         if( cnt == 1 )
00763             {
00764             QCString hostname = hh[ 0 ];
00765             XFreeStringList( hh );
00766             return hostname;
00767             }
00768         XFreeStringList( hh );
00769         }
00770 #endif
00771     // no hostname
00772     return QCString();
00773     }
00774 
00775 void KStartupInfo::setTimeout( unsigned int secs_P )
00776     {
00777     timeout = secs_P;
00778  // schedule removing entries that are older than the new timeout
00779     QTimer::singleShot( 0, this, SLOT( startups_cleanup_no_age()));
00780     }
00781 
00782 void KStartupInfo::startups_cleanup_no_age()
00783     {
00784     startups_cleanup_internal( false );
00785     }
00786 
00787 void KStartupInfo::startups_cleanup()
00788     {
00789     if( d == NULL )
00790         return;
00791     if( d->startups.count() == 0 && d->silent_startups.count() == 0 )
00792         {
00793         d->cleanup->stop();
00794         return;
00795         }
00796     startups_cleanup_internal( true );
00797     }
00798 
00799 void KStartupInfo::startups_cleanup_internal( bool age_P )
00800     {
00801     if( d == NULL )
00802         return;
00803     for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin();
00804          it != d->startups.end();
00805          )
00806         {
00807         if( age_P )
00808             ( *it ).age++;
00809     int tout = timeout;
00810     if( ( *it ).silent() == Data::Yes ) // TODO
00811         tout *= 20;
00812         if( ( *it ).age >= timeout )
00813             {
00814             const KStartupInfoId& key = it.key();
00815             ++it;
00816             kdDebug( 172 ) << "entry timeout:" << key.id() << endl;
00817             remove_startup_info_internal( key );
00818             }
00819         else
00820             ++it;
00821         }
00822     for( QMap< KStartupInfoId, Data >::Iterator it = d->silent_startups.begin();
00823          it != d->silent_startups.end();
00824          )
00825         {
00826         if( age_P )
00827             ( *it ).age++;
00828     int tout = timeout;
00829     if( ( *it ).silent() == Data::Yes ) // TODO
00830         tout *= 20;
00831         if( ( *it ).age >= timeout )
00832             {
00833             const KStartupInfoId& key = it.key();
00834             ++it;
00835             kdDebug( 172 ) << "entry timeout:" << key.id() << endl;
00836             remove_startup_info_internal( key );
00837             }
00838         else
00839             ++it;
00840         }
00841     }
00842 
00843 void KStartupInfo::clean_all_noncompliant()
00844     {
00845     if( d == NULL )
00846         return;
00847     for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin();
00848          it != d->startups.end();
00849          )
00850         {
00851         if( ( *it ).WMClass() != "0" )
00852             {
00853             ++it;
00854             continue;
00855             }
00856         const KStartupInfoId& key = it.key();
00857         ++it;
00858         kdDebug( 172 ) << "entry cleaning:" << key.id() << endl;
00859         remove_startup_info_internal( key );
00860         }
00861     }
00862 
00863 struct KStartupInfoIdPrivate
00864     {
00865     KStartupInfoIdPrivate() : id( "" ) {};
00866     QCString id; // id
00867     };
00868 
00869 const QCString& KStartupInfoId::id() const
00870     {
00871     return d->id;
00872     }
00873 
00874 
00875 QString KStartupInfoId::to_text() const
00876     {
00877     return QString::fromLatin1( " ID=\"%1\" " ).arg( escape_str( id()));
00878     }
00879 
00880 KStartupInfoId::KStartupInfoId( const QString& txt_P )
00881     {
00882     d = new KStartupInfoIdPrivate;
00883     QStringList items = get_fields( txt_P );
00884     const QString id_str = QString::fromLatin1( "ID=" );
00885     for( QStringList::Iterator it = items.begin();
00886          it != items.end();
00887          ++it )
00888         {
00889         if( ( *it ).startsWith( id_str ))
00890             d->id = get_cstr( *it );
00891         }
00892     }
00893 
00894 void KStartupInfoId::initId( const QCString& id_P )
00895     {
00896     if( !id_P.isEmpty())
00897         {
00898         d->id = id_P;
00899 #ifdef KSTARTUPINFO_ALL_DEBUG
00900         kdDebug( 172 ) << "using: " << d->id << endl;
00901 #endif
00902         return;
00903         }
00904     const char* startup_env = getenv( NET_STARTUP_ENV );
00905     if( startup_env != NULL && *startup_env != '\0' )
00906         { // already has id
00907         d->id = startup_env;
00908 #ifdef KSTARTUPINFO_ALL_DEBUG
00909         kdDebug( 172 ) << "reusing: " << d->id << endl;
00910 #endif
00911         return;
00912         }
00913     // assign a unique id  CHECKME
00914     // use hostname+time+pid, that should be 200% unique
00915     // hmm, probably something 99.9% unique and much shorter would be enough
00916     struct timeval tm;
00917     gettimeofday( &tm, NULL );
00918     char hostname[ 256 ];
00919     hostname[ 0 ] = '\0';
00920     if (!gethostname( hostname, 255 ))
00921     hostname[sizeof(hostname)-1] = '\0';
00922     d->id = QString( "%1;%2;%3;%4" ).arg( hostname ).arg( tm.tv_sec )
00923         .arg( tm.tv_usec ).arg( getpid()).utf8();
00924 #ifdef KSTARTUPINFO_ALL_DEBUG
00925     kdDebug( 172 ) << "creating: " << d->id << endl;
00926 #endif
00927     }
00928 
00929 bool KStartupInfoId::setupStartupEnv() const
00930     {
00931     if( id().isEmpty())
00932         {
00933         unsetenv( NET_STARTUP_ENV );
00934         return false;
00935         }
00936     return setenv( NET_STARTUP_ENV, id(), true ) == 0;
00937     }
00938 
00939 KStartupInfoId KStartupInfo::currentStartupIdEnv()
00940     {
00941     const char* startup_env = getenv( NET_STARTUP_ENV );
00942     KStartupInfoId id;
00943     if( startup_env != NULL && *startup_env != '\0' )
00944         id.d->id = startup_env;
00945     else
00946         id.d->id = "0";
00947     return id;
00948     }
00949 
00950 void KStartupInfo::resetStartupEnv()
00951     {
00952     unsetenv( NET_STARTUP_ENV );
00953     }
00954 
00955 KStartupInfoId::KStartupInfoId()
00956     {
00957     d = new KStartupInfoIdPrivate;
00958     }
00959 
00960 KStartupInfoId::~KStartupInfoId()
00961     {
00962     delete d;
00963     }
00964 
00965 KStartupInfoId::KStartupInfoId( const KStartupInfoId& id_P )
00966     {
00967     d = new KStartupInfoIdPrivate( *id_P.d );
00968     }
00969 
00970 KStartupInfoId& KStartupInfoId::operator=( const KStartupInfoId& id_P )
00971     {
00972     if( &id_P == this )
00973         return *this;
00974     delete d;
00975     d = new KStartupInfoIdPrivate( *id_P.d );
00976     return *this;
00977     }
00978 
00979 bool KStartupInfoId::operator==( const KStartupInfoId& id_P ) const
00980     {
00981     return id() == id_P.id();
00982     }
00983 
00984 bool KStartupInfoId::operator!=( const KStartupInfoId& id_P ) const
00985     {
00986     return !(*this == id_P );
00987     }
00988 
00989 // needed for QMap
00990 bool KStartupInfoId::operator<( const KStartupInfoId& id_P ) const
00991     {
00992     return id() < id_P.id();
00993     }
00994 
00995 bool KStartupInfoId::none() const
00996     {
00997     return d->id.isEmpty() || d->id == "0";
00998     }
00999 
01000 struct KStartupInfoDataPrivate
01001     {
01002     KStartupInfoDataPrivate() : desktop( 0 ), wmclass( "" ), hostname( "" ),
01003     silent( KStartupInfoData::Unknown ), timestamp( -1U ), screen( -1 ) {};
01004     QString bin;
01005     QString name;
01006     QString description;
01007     QString icon;
01008     int desktop;
01009     QValueList< pid_t > pids;
01010     QCString wmclass;
01011     QCString hostname;
01012     KStartupInfoData::TriState silent;
01013     unsigned long timestamp;
01014     int screen;
01015     };
01016 
01017 QString KStartupInfoData::to_text() const
01018     {
01019     QString ret = "";
01020     if( !d->bin.isEmpty())
01021         ret += QString::fromLatin1( " BIN=\"%1\"" ).arg( escape_str( d->bin ));
01022     if( !d->name.isEmpty())
01023         ret += QString::fromLatin1( " NAME=\"%1\"" ).arg( escape_str( d->name ));
01024     if( !d->description.isEmpty())
01025         ret += QString::fromLatin1( " DESCRIPTION=\"%1\"" ).arg( escape_str( d->description ));
01026     if( !d->icon.isEmpty())
01027         ret += QString::fromLatin1( " ICON=%1" ).arg( d->icon );
01028     if( d->desktop != 0 )
01029         ret += QString::fromLatin1( " DESKTOP=%1" )
01030             .arg( d->desktop == NET::OnAllDesktops ? NET::OnAllDesktops : d->desktop - 1 ); // spec counts from 0
01031     if( !d->wmclass.isEmpty())
01032         ret += QString::fromLatin1( " WMCLASS=%1" ).arg( d->wmclass );
01033     if( !d->hostname.isEmpty())
01034         ret += QString::fromLatin1( " HOSTNAME=%1" ).arg( d->hostname );
01035     for( QValueList< pid_t >::ConstIterator it = d->pids.begin();
01036          it != d->pids.end();
01037          ++it )
01038         ret += QString::fromLatin1( " PID=%1" ).arg( *it );
01039     if( d->silent != Unknown )
01040     ret += QString::fromLatin1( " SILENT=%1" ).arg( d->silent == Yes ? 1 : 0 );
01041     if( d->timestamp != -1U )
01042         ret += QString::fromLatin1( " TIMESTAMP=%1" ).arg( d->timestamp );
01043     if( d->screen != -1 )
01044         ret += QString::fromLatin1( " SCREEN=%1" ).arg( d->screen );
01045     return ret;
01046     }
01047 
01048 KStartupInfoData::KStartupInfoData( const QString& txt_P )
01049     {
01050     d = new KStartupInfoDataPrivate;
01051     QStringList items = get_fields( txt_P );
01052     const QString bin_str = QString::fromLatin1( "BIN=" );
01053     const QString name_str = QString::fromLatin1( "NAME=" );
01054     const QString description_str = QString::fromLatin1( "DESCRIPTION=" );
01055     const QString icon_str = QString::fromLatin1( "ICON=" );
01056     const QString desktop_str = QString::fromLatin1( "DESKTOP=" );
01057     const QString wmclass_str = QString::fromLatin1( "WMCLASS=" );
01058     const QString hostname_str = QString::fromLatin1( "HOSTNAME=" ); // SELI nonstd
01059     const QString pid_str = QString::fromLatin1( "PID=" );  // SELI nonstd
01060     const QString silent_str = QString::fromLatin1( "SILENT=" );
01061     const QString timestamp_str = QString::fromLatin1( "TIMESTAMP=" );
01062     const QString screen_str = QString::fromLatin1( "SCREEN=" );
01063     for( QStringList::Iterator it = items.begin();
01064          it != items.end();
01065          ++it )
01066         {
01067         if( ( *it ).startsWith( bin_str ))
01068             d->bin = get_str( *it );
01069         else if( ( *it ).startsWith( name_str ))
01070             d->name = get_str( *it );
01071         else if( ( *it ).startsWith( description_str ))
01072             d->description = get_str( *it );
01073         else if( ( *it ).startsWith( icon_str ))
01074             d->icon = get_str( *it );
01075         else if( ( *it ).startsWith( desktop_str ))
01076             {
01077             d->desktop = get_num( *it );
01078             if( d->desktop != NET::OnAllDesktops )
01079                 ++d->desktop; // spec counts from 0
01080             }
01081         else if( ( *it ).startsWith( wmclass_str ))
01082             d->wmclass = get_cstr( *it );
01083         else if( ( *it ).startsWith( hostname_str ))
01084             d->hostname = get_cstr( *it );
01085         else if( ( *it ).startsWith( pid_str ))
01086             addPid( get_num( *it ));
01087         else if( ( *it ).startsWith( silent_str ))
01088             d->silent = get_num( *it ) != 0 ? Yes : No;
01089         else if( ( *it ).startsWith( timestamp_str ))
01090             d->timestamp = get_unum( *it );
01091         else if( ( *it ).startsWith( screen_str ))
01092             d->screen = get_num( *it );
01093         }
01094     }
01095 
01096 KStartupInfoData::KStartupInfoData( const KStartupInfoData& data )
01097 {
01098     d = new KStartupInfoDataPrivate( *data.d );
01099 }
01100 
01101 KStartupInfoData& KStartupInfoData::operator=( const KStartupInfoData& data )
01102 {
01103     if( &data == this )
01104         return *this;
01105     delete d;
01106     d = new KStartupInfoDataPrivate( *data.d );
01107     return *this;
01108 }
01109 
01110 void KStartupInfoData::update( const KStartupInfoData& data_P )
01111     {
01112     if( !data_P.bin().isEmpty())
01113         d->bin = data_P.bin();
01114     if( !data_P.name().isEmpty() && name().isEmpty()) // don't overwrite
01115         d->name = data_P.name();
01116     if( !data_P.description().isEmpty() && description().isEmpty()) // don't overwrite
01117         d->description = data_P.description();
01118     if( !data_P.icon().isEmpty() && icon().isEmpty()) // don't overwrite
01119         d->icon = data_P.icon();
01120     if( data_P.desktop() != 0 && desktop() == 0 ) // don't overwrite
01121         d->desktop = data_P.desktop();
01122     if( !data_P.d->wmclass.isEmpty())
01123         d->wmclass = data_P.d->wmclass;
01124     if( !data_P.d->hostname.isEmpty())
01125         d->hostname = data_P.d->hostname;
01126     for( QValueList< pid_t >::ConstIterator it = data_P.d->pids.begin();
01127          it != data_P.d->pids.end();
01128          ++it )
01129         addPid( *it );
01130     if( data_P.silent() != Unknown )
01131     d->silent = data_P.silent();
01132     if( data_P.timestamp() != -1U && timestamp() == -1U ) // don't overwrite
01133         d->timestamp = data_P.timestamp();
01134     if( data_P.screen() != -1 )
01135         d->screen = data_P.screen();
01136     }
01137 
01138 KStartupInfoData::KStartupInfoData()
01139 {
01140     d = new KStartupInfoDataPrivate;
01141 }
01142 
01143 KStartupInfoData::~KStartupInfoData()
01144 {
01145     delete d;
01146 }
01147 
01148 void KStartupInfoData::setBin( const QString& bin_P )
01149     {
01150     d->bin = bin_P;
01151     }
01152 
01153 const QString& KStartupInfoData::bin() const
01154     {
01155     return d->bin;
01156     }
01157 
01158 void KStartupInfoData::setName( const QString& name_P )
01159     {
01160     d->name = name_P;
01161     }
01162 
01163 const QString& KStartupInfoData::name() const
01164     {
01165     return d->name;
01166     }
01167 
01168 const QString& KStartupInfoData::findName() const
01169     {
01170     if( !name().isEmpty())
01171         return name();
01172     return bin();
01173     }
01174 
01175 void KStartupInfoData::setDescription( const QString& desc_P )
01176     {
01177     d->description = desc_P;
01178     }
01179 
01180 const QString& KStartupInfoData::description() const
01181     {
01182     return d->description;
01183     }
01184 
01185 const QString& KStartupInfoData::findDescription() const
01186     {
01187     if( !description().isEmpty())
01188         return description();
01189     return name();
01190     }
01191 
01192 void KStartupInfoData::setIcon( const QString& icon_P )
01193     {
01194     d->icon = icon_P;
01195     }
01196 
01197 const QString& KStartupInfoData::findIcon() const
01198     {
01199     if( !icon().isEmpty())
01200         return icon();
01201     return bin();
01202     }
01203 
01204 const QString& KStartupInfoData::icon() const
01205     {
01206     return d->icon;
01207     }
01208 
01209 void KStartupInfoData::setDesktop( int desktop_P )
01210     {
01211     d->desktop = desktop_P;
01212     }
01213 
01214 int KStartupInfoData::desktop() const
01215     {
01216     return d->desktop;
01217     }
01218 
01219 void KStartupInfoData::setWMClass( const QCString& wmclass_P )
01220     {
01221     d->wmclass = wmclass_P;
01222     }
01223 
01224 const QCString KStartupInfoData::findWMClass() const
01225     {
01226     if( !WMClass().isEmpty() && WMClass() != "0" )
01227         return WMClass();
01228     return bin().utf8();
01229     }
01230 
01231 const QCString& KStartupInfoData::WMClass() const
01232     {
01233     return d->wmclass;
01234     }
01235 
01236 void KStartupInfoData::setHostname( const QCString& hostname_P )
01237     {
01238     if( !hostname_P.isNull())
01239         d->hostname = hostname_P;
01240     else
01241         {
01242         char tmp[ 256 ];
01243         tmp[ 0 ] = '\0';
01244         if (!gethostname( tmp, 255 ))
01245         tmp[sizeof(tmp)-1] = '\0';
01246         d->hostname = tmp;
01247         }
01248     }
01249 
01250 const QCString& KStartupInfoData::hostname() const
01251     {
01252     return d->hostname;
01253     }
01254 
01255 void KStartupInfoData::addPid( pid_t pid_P )
01256     {
01257     if( !d->pids.contains( pid_P ))
01258         d->pids.append( pid_P );
01259     }
01260 
01261 void KStartupInfoData::remove_pid( pid_t pid_P )
01262     {
01263     d->pids.remove( pid_P );
01264     }
01265 
01266 const QValueList< pid_t >& KStartupInfoData::pids() const
01267     {
01268     return d->pids;
01269     }
01270 
01271 bool KStartupInfoData::is_pid( pid_t pid_P ) const
01272     {
01273     return d->pids.contains( pid_P );
01274     }
01275 
01276 void KStartupInfoData::setSilent( TriState state_P )
01277     {
01278     d->silent = state_P;
01279     }
01280 
01281 KStartupInfoData::TriState KStartupInfoData::silent() const
01282     {
01283     return d->silent;
01284     }
01285 
01286 void KStartupInfoData::setTimestamp( unsigned long time )
01287     {
01288     d->timestamp = time;
01289     }
01290 
01291 unsigned long KStartupInfoData::timestamp() const
01292     {
01293     return d->timestamp;
01294     }
01295 
01296 void KStartupInfoData::setScreen( int screen )
01297     {
01298     d->screen = screen;
01299     }
01300 
01301 int KStartupInfoData::screen() const
01302     {
01303     return d->screen;
01304     }
01305 
01306 static
01307 long get_num( const QString& item_P )
01308     {
01309     unsigned int pos = item_P.find( '=' );
01310     return item_P.mid( pos + 1 ).toLong();
01311     }
01312 
01313 static
01314 unsigned long get_unum( const QString& item_P )
01315     {
01316     unsigned int pos = item_P.find( '=' );
01317     return item_P.mid( pos + 1 ).toULong();
01318     }
01319 
01320 static
01321 QString get_str( const QString& item_P )
01322     {
01323     unsigned int pos = item_P.find( '=' );
01324     if( item_P.length() > pos + 2 && item_P[ pos + 1 ] == '\"' )
01325         {
01326         int pos2 = item_P.left( pos + 2 ).find( '\"' );
01327         if( pos2 < 0 )
01328             return QString::null;                      // 01234
01329         return item_P.mid( pos + 2, pos2 - 2 - pos );  // A="C"
01330         }
01331     return item_P.mid( pos + 1 );
01332     }
01333 
01334 static
01335 QCString get_cstr( const QString& item_P )
01336     {
01337     return get_str( item_P ).utf8();
01338     }
01339 
01340 static
01341 QStringList get_fields( const QString& txt_P )
01342     {
01343     QString txt = txt_P.simplifyWhiteSpace();
01344     QStringList ret;
01345     QString item = "";
01346     bool in = false;
01347     bool escape = false;
01348     for( unsigned int pos = 0;
01349          pos < txt.length();
01350          ++pos )
01351         {
01352         if( escape )
01353             {
01354             item += txt[ pos ];
01355             escape = false;
01356             }
01357         else if( txt[ pos ] == '\\' )
01358             escape = true;
01359         else if( txt[ pos ] == '\"' )
01360             in = !in;
01361         else if( txt[ pos ] == ' ' && !in )
01362             {
01363             ret.append( item );
01364             item = "";
01365             }
01366         else
01367             item += txt[ pos ];
01368         }
01369     ret.append( item );
01370     return ret;
01371     }
01372 
01373 static QString escape_str( const QString& str_P )
01374     {
01375     QString ret = "";
01376     for( unsigned int pos = 0;
01377      pos < str_P.length();
01378      ++pos )
01379     {
01380     if( str_P[ pos ] == '\\'
01381         || str_P[ pos ] == '"' )
01382         ret += '\\';
01383     ret += str_P[ pos ];
01384     }
01385     return ret;
01386     }
01387 
01388 #include "kstartupinfo.moc"
01389 #endif
KDE Logo
This file is part of the documentation for kdecore Library Version 3.2.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Feb 4 12:33:51 2004 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2003