kdecore Library API Documentation

kstartupinfo.cpp

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