• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KDECore

kstartupinfo.cpp

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

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal