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