kdecore Library API Documentation

kstartupinfo.cpp

00001 /**************************************************************************** 00002 00003 $Id: kstartupinfo.cpp,v 1.59 2004/07/15 14:07:27 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> 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 // 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 #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 // 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 #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 // 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 #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; // 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 #if defined Q_WS_X11 && ! defined K_WS_QTONLY 00599 // SELI ??? 00600 NETWinInfo info( qt_xdisplay(), w_P, qt_xrootwin(), 00601 NET::WMWindowType | NET::WMPid | NET::WMState ); 00602 // ignore NET::Tool and other special window types 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 // && type != NET::Dock ) why did I put this here? 00612 return NoMatch; 00613 // lets see if this is a transient 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 // Strategy: 00621 // 00622 // Is this a compliant app ? 00623 // - Yes - test for match 00624 // - No - Is this a NET_WM compliant app ? 00625 // - Yes - test for pid match 00626 // - No - test for WM_CLASS match 00627 kdDebug( 172 ) << "check_startup" << endl; 00628 QCString id = windowStartupId( w_P ); 00629 if( !id.isNull()) 00630 { 00631 if( id.isEmpty() || id == "0" ) // means ignore this window 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 // try XClass matching , this PID stuff sucks :( 00647 } 00648 XClassHint hint; 00649 if( XGetClassHint( qt_xdisplay(), w_P, &hint ) != 0 ) 00650 { // We managed to read the class hint 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 { // Found it ! 00695 if( id_O != NULL ) 00696 *id_O = it.key(); 00697 if( data_O != NULL ) 00698 *data_O = *it; 00699 // non-compliant, remove on first match 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 { // Found it ! 00723 if( id_O != NULL ) 00724 *id_O = it.key(); 00725 if( data_O != NULL ) 00726 *data_O = *it; 00727 // non-compliant, remove on first match 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 { // retry with window group leader, as the spec says 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 // no hostname 00815 return QCString(); 00816 } 00817 00818 void KStartupInfo::setTimeout( unsigned int secs_P ) 00819 { 00820 timeout = secs_P; 00821 // schedule removing entries that are older than the new timeout 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 ) // TODO 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 ) // TODO 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 ) // TODO 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 // Assign a unique id, use hostname+time+pid, that should be 200% unique. 00929 // Also append the user timestamp (for focus stealing prevention). 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; // 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 { // already has id 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 // needed for QMap 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 // libstartup-notification style : 01085 // snprintf (s, len, "%s/%s/%lu/%d-%d-%s", 01086 // canonicalized_launcher, canonicalized_launchee, (unsigned long) timestamp, 01087 // (int) getpid (), (int) sequence_number, hostbuf); 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 // bah ... old KStartupInfo or a problem 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 ); // spec counts from 0 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=" ); // SELI nonstd 01163 const QString pid_str = QString::fromLatin1( "PID=" ); // SELI nonstd 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; // spec counts from 0 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()) // don't overwrite 01219 d->name = data_P.name(); 01220 if( !data_P.description().isEmpty() && description().isEmpty()) // don't overwrite 01221 d->description = data_P.description(); 01222 if( !data_P.icon().isEmpty() && icon().isEmpty()) // don't overwrite 01223 d->icon = data_P.icon(); 01224 if( data_P.desktop() != 0 && desktop() == 0 ) // don't overwrite 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 ) // don't overwrite 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; // 01234 01433 return item_P.mid( pos + 2, pos2 - 2 - pos ); // A="C" 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
KDE Logo
This file is part of the documentation for kdecore Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 17 11:26:10 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003