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 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00599
00600 NETWinInfo info( qt_xdisplay(), w_P, qt_xrootwin(),
00601 NET::WMWindowType | NET::WMPid | NET::WMState );
00602
00603 NET::WindowType type = info.windowType( NET::NormalMask | NET::DesktopMask
00604 | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
00605 | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask );
00606 if( type != NET::Normal
00607 && type != NET::Override
00608 && type != NET::Unknown
00609 && type != NET::Dialog
00610 && type != NET::Utility )
00611
00612 return NoMatch;
00613
00614 Window transient_for;
00615 if( XGetTransientForHint( qt_xdisplay(), static_cast< Window >( w_P ), &transient_for )
00616 && static_cast< WId >( transient_for ) != qt_xrootwin()
00617 && transient_for != None )
00618 return NoMatch;
00619 #endif
00620
00621
00622
00623
00624
00625
00626
00627 kdDebug( 172 ) << "check_startup" << endl;
00628 QCString id = windowStartupId( w_P );
00629 if( !id.isNull())
00630 {
00631 if( id.isEmpty() || id == "0" )
00632 {
00633 kdDebug( 172 ) << "ignore" << endl;
00634 return NoMatch;
00635 }
00636 return find_id( id, id_O, data_O ) ? Match : NoMatch;
00637 }
00638 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00639 pid_t pid = info.pid();
00640 if( pid > 0 )
00641 {
00642 QCString hostname = get_window_hostname( w_P );
00643 if( !hostname.isEmpty()
00644 && find_pid( pid, hostname, id_O, data_O ))
00645 return Match;
00646
00647 }
00648 XClassHint hint;
00649 if( XGetClassHint( qt_xdisplay(), w_P, &hint ) != 0 )
00650 {
00651 QCString res_name = hint.res_name;
00652 QCString res_class = hint.res_class;
00653 XFree( hint.res_name );
00654 XFree( hint.res_class );
00655 if( find_wclass( res_name, res_class, id_O, data_O ))
00656 return Match;
00657 }
00658 #endif
00659 kdDebug( 172 ) << "check_startup:cantdetect" << endl;
00660 return CantDetect;
00661 }
00662
00663 bool KStartupInfo::find_id( const QCString& id_P, KStartupInfoId* id_O,
00664 KStartupInfoData* data_O )
00665 {
00666 if( d == NULL )
00667 return false;
00668 kdDebug( 172 ) << "find_id:" << id_P << endl;
00669 KStartupInfoId id;
00670 id.initId( id_P );
00671 if( d->startups.contains( id ))
00672 {
00673 if( id_O != NULL )
00674 *id_O = id;
00675 if( data_O != NULL )
00676 *data_O = d->startups[ id ];
00677 kdDebug( 172 ) << "check_startup_id:match" << endl;
00678 return true;
00679 }
00680 return false;
00681 }
00682
00683 bool KStartupInfo::find_pid( pid_t pid_P, const QCString& hostname_P,
00684 KStartupInfoId* id_O, KStartupInfoData* data_O )
00685 {
00686 if( d == NULL )
00687 return false;
00688 kdDebug( 172 ) << "find_pid:" << pid_P << endl;
00689 for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin();
00690 it != d->startups.end();
00691 ++it )
00692 {
00693 if( ( *it ).is_pid( pid_P ) && ( *it ).hostname() == hostname_P )
00694 {
00695 if( id_O != NULL )
00696 *id_O = it.key();
00697 if( data_O != NULL )
00698 *data_O = *it;
00699
00700 remove_startup_info_internal( it.key());
00701 kdDebug( 172 ) << "check_startup_pid:match" << endl;
00702 return true;
00703 }
00704 }
00705 return false;
00706 }
00707
00708 bool KStartupInfo::find_wclass( QCString res_name, QCString res_class,
00709 KStartupInfoId* id_O, KStartupInfoData* data_O )
00710 {
00711 if( d == NULL )
00712 return false;
00713 res_name = res_name.lower();
00714 res_class = res_class.lower();
00715 kdDebug( 172 ) << "find_wclass:" << res_name << ":" << res_class << endl;
00716 for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin();
00717 it != d->startups.end();
00718 ++it )
00719 {
00720 const QCString wmclass = ( *it ).findWMClass();
00721 if( wmclass.lower() == res_name || wmclass.lower() == res_class )
00722 {
00723 if( id_O != NULL )
00724 *id_O = it.key();
00725 if( data_O != NULL )
00726 *data_O = *it;
00727
00728 remove_startup_info_internal( it.key());
00729 kdDebug( 172 ) << "check_startup_wclass:match" << endl;
00730 return true;
00731 }
00732 }
00733 return false;
00734 }
00735
00736 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00737 static Atom net_startup_atom = None;
00738
00739 static QCString read_startup_id_property( WId w_P )
00740 {
00741 QCString ret;
00742 unsigned char *name_ret;
00743 Atom type_ret;
00744 int format_ret;
00745 unsigned long nitems_ret = 0, after_ret = 0;
00746 if( XGetWindowProperty( qt_xdisplay(), w_P, net_startup_atom, 0l, 4096,
00747 False, utf8_string_atom, &type_ret, &format_ret, &nitems_ret, &after_ret, &name_ret )
00748 == Success )
00749 {
00750 if( type_ret == utf8_string_atom && format_ret == 8 && name_ret != NULL )
00751 ret = reinterpret_cast< char* >( name_ret );
00752 if ( name_ret != NULL )
00753 XFree( name_ret );
00754 }
00755 return ret;
00756 }
00757
00758 #endif
00759
00760 QCString KStartupInfo::windowStartupId( WId w_P )
00761 {
00762 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00763 if( net_startup_atom == None )
00764 net_startup_atom = XInternAtom( qt_xdisplay(), NET_STARTUP_WINDOW, False );
00765 if( utf8_string_atom == None )
00766 utf8_string_atom = XInternAtom( qt_xdisplay(), "UTF8_STRING", False );
00767 QCString ret = read_startup_id_property( w_P );
00768 if( ret.isEmpty())
00769 {
00770 XWMHints* hints = XGetWMHints( qt_xdisplay(), w_P );
00771 if( hints && ( hints->flags & WindowGroupHint ) != 0 )
00772 ret = read_startup_id_property( hints->window_group );
00773 if( hints )
00774 XFree( hints );
00775 }
00776 return ret;
00777 #else
00778 return QCString();
00779 #endif
00780 }
00781
00782 void KStartupInfo::setWindowStartupId( WId w_P, const QCString& id_P )
00783 {
00784 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00785 if( id_P.isNull())
00786 return;
00787 if( net_startup_atom == None )
00788 net_startup_atom = XInternAtom( qt_xdisplay(), NET_STARTUP_WINDOW, False );
00789 if( utf8_string_atom == None )
00790 utf8_string_atom = XInternAtom( qt_xdisplay(), "UTF8_STRING", False );
00791 XChangeProperty( qt_xdisplay(), w_P, net_startup_atom, utf8_string_atom, 8,
00792 PropModeReplace, reinterpret_cast< unsigned char* >( id_P.data()), id_P.length());
00793 #endif
00794 }
00795
00796 QCString KStartupInfo::get_window_hostname( WId w_P )
00797 {
00798 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00799 XTextProperty tp;
00800 char** hh;
00801 int cnt;
00802 if( XGetWMClientMachine( qt_xdisplay(), w_P, &tp ) != 0
00803 && XTextPropertyToStringList( &tp, &hh, &cnt ) != 0 )
00804 {
00805 if( cnt == 1 )
00806 {
00807 QCString hostname = hh[ 0 ];
00808 XFreeStringList( hh );
00809 return hostname;
00810 }
00811 XFreeStringList( hh );
00812 }
00813 #endif
00814
00815 return QCString();
00816 }
00817
00818 void KStartupInfo::setTimeout( unsigned int secs_P )
00819 {
00820 timeout = secs_P;
00821
00822 QTimer::singleShot( 0, this, SLOT( startups_cleanup_no_age()));
00823 }
00824
00825 void KStartupInfo::startups_cleanup_no_age()
00826 {
00827 startups_cleanup_internal( false );
00828 }
00829
00830 void KStartupInfo::startups_cleanup()
00831 {
00832 if( d == NULL )
00833 return;
00834 if( d->startups.count() == 0 && d->silent_startups.count() == 0
00835 && d->uninited_startups.count() == 0 )
00836 {
00837 d->cleanup->stop();
00838 return;
00839 }
00840 startups_cleanup_internal( true );
00841 }
00842
00843 void KStartupInfo::startups_cleanup_internal( bool age_P )
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( age_P )
00852 ( *it ).age++;
00853 unsigned int tout = timeout;
00854 if( ( *it ).silent() == Data::Yes )
00855 tout *= 20;
00856 if( ( *it ).age >= tout )
00857 {
00858 const KStartupInfoId& key = it.key();
00859 ++it;
00860 kdDebug( 172 ) << "entry timeout:" << key.id() << endl;
00861 remove_startup_info_internal( key );
00862 }
00863 else
00864 ++it;
00865 }
00866 for( QMap< KStartupInfoId, Data >::Iterator it = d->silent_startups.begin();
00867 it != d->silent_startups.end();
00868 )
00869 {
00870 if( age_P )
00871 ( *it ).age++;
00872 unsigned int tout = timeout;
00873 if( ( *it ).silent() == Data::Yes )
00874 tout *= 20;
00875 if( ( *it ).age >= tout )
00876 {
00877 const KStartupInfoId& key = it.key();
00878 ++it;
00879 kdDebug( 172 ) << "entry timeout:" << key.id() << endl;
00880 remove_startup_info_internal( key );
00881 }
00882 else
00883 ++it;
00884 }
00885 for( QMap< KStartupInfoId, Data >::Iterator it = d->uninited_startups.begin();
00886 it != d->uninited_startups.end();
00887 )
00888 {
00889 if( age_P )
00890 ( *it ).age++;
00891 unsigned int tout = timeout;
00892 if( ( *it ).silent() == Data::Yes )
00893 tout *= 20;
00894 if( ( *it ).age >= tout )
00895 {
00896 const KStartupInfoId& key = it.key();
00897 ++it;
00898 kdDebug( 172 ) << "entry timeout:" << key.id() << endl;
00899 remove_startup_info_internal( key );
00900 }
00901 else
00902 ++it;
00903 }
00904 }
00905
00906 void KStartupInfo::clean_all_noncompliant()
00907 {
00908 if( d == NULL )
00909 return;
00910 for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin();
00911 it != d->startups.end();
00912 )
00913 {
00914 if( ( *it ).WMClass() != "0" )
00915 {
00916 ++it;
00917 continue;
00918 }
00919 const KStartupInfoId& key = it.key();
00920 ++it;
00921 kdDebug( 172 ) << "entry cleaning:" << key.id() << endl;
00922 remove_startup_info_internal( key );
00923 }
00924 }
00925
00926 QCString KStartupInfo::createNewStartupId()
00927 {
00928
00929
00930 struct timeval tm;
00931 gettimeofday( &tm, NULL );
00932 char hostname[ 256 ];
00933 hostname[ 0 ] = '\0';
00934 if (!gethostname( hostname, 255 ))
00935 hostname[sizeof(hostname)-1] = '\0';
00936 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00937 extern Time qt_x_user_time;
00938 #else
00939 long qt_x_user_time = 0;
00940 #endif
00941 QCString id = QString( "%1;%2;%3;%4_TIME%5" ).arg( hostname ).arg( tm.tv_sec )
00942 .arg( tm.tv_usec ).arg( getpid()).arg( qt_x_user_time ).utf8();
00943 kdDebug( 172 ) << "creating: " << id << ":" << qAppName() << endl;
00944 return id;
00945 }
00946
00947
00948 struct KStartupInfoIdPrivate
00949 {
00950 KStartupInfoIdPrivate() : id( "" ) {};
00951 QCString id;
00952 };
00953
00954 const QCString& KStartupInfoId::id() const
00955 {
00956 return d->id;
00957 }
00958
00959
00960 QString KStartupInfoId::to_text() const
00961 {
00962 return QString::fromLatin1( " ID=\"%1\" " ).arg( escape_str( id()));
00963 }
00964
00965 KStartupInfoId::KStartupInfoId( const QString& txt_P )
00966 {
00967 d = new KStartupInfoIdPrivate;
00968 QStringList items = get_fields( txt_P );
00969 const QString id_str = QString::fromLatin1( "ID=" );
00970 for( QStringList::Iterator it = items.begin();
00971 it != items.end();
00972 ++it )
00973 {
00974 if( ( *it ).startsWith( id_str ))
00975 d->id = get_cstr( *it );
00976 }
00977 }
00978
00979 void KStartupInfoId::initId( const QCString& id_P )
00980 {
00981 if( !id_P.isEmpty())
00982 {
00983 d->id = id_P;
00984 #ifdef KSTARTUPINFO_ALL_DEBUG
00985 kdDebug( 172 ) << "using: " << d->id << endl;
00986 #endif
00987 return;
00988 }
00989 const char* startup_env = getenv( NET_STARTUP_ENV );
00990 if( startup_env != NULL && *startup_env != '\0' )
00991 {
00992 d->id = startup_env;
00993 #ifdef KSTARTUPINFO_ALL_DEBUG
00994 kdDebug( 172 ) << "reusing: " << d->id << endl;
00995 #endif
00996 return;
00997 }
00998 d->id = KStartupInfo::createNewStartupId();
00999 }
01000
01001 bool KStartupInfoId::setupStartupEnv() const
01002 {
01003 if( id().isEmpty())
01004 {
01005 unsetenv( NET_STARTUP_ENV );
01006 return false;
01007 }
01008 return setenv( NET_STARTUP_ENV, id(), true ) == 0;
01009 }
01010
01011 KStartupInfoId KStartupInfo::currentStartupIdEnv()
01012 {
01013 const char* startup_env = getenv( NET_STARTUP_ENV );
01014 KStartupInfoId id;
01015 if( startup_env != NULL && *startup_env != '\0' )
01016 id.d->id = startup_env;
01017 else
01018 id.d->id = "0";
01019 return id;
01020 }
01021
01022 void KStartupInfo::resetStartupEnv()
01023 {
01024 unsetenv( NET_STARTUP_ENV );
01025 }
01026
01027 KStartupInfoId::KStartupInfoId()
01028 {
01029 d = new KStartupInfoIdPrivate;
01030 }
01031
01032 KStartupInfoId::~KStartupInfoId()
01033 {
01034 delete d;
01035 }
01036
01037 KStartupInfoId::KStartupInfoId( const KStartupInfoId& id_P )
01038 {
01039 d = new KStartupInfoIdPrivate( *id_P.d );
01040 }
01041
01042 KStartupInfoId& KStartupInfoId::operator=( const KStartupInfoId& id_P )
01043 {
01044 if( &id_P == this )
01045 return *this;
01046 delete d;
01047 d = new KStartupInfoIdPrivate( *id_P.d );
01048 return *this;
01049 }
01050
01051 bool KStartupInfoId::operator==( const KStartupInfoId& id_P ) const
01052 {
01053 return id() == id_P.id();
01054 }
01055
01056 bool KStartupInfoId::operator!=( const KStartupInfoId& id_P ) const
01057 {
01058 return !(*this == id_P );
01059 }
01060
01061
01062 bool KStartupInfoId::operator<( const KStartupInfoId& id_P ) const
01063 {
01064 return id() < id_P.id();
01065 }
01066
01067 bool KStartupInfoId::none() const
01068 {
01069 return d->id.isEmpty() || d->id == "0";
01070 }
01071
01072 unsigned long KStartupInfoId::timestamp() const
01073 {
01074 if( none())
01075 return 0;
01076 int pos = d->id.findRev( "_TIME" );
01077 if( pos >= 0 )
01078 {
01079 bool ok;
01080 long time = d->id.mid( pos + 5 ).toLong( &ok );
01081 if( ok )
01082 return time;
01083 }
01084
01085
01086
01087
01088 int pos1 = d->id.findRev( '/' );
01089 if( pos1 > 0 )
01090 {
01091 int pos2 = d->id.findRev( '/', pos1 - 1 );
01092 if( pos2 >= 0 )
01093 {
01094 bool ok;
01095 long time = d->id.mid( pos2 + 1, pos1 - pos2 - 1 ).toLong( &ok );
01096 if( ok )
01097 return time;
01098 }
01099 }
01100
01101 return 0;
01102 }
01103
01104 struct KStartupInfoDataPrivate
01105 {
01106 KStartupInfoDataPrivate() : desktop( 0 ), wmclass( "" ), hostname( "" ),
01107 silent( KStartupInfoData::Unknown ), timestamp( -1U ), screen( -1 ) {};
01108 QString bin;
01109 QString name;
01110 QString description;
01111 QString icon;
01112 int desktop;
01113 QValueList< pid_t > pids;
01114 QCString wmclass;
01115 QCString hostname;
01116 KStartupInfoData::TriState silent;
01117 unsigned long timestamp;
01118 int screen;
01119 };
01120
01121 QString KStartupInfoData::to_text() const
01122 {
01123 QString ret = "";
01124 if( !d->bin.isEmpty())
01125 ret += QString::fromLatin1( " BIN=\"%1\"" ).arg( escape_str( d->bin ));
01126 if( !d->name.isEmpty())
01127 ret += QString::fromLatin1( " NAME=\"%1\"" ).arg( escape_str( d->name ));
01128 if( !d->description.isEmpty())
01129 ret += QString::fromLatin1( " DESCRIPTION=\"%1\"" ).arg( escape_str( d->description ));
01130 if( !d->icon.isEmpty())
01131 ret += QString::fromLatin1( " ICON=%1" ).arg( d->icon );
01132 if( d->desktop != 0 )
01133 ret += QString::fromLatin1( " DESKTOP=%1" )
01134 .arg( d->desktop == NET::OnAllDesktops ? NET::OnAllDesktops : d->desktop - 1 );
01135 if( !d->wmclass.isEmpty())
01136 ret += QString::fromLatin1( " WMCLASS=%1" ).arg( d->wmclass );
01137 if( !d->hostname.isEmpty())
01138 ret += QString::fromLatin1( " HOSTNAME=%1" ).arg( d->hostname );
01139 for( QValueList< pid_t >::ConstIterator it = d->pids.begin();
01140 it != d->pids.end();
01141 ++it )
01142 ret += QString::fromLatin1( " PID=%1" ).arg( *it );
01143 if( d->silent != Unknown )
01144 ret += QString::fromLatin1( " SILENT=%1" ).arg( d->silent == Yes ? 1 : 0 );
01145 if( d->timestamp != -1U )
01146 ret += QString::fromLatin1( " TIMESTAMP=%1" ).arg( d->timestamp );
01147 if( d->screen != -1 )
01148 ret += QString::fromLatin1( " SCREEN=%1" ).arg( d->screen );
01149 return ret;
01150 }
01151
01152 KStartupInfoData::KStartupInfoData( const QString& txt_P )
01153 {
01154 d = new KStartupInfoDataPrivate;
01155 QStringList items = get_fields( txt_P );
01156 const QString bin_str = QString::fromLatin1( "BIN=" );
01157 const QString name_str = QString::fromLatin1( "NAME=" );
01158 const QString description_str = QString::fromLatin1( "DESCRIPTION=" );
01159 const QString icon_str = QString::fromLatin1( "ICON=" );
01160 const QString desktop_str = QString::fromLatin1( "DESKTOP=" );
01161 const QString wmclass_str = QString::fromLatin1( "WMCLASS=" );
01162 const QString hostname_str = QString::fromLatin1( "HOSTNAME=" );
01163 const QString pid_str = QString::fromLatin1( "PID=" );
01164 const QString silent_str = QString::fromLatin1( "SILENT=" );
01165 const QString timestamp_str = QString::fromLatin1( "TIMESTAMP=" );
01166 const QString screen_str = QString::fromLatin1( "SCREEN=" );
01167 for( QStringList::Iterator it = items.begin();
01168 it != items.end();
01169 ++it )
01170 {
01171 if( ( *it ).startsWith( bin_str ))
01172 d->bin = get_str( *it );
01173 else if( ( *it ).startsWith( name_str ))
01174 d->name = get_str( *it );
01175 else if( ( *it ).startsWith( description_str ))
01176 d->description = get_str( *it );
01177 else if( ( *it ).startsWith( icon_str ))
01178 d->icon = get_str( *it );
01179 else if( ( *it ).startsWith( desktop_str ))
01180 {
01181 d->desktop = get_num( *it );
01182 if( d->desktop != NET::OnAllDesktops )
01183 ++d->desktop;
01184 }
01185 else if( ( *it ).startsWith( wmclass_str ))
01186 d->wmclass = get_cstr( *it );
01187 else if( ( *it ).startsWith( hostname_str ))
01188 d->hostname = get_cstr( *it );
01189 else if( ( *it ).startsWith( pid_str ))
01190 addPid( get_num( *it ));
01191 else if( ( *it ).startsWith( silent_str ))
01192 d->silent = get_num( *it ) != 0 ? Yes : No;
01193 else if( ( *it ).startsWith( timestamp_str ))
01194 d->timestamp = get_unum( *it );
01195 else if( ( *it ).startsWith( screen_str ))
01196 d->screen = get_num( *it );
01197 }
01198 }
01199
01200 KStartupInfoData::KStartupInfoData( const KStartupInfoData& data )
01201 {
01202 d = new KStartupInfoDataPrivate( *data.d );
01203 }
01204
01205 KStartupInfoData& KStartupInfoData::operator=( const KStartupInfoData& data )
01206 {
01207 if( &data == this )
01208 return *this;
01209 delete d;
01210 d = new KStartupInfoDataPrivate( *data.d );
01211 return *this;
01212 }
01213
01214 void KStartupInfoData::update( const KStartupInfoData& data_P )
01215 {
01216 if( !data_P.bin().isEmpty())
01217 d->bin = data_P.bin();
01218 if( !data_P.name().isEmpty() && name().isEmpty())
01219 d->name = data_P.name();
01220 if( !data_P.description().isEmpty() && description().isEmpty())
01221 d->description = data_P.description();
01222 if( !data_P.icon().isEmpty() && icon().isEmpty())
01223 d->icon = data_P.icon();
01224 if( data_P.desktop() != 0 && desktop() == 0 )
01225 d->desktop = data_P.desktop();
01226 if( !data_P.d->wmclass.isEmpty())
01227 d->wmclass = data_P.d->wmclass;
01228 if( !data_P.d->hostname.isEmpty())
01229 d->hostname = data_P.d->hostname;
01230 for( QValueList< pid_t >::ConstIterator it = data_P.d->pids.begin();
01231 it != data_P.d->pids.end();
01232 ++it )
01233 addPid( *it );
01234 if( data_P.silent() != Unknown )
01235 d->silent = data_P.silent();
01236 if( data_P.timestamp() != -1U && timestamp() == -1U )
01237 d->timestamp = data_P.timestamp();
01238 if( data_P.screen() != -1 )
01239 d->screen = data_P.screen();
01240 }
01241
01242 KStartupInfoData::KStartupInfoData()
01243 {
01244 d = new KStartupInfoDataPrivate;
01245 }
01246
01247 KStartupInfoData::~KStartupInfoData()
01248 {
01249 delete d;
01250 }
01251
01252 void KStartupInfoData::setBin( const QString& bin_P )
01253 {
01254 d->bin = bin_P;
01255 }
01256
01257 const QString& KStartupInfoData::bin() const
01258 {
01259 return d->bin;
01260 }
01261
01262 void KStartupInfoData::setName( const QString& name_P )
01263 {
01264 d->name = name_P;
01265 }
01266
01267 const QString& KStartupInfoData::name() const
01268 {
01269 return d->name;
01270 }
01271
01272 const QString& KStartupInfoData::findName() const
01273 {
01274 if( !name().isEmpty())
01275 return name();
01276 return bin();
01277 }
01278
01279 void KStartupInfoData::setDescription( const QString& desc_P )
01280 {
01281 d->description = desc_P;
01282 }
01283
01284 const QString& KStartupInfoData::description() const
01285 {
01286 return d->description;
01287 }
01288
01289 const QString& KStartupInfoData::findDescription() const
01290 {
01291 if( !description().isEmpty())
01292 return description();
01293 return name();
01294 }
01295
01296 void KStartupInfoData::setIcon( const QString& icon_P )
01297 {
01298 d->icon = icon_P;
01299 }
01300
01301 const QString& KStartupInfoData::findIcon() const
01302 {
01303 if( !icon().isEmpty())
01304 return icon();
01305 return bin();
01306 }
01307
01308 const QString& KStartupInfoData::icon() const
01309 {
01310 return d->icon;
01311 }
01312
01313 void KStartupInfoData::setDesktop( int desktop_P )
01314 {
01315 d->desktop = desktop_P;
01316 }
01317
01318 int KStartupInfoData::desktop() const
01319 {
01320 return d->desktop;
01321 }
01322
01323 void KStartupInfoData::setWMClass( const QCString& wmclass_P )
01324 {
01325 d->wmclass = wmclass_P;
01326 }
01327
01328 const QCString KStartupInfoData::findWMClass() const
01329 {
01330 if( !WMClass().isEmpty() && WMClass() != "0" )
01331 return WMClass();
01332 return bin().utf8();
01333 }
01334
01335 const QCString& KStartupInfoData::WMClass() const
01336 {
01337 return d->wmclass;
01338 }
01339
01340 void KStartupInfoData::setHostname( const QCString& hostname_P )
01341 {
01342 if( !hostname_P.isNull())
01343 d->hostname = hostname_P;
01344 else
01345 {
01346 char tmp[ 256 ];
01347 tmp[ 0 ] = '\0';
01348 if (!gethostname( tmp, 255 ))
01349 tmp[sizeof(tmp)-1] = '\0';
01350 d->hostname = tmp;
01351 }
01352 }
01353
01354 const QCString& KStartupInfoData::hostname() const
01355 {
01356 return d->hostname;
01357 }
01358
01359 void KStartupInfoData::addPid( pid_t pid_P )
01360 {
01361 if( !d->pids.contains( pid_P ))
01362 d->pids.append( pid_P );
01363 }
01364
01365 void KStartupInfoData::remove_pid( pid_t pid_P )
01366 {
01367 d->pids.remove( pid_P );
01368 }
01369
01370 const QValueList< pid_t >& KStartupInfoData::pids() const
01371 {
01372 return d->pids;
01373 }
01374
01375 bool KStartupInfoData::is_pid( pid_t pid_P ) const
01376 {
01377 return d->pids.contains( pid_P );
01378 }
01379
01380 void KStartupInfoData::setSilent( TriState state_P )
01381 {
01382 d->silent = state_P;
01383 }
01384
01385 KStartupInfoData::TriState KStartupInfoData::silent() const
01386 {
01387 return d->silent;
01388 }
01389
01390 void KStartupInfoData::setTimestamp( unsigned long time )
01391 {
01392 d->timestamp = time;
01393 }
01394
01395 unsigned long KStartupInfoData::timestamp() const
01396 {
01397 return d->timestamp;
01398 }
01399
01400 void KStartupInfoData::setScreen( int screen )
01401 {
01402 d->screen = screen;
01403 }
01404
01405 int KStartupInfoData::screen() const
01406 {
01407 return d->screen;
01408 }
01409
01410 static
01411 long get_num( const QString& item_P )
01412 {
01413 unsigned int pos = item_P.find( '=' );
01414 return item_P.mid( pos + 1 ).toLong();
01415 }
01416
01417 static
01418 unsigned long get_unum( const QString& item_P )
01419 {
01420 unsigned int pos = item_P.find( '=' );
01421 return item_P.mid( pos + 1 ).toULong();
01422 }
01423
01424 static
01425 QString get_str( const QString& item_P )
01426 {
01427 unsigned int pos = item_P.find( '=' );
01428 if( item_P.length() > pos + 2 && item_P[ pos + 1 ] == '\"' )
01429 {
01430 int pos2 = item_P.left( pos + 2 ).find( '\"' );
01431 if( pos2 < 0 )
01432 return QString::null;
01433 return item_P.mid( pos + 2, pos2 - 2 - pos );
01434 }
01435 return item_P.mid( pos + 1 );
01436 }
01437
01438 static
01439 QCString get_cstr( const QString& item_P )
01440 {
01441 return get_str( item_P ).utf8();
01442 }
01443
01444 static
01445 QStringList get_fields( const QString& txt_P )
01446 {
01447 QString txt = txt_P.simplifyWhiteSpace();
01448 QStringList ret;
01449 QString item = "";
01450 bool in = false;
01451 bool escape = false;
01452 for( unsigned int pos = 0;
01453 pos < txt.length();
01454 ++pos )
01455 {
01456 if( escape )
01457 {
01458 item += txt[ pos ];
01459 escape = false;
01460 }
01461 else if( txt[ pos ] == '\\' )
01462 escape = true;
01463 else if( txt[ pos ] == '\"' )
01464 in = !in;
01465 else if( txt[ pos ] == ' ' && !in )
01466 {
01467 ret.append( item );
01468 item = "";
01469 }
01470 else
01471 item += txt[ pos ];
01472 }
01473 ret.append( item );
01474 return ret;
01475 }
01476
01477 static QString escape_str( const QString& str_P )
01478 {
01479 QString ret = "";
01480 for( unsigned int pos = 0;
01481 pos < str_P.length();
01482 ++pos )
01483 {
01484 if( str_P[ pos ] == '\\'
01485 || str_P[ pos ] == '"' )
01486 ret += '\\';
01487 ret += str_P[ pos ];
01488 }
01489 return ret;
01490 }
01491
01492 #include "kstartupinfo.moc"
01493 #endif