kdecore Library API Documentation

kstartupinfo.cpp

00001 /**************************************************************************** 00002 00003 $Id: kstartupinfo.cpp,v 1.61 2005/01/25 10:23:34 faure 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 #ifdef Q_WS_X11 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 #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 // DESKTOP_STARTUP_ID is used also in kinit/wrapper.c 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() {}; // just because it's in a QMap 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 // contains silenced ASN's only if !AnnounceSilencedChanges 00097 QMap< KStartupInfoId, KStartupInfo::Data > silent_startups; 00098 // contains ASN's that had change: but no new: yet 00099 QMap< KStartupInfoId, KStartupInfo::Data > uninited_startups; 00100 #ifdef Q_WS_X11 00101 KWinModule* wm_module; 00102 KXMessages msgs; 00103 #endif 00104 QTimer* cleanup; 00105 int flags; 00106 KStartupInfoPrivate( int flags_P ) 00107 : 00108 #ifdef Q_WS_X11 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 // d == NULL means "disabled" 00131 if( !KApplication::kApplication()) 00132 return; 00133 if( !KApplication::kApplication()->getDisplay()) 00134 return; 00135 00136 d = new KStartupInfoPrivate( flags_P ); 00137 #ifdef Q_WS_X11 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 // TODO do something with SCREEN= ? 00160 kdDebug( 172 ) << "got:" << msg_P << endl; 00161 QString msg = msg_P.stripWhiteSpace(); 00162 if( msg.startsWith( "new:" )) // must match length below 00163 got_startup_info( msg.mid( 4 ), false ); 00164 else if( msg.startsWith( "change:" )) // must match length below 00165 got_startup_info( msg.mid( 7 ), true ); 00166 else if( msg.startsWith( "remove:" )) // must match length below 00167 got_remove_startup_info( msg.mid( 7 )); 00168 } 00169 00170 // if the application stops responding for a while, KWinModule may get 00171 // the information about the already mapped window before KXMessages 00172 // actually gets the info about the started application (depends 00173 // on their order in X11 event filter in KApplication) 00174 // simply delay info from KWinModule a bit 00175 // SELI??? 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; // nothing 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 { // already reported, update 00238 d->startups[ id_P ].update( data_P ); 00239 d->startups[ id_P ].age = 0; // CHECKME 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 { // already reported, update 00254 d->silent_startups[ id_P ].update( data_P ); 00255 d->silent_startups[ id_P ].age = 0; // CHECKME 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 ) // uninited finally got new: 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 // no change announce, it's still uninited 00279 return; 00280 } 00281 if( update_P ) // change: without any new: first 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 // new silenced, and silent shouldn't be announced 00293 { 00294 kdDebug( 172 ) << "adding silent" << endl; 00295 d->silent_startups.insert( id_P, data_P ); 00296 } 00297 d->cleanup->start( 1000 ); // 1 sec 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 { // first find the matching info 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; // not the matching info 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 ); // remove all pids from the info 00374 if( data->pids().count() == 0 ) // all pids removed -> remove info 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 // kdWarning( 172 ) << "NAME not specified in initial startup message" << endl; 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 ) // add automatically if needed 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 // if( id_P.none()) // id may be none, the pids and hostname matter then 00472 // return false; 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 // if( id_P.none()) // id may be none, the pids and hostname matter then 00485 // return false; 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 ) // KApplication constructor unsets the env. variable 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 ) // don't rely on qt_xdisplay() 00511 { 00512 #ifdef Q_WS_X11 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; // WM will take care of it 00558 } 00559 } 00560 if( activate ) 00561 // This is not very nice, but there's no way how to get any 00562 // usable timestamp without ASN, so force activating the window. 00563 // And even with ASN, it's not possible to get the timestamp here, 00564 // so if the WM doesn't have support for ASN, it can't be used either. 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; // no startups 00598 // Strategy: 00599 // 00600 // Is this a compliant app ? 00601 // - Yes - test for match 00602 // - No - Is this a NET_WM compliant app ? 00603 // - Yes - test for pid match 00604 // - No - test for WM_CLASS match 00605 kdDebug( 172 ) << "check_startup" << endl; 00606 QCString id = windowStartupId( w_P ); 00607 if( !id.isNull()) 00608 { 00609 if( id.isEmpty() || id == "0" ) // means ignore this window 00610 { 00611 kdDebug( 172 ) << "ignore" << endl; 00612 return NoMatch; 00613 } 00614 return find_id( id, id_O, data_O ) ? Match : NoMatch; 00615 } 00616 #ifdef Q_WS_X11 00617 NETWinInfo info( qt_xdisplay(), w_P, qt_xrootwin(), 00618 NET::WMWindowType | NET::WMPid | NET::WMState ); 00619 pid_t pid = info.pid(); 00620 if( pid > 0 ) 00621 { 00622 QCString hostname = get_window_hostname( w_P ); 00623 if( !hostname.isEmpty() 00624 && find_pid( pid, hostname, id_O, data_O )) 00625 return Match; 00626 // try XClass matching , this PID stuff sucks :( 00627 } 00628 XClassHint hint; 00629 if( XGetClassHint( qt_xdisplay(), w_P, &hint ) != 0 ) 00630 { // We managed to read the class hint 00631 QCString res_name = hint.res_name; 00632 QCString res_class = hint.res_class; 00633 XFree( hint.res_name ); 00634 XFree( hint.res_class ); 00635 if( find_wclass( res_name, res_class, id_O, data_O )) 00636 return Match; 00637 } 00638 // ignore NET::Tool and other special window types, if they can't be matched 00639 NET::WindowType type = info.windowType( NET::NormalMask | NET::DesktopMask 00640 | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask 00641 | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask ); 00642 if( type != NET::Normal 00643 && type != NET::Override 00644 && type != NET::Unknown 00645 && type != NET::Dialog 00646 && type != NET::Utility ) 00647 // && type != NET::Dock ) why did I put this here? 00648 return NoMatch; 00649 // lets see if this is a transient 00650 Window transient_for; 00651 if( XGetTransientForHint( qt_xdisplay(), static_cast< Window >( w_P ), &transient_for ) 00652 && static_cast< WId >( transient_for ) != qt_xrootwin() 00653 && transient_for != None ) 00654 return NoMatch; 00655 #endif 00656 kdDebug( 172 ) << "check_startup:cantdetect" << endl; 00657 return CantDetect; 00658 } 00659 00660 bool KStartupInfo::find_id( const QCString& id_P, KStartupInfoId* id_O, 00661 KStartupInfoData* data_O ) 00662 { 00663 if( d == NULL ) 00664 return false; 00665 kdDebug( 172 ) << "find_id:" << id_P << endl; 00666 KStartupInfoId id; 00667 id.initId( id_P ); 00668 if( d->startups.contains( id )) 00669 { 00670 if( id_O != NULL ) 00671 *id_O = id; 00672 if( data_O != NULL ) 00673 *data_O = d->startups[ id ]; 00674 kdDebug( 172 ) << "check_startup_id:match" << endl; 00675 return true; 00676 } 00677 return false; 00678 } 00679 00680 bool KStartupInfo::find_pid( pid_t pid_P, const QCString& hostname_P, 00681 KStartupInfoId* id_O, KStartupInfoData* data_O ) 00682 { 00683 if( d == NULL ) 00684 return false; 00685 kdDebug( 172 ) << "find_pid:" << pid_P << endl; 00686 for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin(); 00687 it != d->startups.end(); 00688 ++it ) 00689 { 00690 if( ( *it ).is_pid( pid_P ) && ( *it ).hostname() == hostname_P ) 00691 { // Found it ! 00692 if( id_O != NULL ) 00693 *id_O = it.key(); 00694 if( data_O != NULL ) 00695 *data_O = *it; 00696 // non-compliant, remove on first match 00697 remove_startup_info_internal( it.key()); 00698 kdDebug( 172 ) << "check_startup_pid:match" << endl; 00699 return true; 00700 } 00701 } 00702 return false; 00703 } 00704 00705 bool KStartupInfo::find_wclass( QCString res_name, QCString res_class, 00706 KStartupInfoId* id_O, KStartupInfoData* data_O ) 00707 { 00708 if( d == NULL ) 00709 return false; 00710 res_name = res_name.lower(); 00711 res_class = res_class.lower(); 00712 kdDebug( 172 ) << "find_wclass:" << res_name << ":" << res_class << endl; 00713 for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin(); 00714 it != d->startups.end(); 00715 ++it ) 00716 { 00717 const QCString wmclass = ( *it ).findWMClass(); 00718 if( wmclass.lower() == res_name || wmclass.lower() == res_class ) 00719 { // Found it ! 00720 if( id_O != NULL ) 00721 *id_O = it.key(); 00722 if( data_O != NULL ) 00723 *data_O = *it; 00724 // non-compliant, remove on first match 00725 remove_startup_info_internal( it.key()); 00726 kdDebug( 172 ) << "check_startup_wclass:match" << endl; 00727 return true; 00728 } 00729 } 00730 return false; 00731 } 00732 00733 #ifdef Q_WS_X11 00734 static Atom net_startup_atom = None; 00735 00736 static QCString read_startup_id_property( WId w_P ) 00737 { 00738 QCString ret; 00739 unsigned char *name_ret; 00740 Atom type_ret; 00741 int format_ret; 00742 unsigned long nitems_ret = 0, after_ret = 0; 00743 if( XGetWindowProperty( qt_xdisplay(), w_P, net_startup_atom, 0l, 4096, 00744 False, utf8_string_atom, &type_ret, &format_ret, &nitems_ret, &after_ret, &name_ret ) 00745 == Success ) 00746 { 00747 if( type_ret == utf8_string_atom && format_ret == 8 && name_ret != NULL ) 00748 ret = reinterpret_cast< char* >( name_ret ); 00749 if ( name_ret != NULL ) 00750 XFree( name_ret ); 00751 } 00752 return ret; 00753 } 00754 00755 #endif 00756 00757 QCString KStartupInfo::windowStartupId( WId w_P ) 00758 { 00759 #ifdef Q_WS_X11 00760 if( net_startup_atom == None ) 00761 net_startup_atom = XInternAtom( qt_xdisplay(), NET_STARTUP_WINDOW, False ); 00762 if( utf8_string_atom == None ) 00763 utf8_string_atom = XInternAtom( qt_xdisplay(), "UTF8_STRING", False ); 00764 QCString ret = read_startup_id_property( w_P ); 00765 if( ret.isEmpty()) 00766 { // retry with window group leader, as the spec says 00767 XWMHints* hints = XGetWMHints( qt_xdisplay(), w_P ); 00768 if( hints && ( hints->flags & WindowGroupHint ) != 0 ) 00769 ret = read_startup_id_property( hints->window_group ); 00770 if( hints ) 00771 XFree( hints ); 00772 } 00773 return ret; 00774 #else 00775 return QCString(); 00776 #endif 00777 } 00778 00779 void KStartupInfo::setWindowStartupId( WId w_P, const QCString& id_P ) 00780 { 00781 #ifdef Q_WS_X11 00782 if( id_P.isNull()) 00783 return; 00784 if( net_startup_atom == None ) 00785 net_startup_atom = XInternAtom( qt_xdisplay(), NET_STARTUP_WINDOW, False ); 00786 if( utf8_string_atom == None ) 00787 utf8_string_atom = XInternAtom( qt_xdisplay(), "UTF8_STRING", False ); 00788 XChangeProperty( qt_xdisplay(), w_P, net_startup_atom, utf8_string_atom, 8, 00789 PropModeReplace, reinterpret_cast< unsigned char* >( id_P.data()), id_P.length()); 00790 #endif 00791 } 00792 00793 QCString KStartupInfo::get_window_hostname( WId w_P ) 00794 { 00795 #ifdef Q_WS_X11 00796 XTextProperty tp; 00797 char** hh; 00798 int cnt; 00799 if( XGetWMClientMachine( qt_xdisplay(), w_P, &tp ) != 0 00800 && XTextPropertyToStringList( &tp, &hh, &cnt ) != 0 ) 00801 { 00802 if( cnt == 1 ) 00803 { 00804 QCString hostname = hh[ 0 ]; 00805 XFreeStringList( hh ); 00806 return hostname; 00807 } 00808 XFreeStringList( hh ); 00809 } 00810 #endif 00811 // no hostname 00812 return QCString(); 00813 } 00814 00815 void KStartupInfo::setTimeout( unsigned int secs_P ) 00816 { 00817 timeout = secs_P; 00818 // schedule removing entries that are older than the new timeout 00819 QTimer::singleShot( 0, this, SLOT( startups_cleanup_no_age())); 00820 } 00821 00822 void KStartupInfo::startups_cleanup_no_age() 00823 { 00824 startups_cleanup_internal( false ); 00825 } 00826 00827 void KStartupInfo::startups_cleanup() 00828 { 00829 if( d == NULL ) 00830 return; 00831 if( d->startups.count() == 0 && d->silent_startups.count() == 0 00832 && d->uninited_startups.count() == 0 ) 00833 { 00834 d->cleanup->stop(); 00835 return; 00836 } 00837 startups_cleanup_internal( true ); 00838 } 00839 00840 void KStartupInfo::startups_cleanup_internal( bool age_P ) 00841 { 00842 if( d == NULL ) 00843 return; 00844 for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin(); 00845 it != d->startups.end(); 00846 ) 00847 { 00848 if( age_P ) 00849 ( *it ).age++; 00850 unsigned int tout = timeout; 00851 if( ( *it ).silent() == Data::Yes ) // TODO 00852 tout *= 20; 00853 if( ( *it ).age >= tout ) 00854 { 00855 const KStartupInfoId& key = it.key(); 00856 ++it; 00857 kdDebug( 172 ) << "entry timeout:" << key.id() << endl; 00858 remove_startup_info_internal( key ); 00859 } 00860 else 00861 ++it; 00862 } 00863 for( QMap< KStartupInfoId, Data >::Iterator it = d->silent_startups.begin(); 00864 it != d->silent_startups.end(); 00865 ) 00866 { 00867 if( age_P ) 00868 ( *it ).age++; 00869 unsigned int tout = timeout; 00870 if( ( *it ).silent() == Data::Yes ) // TODO 00871 tout *= 20; 00872 if( ( *it ).age >= tout ) 00873 { 00874 const KStartupInfoId& key = it.key(); 00875 ++it; 00876 kdDebug( 172 ) << "entry timeout:" << key.id() << endl; 00877 remove_startup_info_internal( key ); 00878 } 00879 else 00880 ++it; 00881 } 00882 for( QMap< KStartupInfoId, Data >::Iterator it = d->uninited_startups.begin(); 00883 it != d->uninited_startups.end(); 00884 ) 00885 { 00886 if( age_P ) 00887 ( *it ).age++; 00888 unsigned int tout = timeout; 00889 if( ( *it ).silent() == Data::Yes ) // TODO 00890 tout *= 20; 00891 if( ( *it ).age >= tout ) 00892 { 00893 const KStartupInfoId& key = it.key(); 00894 ++it; 00895 kdDebug( 172 ) << "entry timeout:" << key.id() << endl; 00896 remove_startup_info_internal( key ); 00897 } 00898 else 00899 ++it; 00900 } 00901 } 00902 00903 void KStartupInfo::clean_all_noncompliant() 00904 { 00905 if( d == NULL ) 00906 return; 00907 for( QMap< KStartupInfoId, Data >::Iterator it = d->startups.begin(); 00908 it != d->startups.end(); 00909 ) 00910 { 00911 if( ( *it ).WMClass() != "0" ) 00912 { 00913 ++it; 00914 continue; 00915 } 00916 const KStartupInfoId& key = it.key(); 00917 ++it; 00918 kdDebug( 172 ) << "entry cleaning:" << key.id() << endl; 00919 remove_startup_info_internal( key ); 00920 } 00921 } 00922 00923 QCString KStartupInfo::createNewStartupId() 00924 { 00925 // Assign a unique id, use hostname+time+pid, that should be 200% unique. 00926 // Also append the user timestamp (for focus stealing prevention). 00927 struct timeval tm; 00928 gettimeofday( &tm, NULL ); 00929 char hostname[ 256 ]; 00930 hostname[ 0 ] = '\0'; 00931 if (!gethostname( hostname, 255 )) 00932 hostname[sizeof(hostname)-1] = '\0'; 00933 #ifdef Q_WS_X11 00934 extern Time qt_x_user_time; 00935 #else 00936 long qt_x_user_time = 0; 00937 #endif 00938 QCString id = QString( "%1;%2;%3;%4_TIME%5" ).arg( hostname ).arg( tm.tv_sec ) 00939 .arg( tm.tv_usec ).arg( getpid()).arg( qt_x_user_time ).utf8(); 00940 kdDebug( 172 ) << "creating: " << id << ":" << qAppName() << endl; 00941 return id; 00942 } 00943 00944 00945 struct KStartupInfoIdPrivate 00946 { 00947 KStartupInfoIdPrivate() : id( "" ) {}; 00948 QCString id; // id 00949 }; 00950 00951 const QCString& KStartupInfoId::id() const 00952 { 00953 return d->id; 00954 } 00955 00956 00957 QString KStartupInfoId::to_text() const 00958 { 00959 return QString::fromLatin1( " ID=\"%1\" " ).arg( escape_str( id())); 00960 } 00961 00962 KStartupInfoId::KStartupInfoId( const QString& txt_P ) 00963 { 00964 d = new KStartupInfoIdPrivate; 00965 QStringList items = get_fields( txt_P ); 00966 const QString id_str = QString::fromLatin1( "ID=" ); 00967 for( QStringList::Iterator it = items.begin(); 00968 it != items.end(); 00969 ++it ) 00970 { 00971 if( ( *it ).startsWith( id_str )) 00972 d->id = get_cstr( *it ); 00973 } 00974 } 00975 00976 void KStartupInfoId::initId( const QCString& id_P ) 00977 { 00978 if( !id_P.isEmpty()) 00979 { 00980 d->id = id_P; 00981 #ifdef KSTARTUPINFO_ALL_DEBUG 00982 kdDebug( 172 ) << "using: " << d->id << endl; 00983 #endif 00984 return; 00985 } 00986 const char* startup_env = getenv( NET_STARTUP_ENV ); 00987 if( startup_env != NULL && *startup_env != '\0' ) 00988 { // already has id 00989 d->id = startup_env; 00990 #ifdef KSTARTUPINFO_ALL_DEBUG 00991 kdDebug( 172 ) << "reusing: " << d->id << endl; 00992 #endif 00993 return; 00994 } 00995 d->id = KStartupInfo::createNewStartupId(); 00996 } 00997 00998 bool KStartupInfoId::setupStartupEnv() const 00999 { 01000 if( id().isEmpty()) 01001 { 01002 unsetenv( NET_STARTUP_ENV ); 01003 return false; 01004 } 01005 return setenv( NET_STARTUP_ENV, id(), true ) == 0; 01006 } 01007 01008 KStartupInfoId KStartupInfo::currentStartupIdEnv() 01009 { 01010 const char* startup_env = getenv( NET_STARTUP_ENV ); 01011 KStartupInfoId id; 01012 if( startup_env != NULL && *startup_env != '\0' ) 01013 id.d->id = startup_env; 01014 else 01015 id.d->id = "0"; 01016 return id; 01017 } 01018 01019 void KStartupInfo::resetStartupEnv() 01020 { 01021 unsetenv( NET_STARTUP_ENV ); 01022 } 01023 01024 KStartupInfoId::KStartupInfoId() 01025 { 01026 d = new KStartupInfoIdPrivate; 01027 } 01028 01029 KStartupInfoId::~KStartupInfoId() 01030 { 01031 delete d; 01032 } 01033 01034 KStartupInfoId::KStartupInfoId( const KStartupInfoId& id_P ) 01035 { 01036 d = new KStartupInfoIdPrivate( *id_P.d ); 01037 } 01038 01039 KStartupInfoId& KStartupInfoId::operator=( const KStartupInfoId& id_P ) 01040 { 01041 if( &id_P == this ) 01042 return *this; 01043 delete d; 01044 d = new KStartupInfoIdPrivate( *id_P.d ); 01045 return *this; 01046 } 01047 01048 bool KStartupInfoId::operator==( const KStartupInfoId& id_P ) const 01049 { 01050 return id() == id_P.id(); 01051 } 01052 01053 bool KStartupInfoId::operator!=( const KStartupInfoId& id_P ) const 01054 { 01055 return !(*this == id_P ); 01056 } 01057 01058 // needed for QMap 01059 bool KStartupInfoId::operator<( const KStartupInfoId& id_P ) const 01060 { 01061 return id() < id_P.id(); 01062 } 01063 01064 bool KStartupInfoId::none() const 01065 { 01066 return d->id.isEmpty() || d->id == "0"; 01067 } 01068 01069 unsigned long KStartupInfoId::timestamp() const 01070 { 01071 if( none()) 01072 return 0; 01073 int pos = d->id.findRev( "_TIME" ); 01074 if( pos >= 0 ) 01075 { 01076 bool ok; 01077 long time = d->id.mid( pos + 5 ).toLong( &ok ); 01078 if( ok ) 01079 return time; 01080 } 01081 // libstartup-notification style : 01082 // snprintf (s, len, "%s/%s/%lu/%d-%d-%s", 01083 // canonicalized_launcher, canonicalized_launchee, (unsigned long) timestamp, 01084 // (int) getpid (), (int) sequence_number, hostbuf); 01085 int pos1 = d->id.findRev( '/' ); 01086 if( pos1 > 0 ) 01087 { 01088 int pos2 = d->id.findRev( '/', pos1 - 1 ); 01089 if( pos2 >= 0 ) 01090 { 01091 bool ok; 01092 long time = d->id.mid( pos2 + 1, pos1 - pos2 - 1 ).toLong( &ok ); 01093 if( ok ) 01094 return time; 01095 } 01096 } 01097 // bah ... old KStartupInfo or a problem 01098 return 0; 01099 } 01100 01101 struct KStartupInfoDataPrivate 01102 { 01103 KStartupInfoDataPrivate() : desktop( 0 ), wmclass( "" ), hostname( "" ), 01104 silent( KStartupInfoData::Unknown ), timestamp( -1U ), screen( -1 ) {}; 01105 QString bin; 01106 QString name; 01107 QString description; 01108 QString icon; 01109 int desktop; 01110 QValueList< pid_t > pids; 01111 QCString wmclass; 01112 QCString hostname; 01113 KStartupInfoData::TriState silent; 01114 unsigned long timestamp; 01115 int screen; 01116 }; 01117 01118 QString KStartupInfoData::to_text() const 01119 { 01120 QString ret = ""; 01121 if( !d->bin.isEmpty()) 01122 ret += QString::fromLatin1( " BIN=\"%1\"" ).arg( escape_str( d->bin )); 01123 if( !d->name.isEmpty()) 01124 ret += QString::fromLatin1( " NAME=\"%1\"" ).arg( escape_str( d->name )); 01125 if( !d->description.isEmpty()) 01126 ret += QString::fromLatin1( " DESCRIPTION=\"%1\"" ).arg( escape_str( d->description )); 01127 if( !d->icon.isEmpty()) 01128 ret += QString::fromLatin1( " ICON=%1" ).arg( d->icon ); 01129 if( d->desktop != 0 ) 01130 ret += QString::fromLatin1( " DESKTOP=%1" ) 01131 .arg( d->desktop == NET::OnAllDesktops ? NET::OnAllDesktops : d->desktop - 1 ); // spec counts from 0 01132 if( !d->wmclass.isEmpty()) 01133 ret += QString::fromLatin1( " WMCLASS=%1" ).arg( d->wmclass ); 01134 if( !d->hostname.isEmpty()) 01135 ret += QString::fromLatin1( " HOSTNAME=%1" ).arg( d->hostname ); 01136 for( QValueList< pid_t >::ConstIterator it = d->pids.begin(); 01137 it != d->pids.end(); 01138 ++it ) 01139 ret += QString::fromLatin1( " PID=%1" ).arg( *it ); 01140 if( d->silent != Unknown ) 01141 ret += QString::fromLatin1( " SILENT=%1" ).arg( d->silent == Yes ? 1 : 0 ); 01142 if( d->timestamp != -1U ) 01143 ret += QString::fromLatin1( " TIMESTAMP=%1" ).arg( d->timestamp ); 01144 if( d->screen != -1 ) 01145 ret += QString::fromLatin1( " SCREEN=%1" ).arg( d->screen ); 01146 return ret; 01147 } 01148 01149 KStartupInfoData::KStartupInfoData( const QString& txt_P ) 01150 { 01151 d = new KStartupInfoDataPrivate; 01152 QStringList items = get_fields( txt_P ); 01153 const QString bin_str = QString::fromLatin1( "BIN=" ); 01154 const QString name_str = QString::fromLatin1( "NAME=" ); 01155 const QString description_str = QString::fromLatin1( "DESCRIPTION=" ); 01156 const QString icon_str = QString::fromLatin1( "ICON=" ); 01157 const QString desktop_str = QString::fromLatin1( "DESKTOP=" ); 01158 const QString wmclass_str = QString::fromLatin1( "WMCLASS=" ); 01159 const QString hostname_str = QString::fromLatin1( "HOSTNAME=" ); // SELI nonstd 01160 const QString pid_str = QString::fromLatin1( "PID=" ); // SELI nonstd 01161 const QString silent_str = QString::fromLatin1( "SILENT=" ); 01162 const QString timestamp_str = QString::fromLatin1( "TIMESTAMP=" ); 01163 const QString screen_str = QString::fromLatin1( "SCREEN=" ); 01164 for( QStringList::Iterator it = items.begin(); 01165 it != items.end(); 01166 ++it ) 01167 { 01168 if( ( *it ).startsWith( bin_str )) 01169 d->bin = get_str( *it ); 01170 else if( ( *it ).startsWith( name_str )) 01171 d->name = get_str( *it ); 01172 else if( ( *it ).startsWith( description_str )) 01173 d->description = get_str( *it ); 01174 else if( ( *it ).startsWith( icon_str )) 01175 d->icon = get_str( *it ); 01176 else if( ( *it ).startsWith( desktop_str )) 01177 { 01178 d->desktop = get_num( *it ); 01179 if( d->desktop != NET::OnAllDesktops ) 01180 ++d->desktop; // spec counts from 0 01181 } 01182 else if( ( *it ).startsWith( wmclass_str )) 01183 d->wmclass = get_cstr( *it ); 01184 else if( ( *it ).startsWith( hostname_str )) 01185 d->hostname = get_cstr( *it ); 01186 else if( ( *it ).startsWith( pid_str )) 01187 addPid( get_num( *it )); 01188 else if( ( *it ).startsWith( silent_str )) 01189 d->silent = get_num( *it ) != 0 ? Yes : No; 01190 else if( ( *it ).startsWith( timestamp_str )) 01191 d->timestamp = get_unum( *it ); 01192 else if( ( *it ).startsWith( screen_str )) 01193 d->screen = get_num( *it ); 01194 } 01195 } 01196 01197 KStartupInfoData::KStartupInfoData( const KStartupInfoData& data ) 01198 { 01199 d = new KStartupInfoDataPrivate( *data.d ); 01200 } 01201 01202 KStartupInfoData& KStartupInfoData::operator=( const KStartupInfoData& data ) 01203 { 01204 if( &data == this ) 01205 return *this; 01206 delete d; 01207 d = new KStartupInfoDataPrivate( *data.d ); 01208 return *this; 01209 } 01210 01211 void KStartupInfoData::update( const KStartupInfoData& data_P ) 01212 { 01213 if( !data_P.bin().isEmpty()) 01214 d->bin = data_P.bin(); 01215 if( !data_P.name().isEmpty() && name().isEmpty()) // don't overwrite 01216 d->name = data_P.name(); 01217 if( !data_P.description().isEmpty() && description().isEmpty()) // don't overwrite 01218 d->description = data_P.description(); 01219 if( !data_P.icon().isEmpty() && icon().isEmpty()) // don't overwrite 01220 d->icon = data_P.icon(); 01221 if( data_P.desktop() != 0 && desktop() == 0 ) // don't overwrite 01222 d->desktop = data_P.desktop(); 01223 if( !data_P.d->wmclass.isEmpty()) 01224 d->wmclass = data_P.d->wmclass; 01225 if( !data_P.d->hostname.isEmpty()) 01226 d->hostname = data_P.d->hostname; 01227 for( QValueList< pid_t >::ConstIterator it = data_P.d->pids.begin(); 01228 it != data_P.d->pids.end(); 01229 ++it ) 01230 addPid( *it ); 01231 if( data_P.silent() != Unknown ) 01232 d->silent = data_P.silent(); 01233 if( data_P.timestamp() != -1U && timestamp() == -1U ) // don't overwrite 01234 d->timestamp = data_P.timestamp(); 01235 if( data_P.screen() != -1 ) 01236 d->screen = data_P.screen(); 01237 } 01238 01239 KStartupInfoData::KStartupInfoData() 01240 { 01241 d = new KStartupInfoDataPrivate; 01242 } 01243 01244 KStartupInfoData::~KStartupInfoData() 01245 { 01246 delete d; 01247 } 01248 01249 void KStartupInfoData::setBin( const QString& bin_P ) 01250 { 01251 d->bin = bin_P; 01252 } 01253 01254 const QString& KStartupInfoData::bin() const 01255 { 01256 return d->bin; 01257 } 01258 01259 void KStartupInfoData::setName( const QString& name_P ) 01260 { 01261 d->name = name_P; 01262 } 01263 01264 const QString& KStartupInfoData::name() const 01265 { 01266 return d->name; 01267 } 01268 01269 const QString& KStartupInfoData::findName() const 01270 { 01271 if( !name().isEmpty()) 01272 return name(); 01273 return bin(); 01274 } 01275 01276 void KStartupInfoData::setDescription( const QString& desc_P ) 01277 { 01278 d->description = desc_P; 01279 } 01280 01281 const QString& KStartupInfoData::description() const 01282 { 01283 return d->description; 01284 } 01285 01286 const QString& KStartupInfoData::findDescription() const 01287 { 01288 if( !description().isEmpty()) 01289 return description(); 01290 return name(); 01291 } 01292 01293 void KStartupInfoData::setIcon( const QString& icon_P ) 01294 { 01295 d->icon = icon_P; 01296 } 01297 01298 const QString& KStartupInfoData::findIcon() const 01299 { 01300 if( !icon().isEmpty()) 01301 return icon(); 01302 return bin(); 01303 } 01304 01305 const QString& KStartupInfoData::icon() const 01306 { 01307 return d->icon; 01308 } 01309 01310 void KStartupInfoData::setDesktop( int desktop_P ) 01311 { 01312 d->desktop = desktop_P; 01313 } 01314 01315 int KStartupInfoData::desktop() const 01316 { 01317 return d->desktop; 01318 } 01319 01320 void KStartupInfoData::setWMClass( const QCString& wmclass_P ) 01321 { 01322 d->wmclass = wmclass_P; 01323 } 01324 01325 const QCString KStartupInfoData::findWMClass() const 01326 { 01327 if( !WMClass().isEmpty() && WMClass() != "0" ) 01328 return WMClass(); 01329 return bin().utf8(); 01330 } 01331 01332 const QCString& KStartupInfoData::WMClass() const 01333 { 01334 return d->wmclass; 01335 } 01336 01337 void KStartupInfoData::setHostname( const QCString& hostname_P ) 01338 { 01339 if( !hostname_P.isNull()) 01340 d->hostname = hostname_P; 01341 else 01342 { 01343 char tmp[ 256 ]; 01344 tmp[ 0 ] = '\0'; 01345 if (!gethostname( tmp, 255 )) 01346 tmp[sizeof(tmp)-1] = '\0'; 01347 d->hostname = tmp; 01348 } 01349 } 01350 01351 const QCString& KStartupInfoData::hostname() const 01352 { 01353 return d->hostname; 01354 } 01355 01356 void KStartupInfoData::addPid( pid_t pid_P ) 01357 { 01358 if( !d->pids.contains( pid_P )) 01359 d->pids.append( pid_P ); 01360 } 01361 01362 void KStartupInfoData::remove_pid( pid_t pid_P ) 01363 { 01364 d->pids.remove( pid_P ); 01365 } 01366 01367 const QValueList< pid_t >& KStartupInfoData::pids() const 01368 { 01369 return d->pids; 01370 } 01371 01372 bool KStartupInfoData::is_pid( pid_t pid_P ) const 01373 { 01374 return d->pids.contains( pid_P ); 01375 } 01376 01377 void KStartupInfoData::setSilent( TriState state_P ) 01378 { 01379 d->silent = state_P; 01380 } 01381 01382 KStartupInfoData::TriState KStartupInfoData::silent() const 01383 { 01384 return d->silent; 01385 } 01386 01387 void KStartupInfoData::setTimestamp( unsigned long time ) 01388 { 01389 d->timestamp = time; 01390 } 01391 01392 unsigned long KStartupInfoData::timestamp() const 01393 { 01394 return d->timestamp; 01395 } 01396 01397 void KStartupInfoData::setScreen( int screen ) 01398 { 01399 d->screen = screen; 01400 } 01401 01402 int KStartupInfoData::screen() const 01403 { 01404 return d->screen; 01405 } 01406 01407 static 01408 long get_num( const QString& item_P ) 01409 { 01410 unsigned int pos = item_P.find( '=' ); 01411 return item_P.mid( pos + 1 ).toLong(); 01412 } 01413 01414 static 01415 unsigned long get_unum( const QString& item_P ) 01416 { 01417 unsigned int pos = item_P.find( '=' ); 01418 return item_P.mid( pos + 1 ).toULong(); 01419 } 01420 01421 static 01422 QString get_str( const QString& item_P ) 01423 { 01424 unsigned int pos = item_P.find( '=' ); 01425 if( item_P.length() > pos + 2 && item_P[ pos + 1 ] == '\"' ) 01426 { 01427 int pos2 = item_P.left( pos + 2 ).find( '\"' ); 01428 if( pos2 < 0 ) 01429 return QString::null; // 01234 01430 return item_P.mid( pos + 2, pos2 - 2 - pos ); // A="C" 01431 } 01432 return item_P.mid( pos + 1 ); 01433 } 01434 01435 static 01436 QCString get_cstr( const QString& item_P ) 01437 { 01438 return get_str( item_P ).utf8(); 01439 } 01440 01441 static 01442 QStringList get_fields( const QString& txt_P ) 01443 { 01444 QString txt = txt_P.simplifyWhiteSpace(); 01445 QStringList ret; 01446 QString item = ""; 01447 bool in = false; 01448 bool escape = false; 01449 for( unsigned int pos = 0; 01450 pos < txt.length(); 01451 ++pos ) 01452 { 01453 if( escape ) 01454 { 01455 item += txt[ pos ]; 01456 escape = false; 01457 } 01458 else if( txt[ pos ] == '\\' ) 01459 escape = true; 01460 else if( txt[ pos ] == '\"' ) 01461 in = !in; 01462 else if( txt[ pos ] == ' ' && !in ) 01463 { 01464 ret.append( item ); 01465 item = ""; 01466 } 01467 else 01468 item += txt[ pos ]; 01469 } 01470 ret.append( item ); 01471 return ret; 01472 } 01473 01474 static QString escape_str( const QString& str_P ) 01475 { 01476 QString ret = ""; 01477 for( unsigned int pos = 0; 01478 pos < str_P.length(); 01479 ++pos ) 01480 { 01481 if( str_P[ pos ] == '\\' 01482 || str_P[ pos ] == '"' ) 01483 ret += '\\'; 01484 ret += str_P[ pos ]; 01485 } 01486 return ret; 01487 } 01488 01489 #include "kstartupinfo.moc" 01490 #endif
KDE Logo
This file is part of the documentation for kdecore Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Apr 14 00:03:33 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003