00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
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
00038 #include <qglobal.h>
00039 #ifdef HAVE_CONFIG_H
00040 #include <config.h>
00041 #endif
00042
00043
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>
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>
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
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() {};
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
00097 QMap< KStartupInfoId, KStartupInfo::Data > silent_startups;
00098
00099 QMap< KStartupInfoId, KStartupInfo::Data > uninited_startups;
00100 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00101 KWinModule* wm_module;
00102 KXMessages msgs;
00103 #endif
00104 QTimer* cleanup;
00105 int flags;
00106 KStartupInfoPrivate( int flags_P )
00107 :
00108 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
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
00131 if( !KApplication::kApplication())
00132 return;
00133 if( !KApplication::kApplication()->getDisplay())
00134 return;
00135
00136 d = new KStartupInfoPrivate( flags_P );
00137 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
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
00160 kdDebug( 172 ) << "got:" << msg_P << endl;
00161 QString msg = msg_P.stripWhiteSpace();
00162 if( msg.startsWith( "new:" ))
00163 got_startup_info( msg.mid( 4 ), false );
00164 else if( msg.startsWith( "change:" ))
00165 got_startup_info( msg.mid( 7 ), true );
00166 else if( msg.startsWith( "remove:" ))
00167 got_remove_startup_info( msg.mid( 7 ));
00168 }
00169
00170
00171
00172
00173
00174
00175
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;
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 {
00238 d->startups[ id_P ].update( data_P );
00239 d->startups[ id_P ].age = 0;
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 {
00254 d->silent_startups[ id_P ].update( data_P );
00255 d->silent_startups[ id_P ].age = 0;
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 )
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
00279 return;
00280 }
00281 if( update_P )
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
00293 {
00294 kdDebug( 172 ) << "adding silent" << endl;
00295 d->silent_startups.insert( id_P, data_P );
00296 }
00297 d->cleanup->start( 1000 );
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 {
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;
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 );
00374 if( data->pids().count() == 0 )
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
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 )
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
00472
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
00485
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 )
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 )
00511 {
00512 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
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;
00558 }
00559 }
00560 if( activate )
00561
00562
00563
00564
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;
00598
00599
00600
00601
00602
00603
00604
00605 kdDebug( 172 ) << "check_startup" << endl;
00606 QCString id = windowStartupId( w_P );
00607 if( !id.isNull())
00608 {
00609 if( id.isEmpty() || id == "0" )
00610 {
00611 kdDebug( 172 ) << "ignore" << endl;
00612 return NoMatch;
00613 }
00614 return find_id( id, id_O, data_O ) ? Match : NoMatch;
00615 }
00616 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
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
00627 }
00628 XClassHint hint;
00629 if( XGetClassHint( qt_xdisplay(), w_P, &hint ) != 0 )
00630 {
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
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
00648 return NoMatch;
00649
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 {
00692 if( id_O != NULL )
00693 *id_O = it.key();
00694 if( data_O != NULL )
00695 *data_O = *it;
00696
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 {
00720 if( id_O != NULL )
00721 *id_O = it.key();
00722 if( data_O != NULL )
00723 *data_O = *it;
00724
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 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
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 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
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 {
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 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
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 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
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
00812 return QCString();
00813 }
00814
00815 void KStartupInfo::setTimeout( unsigned int secs_P )
00816 {
00817 timeout = secs_P;
00818
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 )
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 )
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 )
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
00926
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 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
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;
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 {
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
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
01082
01083
01084
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
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 );
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=" );
01160 const QString pid_str = QString::fromLatin1( "PID=" );
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;
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())
01216 d->name = data_P.name();
01217 if( !data_P.description().isEmpty() && description().isEmpty())
01218 d->description = data_P.description();
01219 if( !data_P.icon().isEmpty() && icon().isEmpty())
01220 d->icon = data_P.icon();
01221 if( data_P.desktop() != 0 && desktop() == 0 )
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 )
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;
01430 return item_P.mid( pos + 2, pos2 - 2 - pos );
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