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