• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdecore
 

tdecore

tdestartupinfo.cpp

00001 /****************************************************************************
00002 
00003  $Id$
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 tdeinit
00028 #if 0
00029 #define KSTARTUPINFO_ALL_DEBUG
00030 #warning Extra TDEStartupInfo debug messages enabled.
00031 #endif
00032 
00033 #include <tqwidget.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 <tqglobal.h>
00039 #ifdef HAVE_CONFIG_H
00040 #include <config.h>
00041 #endif
00042 
00043 // need to resolve INT32(tqglobal.h)<>INT32(Xlibint.h) conflict
00044 #ifndef QT_CLEAN_NAMESPACE
00045 #define QT_CLEAN_NAMESPACE
00046 #endif
00047 
00048 #include "tdestartupinfo.h"
00049 
00050 #include <unistd.h>
00051 #include <sys/time.h>
00052 #include <stdlib.h>
00053 #include <tqtimer.h>
00054 #ifdef Q_WS_X11
00055 #include <netwm.h>
00056 #endif
00057 #include <kdebug.h>
00058 #include <tdeapplication.h>
00059 #include <signal.h>
00060 #ifdef Q_WS_X11
00061 #include <twinmodule.h>
00062 #include <kxmessages.h>
00063 #include <twin.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 tdeinit/wrapper.c ,
00069 // tdesu in both tdelibs and tdebase 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 TQString& item_P );
00075 static unsigned long get_unum( const TQString& item_P );
00076 static TQString get_str( const TQString& item_P );
00077 static TQCString get_cstr( const TQString& item_P );
00078 static TQStringList get_fields( const TQString& txt_P );
00079 static TQString escape_str( const TQString& str_P );
00080 
00081 static Atom utf8_string_atom = None;
00082 
00083 class TDEStartupInfo::Data
00084     : public TDEStartupInfoData
00085     {
00086     public:
00087         Data() : TDEStartupInfoData(), age(0) {} // just because it's in a QMap
00088         Data( const TQString& txt_P )
00089             : TDEStartupInfoData( txt_P ), age( 0 ) {}
00090         unsigned int age;
00091     };
00092 
00093 struct TDEStartupInfoPrivate
00094     {
00095     public:
00096         TQMap< TDEStartupInfoId, TDEStartupInfo::Data > startups;
00097     // contains silenced ASN's only if !AnnounceSilencedChanges
00098         TQMap< TDEStartupInfoId, TDEStartupInfo::Data > silent_startups;
00099         // contains ASN's that had change: but no new: yet
00100         TQMap< TDEStartupInfoId, TDEStartupInfo::Data > uninited_startups;
00101 #ifdef Q_WS_X11
00102         KWinModule* wm_module;
00103         KXMessages msgs;
00104 #endif
00105     TQTimer* cleanup;
00106     int flags;
00107     TDEStartupInfoPrivate( 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 TDEStartupInfo::TDEStartupInfo( int flags_P, TQObject* parent_P, const char* name_P )
00116     : TQObject( parent_P, name_P ),
00117         timeout( 60 ), d( NULL )
00118     {
00119     init( flags_P );
00120     }
00121 
00122 TDEStartupInfo::TDEStartupInfo( bool clean_on_cantdetect_P, TQObject* parent_P, const char* name_P )
00123     : TQObject( parent_P, name_P ),
00124         timeout( 60 ), d( NULL )
00125     {
00126     init( clean_on_cantdetect_P ? CleanOnCantDetect : 0 );
00127     }
00128 
00129 void TDEStartupInfo::init( int flags_P )
00130     {
00131     // d == NULL means "disabled"
00132     if( !TDEApplication::kApplication())
00133         return;
00134     if( !TDEApplication::kApplication()->getDisplay())
00135         return;
00136 
00137     d = new TDEStartupInfoPrivate( 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, TQT_SIGNAL( windowAdded( WId )), TQT_SLOT( slot_window_added( WId )));
00143         connect( d->wm_module, TQT_SIGNAL( systemTrayWindowAdded( WId )), TQT_SLOT( slot_window_added( WId )));
00144         }
00145     else
00146         d->wm_module = NULL;
00147     connect( &d->msgs, TQT_SIGNAL( gotMessage( const TQString& )), TQT_SLOT( got_message( const TQString& )));
00148 #endif
00149     d->cleanup = new TQTimer( this, "cleanup" );
00150     connect( d->cleanup, TQT_SIGNAL( timeout()), TQT_SLOT( startups_cleanup()));
00151     }
00152 
00153 TDEStartupInfo::~TDEStartupInfo()
00154     {
00155     delete d;
00156     }
00157 
00158 void TDEStartupInfo::got_message( const TQString& msg_P )
00159     {
00160 // TODO do something with SCREEN= ?
00161     kdDebug( 172 ) << "[tdecore-tdestartupinfo] got:" << msg_P << endl;
00162     TQString 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 TDEApplication)
00175 // simply delay info from KWinModule a bit
00176 // SELI???
00177 namespace
00178 {
00179 class DelayedWindowEvent
00180     : public TQCustomEvent
00181     {
00182     public:
00183     DelayedWindowEvent( WId w_P )
00184         : TQCustomEvent( TQEvent::User + 15 ), w( w_P ) {}
00185     Window w;
00186     };
00187 }
00188 
00189 void TDEStartupInfo::slot_window_added( WId w_P )
00190     {
00191     kapp->postEvent( this, new DelayedWindowEvent( w_P ));
00192     }
00193 
00194 void TDEStartupInfo::customEvent( TQCustomEvent* e_P )
00195     {
00196     if( e_P->type() == TQEvent::User + 15 )
00197     window_added( static_cast< DelayedWindowEvent* >( e_P )->w );
00198     else
00199     TQObject::customEvent( e_P );
00200     }
00201 
00202 void TDEStartupInfo::window_added( WId w_P )
00203     {
00204     TDEStartupInfoId id;
00205     TDEStartupInfoData data;
00206     startup_t ret = check_startup_internal( w_P, &id, &data );
00207     switch( ret )
00208         {
00209         case Match:
00210             kdDebug( 172 ) << "[tdecore-tdestartupinfo] 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 TDEStartupInfo::got_startup_info( const TQString& msg_P, bool update_P )
00222     {
00223     TDEStartupInfoId id( msg_P );
00224     if( id.none())
00225         return;
00226     TDEStartupInfo::Data data( msg_P );
00227     new_startup_info_internal( id, data, update_P );
00228     }
00229 
00230 void TDEStartupInfo::new_startup_info_internal( const TDEStartupInfoId& 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 ) << "[tdecore-tdestartupinfo] 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 ) << "[tdecore-tdestartupinfo] 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 ) << "[tdecore-tdestartupinfo] 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 ) << "[tdecore-tdestartupinfo] 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 ) << "[tdecore-tdestartupinfo] 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 ) << "[tdecore-tdestartupinfo] adding silent" << endl;
00296     d->silent_startups.insert( id_P, data_P );
00297     }
00298     d->cleanup->start( 1000 ); // 1 sec
00299     }
00300 
00301 void TDEStartupInfo::got_remove_startup_info( const TQString& msg_P )
00302     {
00303     TDEStartupInfoId id( msg_P );
00304     TDEStartupInfoData 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 TDEStartupInfo::remove_startup_info_internal( const TDEStartupInfoId& id_P )
00317     {
00318     if( d == NULL )
00319         return;
00320     if( d->startups.contains( id_P ))
00321         {
00322     kdDebug( 172 ) << "[tdecore-tdestartupinfo] 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 ) << "[tdecore-tdestartupinfo] removing silent" << endl;
00329     d->silent_startups.remove( id_P );
00330     }
00331     else if( d->uninited_startups.contains( id_P ))
00332     {
00333     kdDebug( 172 ) << "[tdecore-tdestartupinfo] removing uninited" << endl;
00334     d->uninited_startups.remove( id_P );
00335     }
00336     return;
00337     }
00338 
00339 void TDEStartupInfo::remove_startup_pids( const TDEStartupInfoData& data_P )
00340     { // first find the matching info
00341     if( d == NULL )
00342         return;
00343     for( TQMap< TDEStartupInfoId, 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 TDEStartupInfo::remove_startup_pids( const TDEStartupInfoId& id_P,
00357     const TDEStartupInfoData& 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( TQValueList< 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 TDEStartupInfo::sendStartup( const TDEStartupInfoId& id_P, const TDEStartupInfoData& data_P )
00380     {
00381     if( id_P.none())
00382         return false;
00383     KXMessages msgs;
00384     TQString msg = TQString::fromLatin1( "new: %1 %2" )
00385         .arg( id_P.to_text()).arg( data_P.to_text());
00386     msg = check_required_startup_fields( msg, data_P, tqt_xscreen());
00387     kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
00388     msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
00389     return true;
00390     }
00391 
00392 bool TDEStartupInfo::sendStartupX( Display* disp_P, const TDEStartupInfoId& id_P,
00393     const TDEStartupInfoData& data_P )
00394     {
00395     if( id_P.none())
00396         return false;
00397     TQString msg = TQString::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 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
00402 #endif
00403     return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
00404     }
00405 
00406 TQString TDEStartupInfo::check_required_startup_fields( const TQString& msg, const TDEStartupInfoData& data_P,
00407     int screen )
00408     {
00409     TQString ret = msg;
00410     if( data_P.name().isEmpty())
00411         {
00412 //        kdWarning( 172 ) << "[tdecore-tdestartupinfo] NAME not specified in initial startup message" << endl;
00413         TQString name = data_P.bin();
00414         if( name.isEmpty())
00415             name = "UNKNOWN";
00416         ret += TQString( " NAME=\"%1\"" ).arg( escape_str( name ));
00417         }
00418     if( data_P.screen() == -1 ) // add automatically if needed
00419         ret += TQString( " SCREEN=%1" ).arg( screen );
00420     return ret;
00421     }
00422 
00423 bool TDEStartupInfo::sendChange( const TDEStartupInfoId& id_P, const TDEStartupInfoData& data_P )
00424     {
00425     if( id_P.none())
00426         return false;
00427     KXMessages msgs;
00428     TQString msg = TQString::fromLatin1( "change: %1 %2" )
00429         .arg( id_P.to_text()).arg( data_P.to_text());
00430     kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
00431     msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
00432     return true;
00433     }
00434 
00435 bool TDEStartupInfo::sendChangeX( Display* disp_P, const TDEStartupInfoId& id_P,
00436     const TDEStartupInfoData& data_P )
00437     {
00438     if( id_P.none())
00439         return false;
00440     TQString msg = TQString::fromLatin1( "change: %1 %2" )
00441         .arg( id_P.to_text()).arg( data_P.to_text());
00442 #ifdef KSTARTUPINFO_ALL_DEBUG
00443     kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
00444 #endif
00445     return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
00446     }
00447 
00448 bool TDEStartupInfo::sendFinish( const TDEStartupInfoId& id_P )
00449     {
00450     if( id_P.none())
00451         return false;
00452     KXMessages msgs;
00453     TQString msg = TQString::fromLatin1( "remove: %1" ).arg( id_P.to_text());
00454     kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
00455     msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
00456     return true;
00457     }
00458 
00459 bool TDEStartupInfo::sendFinishX( Display* disp_P, const TDEStartupInfoId& id_P )
00460     {
00461     if( id_P.none())
00462         return false;
00463     TQString msg = TQString::fromLatin1( "remove: %1" ).arg( id_P.to_text());
00464 #ifdef KSTARTUPINFO_ALL_DEBUG
00465     kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
00466 #endif
00467     return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
00468     }
00469 
00470 bool TDEStartupInfo::sendFinish( const TDEStartupInfoId& id_P, const TDEStartupInfoData& 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     TQString msg = TQString::fromLatin1( "remove: %1 %2" )
00476         .arg( id_P.to_text()).arg( data_P.to_text());
00477     kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
00478     msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
00479     return true;
00480     }
00481 
00482 bool TDEStartupInfo::sendFinishX( Display* disp_P, const TDEStartupInfoId& id_P,
00483     const TDEStartupInfoData& data_P )
00484     {
00485 //    if( id_P.none()) // id may be none, the pids and hostname matter then
00486 //        return false;
00487     TQString msg = TQString::fromLatin1( "remove: %1 %2" )
00488         .arg( id_P.to_text()).arg( data_P.to_text());
00489 #ifdef KSTARTUPINFO_ALL_DEBUG
00490     kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
00491 #endif
00492     return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
00493     }
00494 
00495 void TDEStartupInfo::appStarted()
00496     {
00497     if( kapp != NULL )  // TDEApplication constructor unsets the env. variable
00498         appStarted( kapp->startupId());
00499     else
00500         appStarted( TDEStartupInfo::currentStartupIdEnv().id());
00501     }
00502 
00503 void TDEStartupInfo::appStarted( const TQCString& startup_id )
00504     {
00505     TDEStartupInfoId id;
00506     id.initId( startup_id );
00507     if( id.none())
00508         return;
00509     if( kapp != NULL )
00510         TDEStartupInfo::sendFinish( id );
00511     else if( getenv( "DISPLAY" ) != NULL ) // don't rely on tqt_xdisplay()
00512         {
00513 #ifdef Q_WS_X11
00514         Display* disp = XOpenDisplay( NULL );
00515         if( disp != NULL )
00516             {
00517             TDEStartupInfo::sendFinishX( disp, id );
00518             XCloseDisplay( disp );
00519             }
00520 #endif
00521         }
00522     }
00523 
00524 void TDEStartupInfo::disableAutoAppStartedSending( bool disable )
00525     {
00526     auto_app_started_sending = !disable;
00527     }
00528 
00529 void TDEStartupInfo::silenceStartup( bool silence )
00530     {
00531     TDEStartupInfoId id;
00532     id.initId( kapp->startupId());
00533     if( id.none())
00534         return;
00535     TDEStartupInfoData data;
00536     data.setSilent( silence ? TDEStartupInfoData::Yes : TDEStartupInfoData::No );
00537     sendChange( id, data );
00538     }
00539 
00540 void TDEStartupInfo::handleAutoAppStartedSending()
00541     {
00542     if( auto_app_started_sending )
00543         appStarted();
00544     }
00545 
00546 void TDEStartupInfo::setNewStartupId( TQWidget* window, const TQCString& 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( tqt_xdisplay(), NET::Supported );
00555             if( i.isSupported( NET::WM2StartupId ))
00556                 {
00557                 TDEStartupInfo::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     TDEStartupInfo::handleAutoAppStartedSending();
00572     }
00573 
00574 TDEStartupInfo::startup_t TDEStartupInfo::checkStartup( WId w_P, TDEStartupInfoId& id_O,
00575     TDEStartupInfoData& data_O )
00576     {
00577     return check_startup_internal( w_P, &id_O, &data_O );
00578     }
00579 
00580 TDEStartupInfo::startup_t TDEStartupInfo::checkStartup( WId w_P, TDEStartupInfoId& id_O )
00581     {
00582     return check_startup_internal( w_P, &id_O, NULL );
00583     }
00584 
00585 TDEStartupInfo::startup_t TDEStartupInfo::checkStartup( WId w_P, TDEStartupInfoData& data_O )
00586     {
00587     return check_startup_internal( w_P, NULL, &data_O );
00588     }
00589 
00590 TDEStartupInfo::startup_t TDEStartupInfo::checkStartup( WId w_P )
00591     {
00592     return check_startup_internal( w_P, NULL, NULL );
00593     }
00594 
00595 TDEStartupInfo::startup_t TDEStartupInfo::check_startup_internal( WId w_P, TDEStartupInfoId* id_O,
00596     TDEStartupInfoData* 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 ) << "[tdecore-tdestartupinfo] check_startup" << endl;
00610     TQCString id = windowStartupId( w_P );
00611     if( !id.isNull())
00612         {
00613         if( id.isEmpty() || id == "0" ) // means ignore this window
00614             {
00615             kdDebug( 172 ) << "[tdecore-tdestartupinfo] 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( tqt_xdisplay(),  w_P, tqt_xrootwin(),
00622         NET::WMWindowType | NET::WMPid | NET::WMState );
00623     pid_t pid = info.pid();
00624     if( pid > 0 )
00625         {
00626         TQCString 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( tqt_xdisplay(), w_P, &hint ) != 0 )
00634         { // We managed to read the class hint
00635         TQCString res_name = hint.res_name;
00636         TQCString 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( tqt_xdisplay(), static_cast< Window >( w_P ), &transient_for )
00656         && static_cast< WId >( transient_for ) != tqt_xrootwin()
00657         && transient_for != None )
00658     return NoMatch;
00659 #endif
00660     kdDebug( 172 ) << "[tdecore-tdestartupinfo] check_startup:cantdetect" << endl;
00661     return CantDetect;
00662     }
00663 
00664 bool TDEStartupInfo::find_id( const TQCString& id_P, TDEStartupInfoId* id_O,
00665     TDEStartupInfoData* data_O )
00666     {
00667     if( d == NULL )
00668         return false;
00669     kdDebug( 172 ) << "[tdecore-tdestartupinfo] find_id:" << id_P << endl;
00670     TDEStartupInfoId 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 ) << "[tdecore-tdestartupinfo] check_startup_id:match" << endl;
00679         return true;
00680         }
00681     return false;
00682     }
00683 
00684 bool TDEStartupInfo::find_pid( pid_t pid_P, const TQCString& hostname_P,
00685     TDEStartupInfoId* id_O, TDEStartupInfoData* data_O )
00686     {
00687     if( d == NULL )
00688         return false;
00689     kdDebug( 172 ) << "[tdecore-tdestartupinfo] find_pid:" << pid_P << endl;
00690     for( TQMap< TDEStartupInfoId, 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 ) << "[tdecore-tdestartupinfo] check_startup_pid:match" << endl;
00703             return true;
00704             }
00705         }
00706     return false;
00707     }
00708 
00709 bool TDEStartupInfo::find_wclass( TQCString res_name, TQCString res_class,
00710     TDEStartupInfoId* id_O, TDEStartupInfoData* 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 ) << "[tdecore-tdestartupinfo] find_wclass:" << res_name << ":" << res_class << endl;
00717     for( TQMap< TDEStartupInfoId, Data >::Iterator it = d->startups.begin();
00718          it != d->startups.end();
00719          ++it )
00720         {
00721         const TQCString 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 ) << "[tdecore-tdestartupinfo] 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 TQCString read_startup_id_property( WId w_P )
00741     {
00742     TQCString 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( tqt_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 TQCString TDEStartupInfo::windowStartupId( WId w_P )
00762     {
00763 #ifdef Q_WS_X11
00764     if( net_startup_atom == None )
00765         net_startup_atom = XInternAtom( tqt_xdisplay(), NET_STARTUP_WINDOW, False );
00766     if( utf8_string_atom == None )
00767         utf8_string_atom = XInternAtom( tqt_xdisplay(), "UTF8_STRING", False );
00768     TQCString 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( tqt_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 TQCString();
00780 #endif
00781     }
00782 
00783 void TDEStartupInfo::setWindowStartupId( WId w_P, const TQCString& 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( tqt_xdisplay(), NET_STARTUP_WINDOW, False );
00790     if( utf8_string_atom == None )
00791         utf8_string_atom = XInternAtom( tqt_xdisplay(), "UTF8_STRING", False );
00792     XChangeProperty( tqt_xdisplay(), w_P, net_startup_atom, utf8_string_atom, 8,
00793         PropModeReplace, reinterpret_cast< unsigned char* >( const_cast<TQCString&>(id_P).data()), id_P.length());
00794 #endif
00795     }
00796 
00797 TQCString TDEStartupInfo::get_window_hostname( WId w_P )
00798     {
00799 #ifdef Q_WS_X11
00800     XTextProperty tp;
00801     char** hh;
00802     int cnt;
00803     if( XGetWMClientMachine( tqt_xdisplay(), w_P, &tp ) != 0
00804         && XTextPropertyToStringList( &tp, &hh, &cnt ) != 0 )
00805         {
00806         if( cnt == 1 )
00807             {
00808             TQCString hostname = hh[ 0 ];
00809             XFreeStringList( hh );
00810             return hostname;
00811             }
00812         XFreeStringList( hh );
00813         }
00814 #endif
00815     // no hostname
00816     return TQCString();
00817     }
00818 
00819 void TDEStartupInfo::setTimeout( unsigned int secs_P )
00820     {
00821     timeout = secs_P;
00822  // schedule removing entries that are older than the new timeout
00823     TQTimer::singleShot( 0, this, TQT_SLOT( startups_cleanup_no_age()));
00824     }
00825 
00826 void TDEStartupInfo::startups_cleanup_no_age()
00827     {
00828     startups_cleanup_internal( false );
00829     }
00830 
00831 void TDEStartupInfo::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 TDEStartupInfo::startups_cleanup_internal( bool age_P )
00845     {
00846     if( d == NULL )
00847         return;
00848     for( TQMap< TDEStartupInfoId, 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 TDEStartupInfoId& key = it.key();
00860             ++it;
00861             kdDebug( 172 ) << "[tdecore-tdestartupinfo] startups entry timeout:" << key.id() << endl;
00862             remove_startup_info_internal( key );
00863             }
00864         else
00865             ++it;
00866         }
00867     for( TQMap< TDEStartupInfoId, 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 TDEStartupInfoId& key = it.key();
00879             ++it;
00880             kdDebug( 172 ) << "[tdecore-tdestartupinfo] silent entry timeout:" << key.id() << endl;
00881             remove_startup_info_internal( key );
00882             }
00883         else
00884             ++it;
00885         }
00886     for( TQMap< TDEStartupInfoId, 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 TDEStartupInfoId& key = it.key();
00898             ++it;
00899             kdDebug( 172 ) << "[tdecore-tdestartupinfo] uninited entry timeout:" << key.id() << endl;
00900             remove_startup_info_internal( key );
00901             }
00902         else
00903             ++it;
00904         }
00905     }
00906 
00907 void TDEStartupInfo::clean_all_noncompliant()
00908     {
00909     if( d == NULL )
00910         return;
00911     for( TQMap< TDEStartupInfoId, 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 TDEStartupInfoId& key = it.key();
00921         ++it;
00922         kdDebug( 172 ) << "[tdecore-tdestartupinfo] entry cleaning:" << key.id() << endl;
00923         remove_startup_info_internal( key );
00924         }
00925     }
00926 
00927 TQCString TDEStartupInfo::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     TQCString id = TQString(TQString( "%1;%2;%3;%4_TIME%5" ).arg( hostname ).arg( tm.tv_sec )
00938         .arg( tm.tv_usec ).arg( getpid()).arg( GET_QT_X_USER_TIME() )).utf8();
00939     kdDebug( 172 ) << "[tdecore-tdestartupinfo] creating: " << id << ":" << tqAppName() << endl;
00940     return id;
00941     }
00942 
00943 
00944 struct TDEStartupInfoIdPrivate
00945     {
00946     TDEStartupInfoIdPrivate() : id( "" ) {}
00947     TQCString id; // id
00948     };
00949 
00950 const TQCString& TDEStartupInfoId::id() const
00951     {
00952     return d->id;
00953     }
00954 
00955 
00956 TQString TDEStartupInfoId::to_text() const
00957     {
00958     return TQString::fromLatin1( " ID=\"%1\" " ).arg( escape_str( id()));
00959     }
00960 
00961 TDEStartupInfoId::TDEStartupInfoId( const TQString& txt_P )
00962     {
00963     d = new TDEStartupInfoIdPrivate;
00964     TQStringList items = get_fields( txt_P );
00965     const TQString id_str = TQString::fromLatin1( "ID=" );
00966     for( TQStringList::Iterator it = items.begin();
00967          it != items.end();
00968          ++it )
00969         {
00970         if( ( *it ).startsWith( id_str ))
00971             d->id = get_cstr( *it );
00972         }
00973     }
00974 
00975 void TDEStartupInfoId::initId( const TQCString& id_P )
00976     {
00977     if( !id_P.isEmpty())
00978         {
00979         d->id = id_P;
00980 #ifdef KSTARTUPINFO_ALL_DEBUG
00981         kdDebug( 172 ) << "[tdecore-tdestartupinfo] using: " << d->id << endl;
00982 #endif
00983         return;
00984         }
00985     const char* startup_env = getenv( NET_STARTUP_ENV );
00986     if( startup_env != NULL && *startup_env != '\0' )
00987         { // already has id
00988         d->id = startup_env;
00989 #ifdef KSTARTUPINFO_ALL_DEBUG
00990         kdDebug( 172 ) << "[tdecore-tdestartupinfo] reusing: " << d->id << endl;
00991 #endif
00992         return;
00993         }
00994     d->id = TDEStartupInfo::createNewStartupId();
00995     }
00996 
00997 bool TDEStartupInfoId::setupStartupEnv() const
00998     {
00999     if( id().isEmpty())
01000         {
01001         unsetenv( NET_STARTUP_ENV );
01002         return false;
01003         }
01004     return setenv( NET_STARTUP_ENV, id(), true ) == 0;
01005     }
01006 
01007 TDEStartupInfoId TDEStartupInfo::currentStartupIdEnv()
01008     {
01009     const char* startup_env = getenv( NET_STARTUP_ENV );
01010     TDEStartupInfoId id;
01011     if( startup_env != NULL && *startup_env != '\0' )
01012         id.d->id = startup_env;
01013     else
01014         id.d->id = "0";
01015     return id;
01016     }
01017 
01018 void TDEStartupInfo::resetStartupEnv()
01019     {
01020     unsetenv( NET_STARTUP_ENV );
01021     }
01022 
01023 TDEStartupInfoId::TDEStartupInfoId()
01024     {
01025     d = new TDEStartupInfoIdPrivate;
01026     }
01027 
01028 TDEStartupInfoId::~TDEStartupInfoId()
01029     {
01030     delete d;
01031     }
01032 
01033 TDEStartupInfoId::TDEStartupInfoId( const TDEStartupInfoId& id_P )
01034     {
01035     d = new TDEStartupInfoIdPrivate( *id_P.d );
01036     }
01037 
01038 TDEStartupInfoId& TDEStartupInfoId::operator=( const TDEStartupInfoId& id_P )
01039     {
01040     if( &id_P == this )
01041         return *this;
01042     delete d;
01043     d = new TDEStartupInfoIdPrivate( *id_P.d );
01044     return *this;
01045     }
01046 
01047 bool TDEStartupInfoId::operator==( const TDEStartupInfoId& id_P ) const
01048     {
01049     return id() == id_P.id();
01050     }
01051 
01052 bool TDEStartupInfoId::operator!=( const TDEStartupInfoId& id_P ) const
01053     {
01054     return !(*this == id_P );
01055     }
01056 
01057 // needed for QMap
01058 bool TDEStartupInfoId::operator<( const TDEStartupInfoId& id_P ) const
01059     {
01060     return id() < id_P.id();
01061     }
01062 
01063 bool TDEStartupInfoId::none() const
01064     {
01065     return d->id.isEmpty() || d->id == "0";
01066     }
01067 
01068 unsigned long TDEStartupInfoId::timestamp() const
01069     {
01070     if( none())
01071         return 0;
01072     int pos = d->id.findRev( "_TIME" );
01073     if( pos >= 0 )
01074         {
01075         bool ok;
01076         unsigned long time = d->id.mid( pos + 5 ).toULong( &ok );
01077         if( !ok && d->id[ pos + 5 ] == '-' ) // try if it's as a negative signed number perhaps
01078             time = d->id.mid( pos + 5 ).toLong( &ok );
01079         if( ok )
01080             return time;
01081         }
01082     // libstartup-notification style :
01083     // snprintf (s, len, "%s/%s/%lu/%d-%d-%s",
01084     //   canonicalized_launcher, canonicalized_launchee, (unsigned long) timestamp,
01085     //  (int) getpid (), (int) sequence_number, hostbuf);
01086     int pos1 = d->id.findRev( '/' );
01087     if( pos1 > 0 )
01088         {
01089         int pos2 = d->id.findRev( '/', pos1 - 1 );
01090         if( pos2 >= 0 )
01091             {
01092             bool ok;
01093             unsigned long time = d->id.mid( pos2 + 1, pos1 - pos2 - 1 ).toULong( &ok );
01094             if( !ok && d->id[ pos2 + 1 ] == '-' ) // try if it's as a negative signed number perhaps
01095                 time = d->id.mid( pos2 + 1, pos1 - pos2 - 1 ).toLong( &ok );
01096             if( ok )
01097                 return time;
01098             }
01099         }
01100     // bah ... old TDEStartupInfo or a problem
01101     return 0;
01102     }
01103 
01104 struct TDEStartupInfoDataPrivate
01105     {
01106     TDEStartupInfoDataPrivate() : desktop( 0 ), wmclass( "" ), hostname( "" ),
01107     silent( TDEStartupInfoData::Unknown ), timestamp( -1U ), screen( -1 ), xinerama( -1 ), launched_by( 0 ) {}
01108     TQString bin;
01109     TQString name;
01110     TQString description;
01111     TQString icon;
01112     int desktop;
01113     TQValueList< pid_t > pids;
01114     TQCString wmclass;
01115     TQCString hostname;
01116     TDEStartupInfoData::TriState silent;
01117     unsigned long timestamp;
01118     int screen;
01119     int xinerama;
01120     WId launched_by;
01121     };
01122 
01123 TQString TDEStartupInfoData::to_text() const
01124     {
01125     TQString ret = "";
01126     if( !d->bin.isEmpty())
01127         ret += TQString::fromLatin1( " BIN=\"%1\"" ).arg( escape_str( d->bin ));
01128     if( !d->name.isEmpty())
01129         ret += TQString::fromLatin1( " NAME=\"%1\"" ).arg( escape_str( d->name ));
01130     if( !d->description.isEmpty())
01131         ret += TQString::fromLatin1( " DESCRIPTION=\"%1\"" ).arg( escape_str( d->description ));
01132     if( !d->icon.isEmpty())
01133         ret += TQString::fromLatin1( " ICON=%1" ).arg( d->icon );
01134     if( d->desktop != 0 )
01135         ret += TQString::fromLatin1( " DESKTOP=%1" )
01136             .arg( d->desktop == NET::OnAllDesktops ? NET::OnAllDesktops : d->desktop - 1 ); // spec counts from 0
01137     if( !d->wmclass.isEmpty())
01138         ret += TQString::fromLatin1( " WMCLASS=\"%1\"" ).arg( QString(d->wmclass) );
01139     if( !d->hostname.isEmpty())
01140         ret += TQString::fromLatin1( " HOSTNAME=%1" ).arg( QString(d->hostname) );
01141     for( TQValueList< pid_t >::ConstIterator it = d->pids.begin();
01142          it != d->pids.end();
01143          ++it )
01144         ret += TQString::fromLatin1( " PID=%1" ).arg( *it );
01145     if( d->silent != Unknown )
01146     ret += TQString::fromLatin1( " SILENT=%1" ).arg( d->silent == Yes ? 1 : 0 );
01147     if( d->timestamp != -1U )
01148         ret += TQString::fromLatin1( " TIMESTAMP=%1" ).arg( d->timestamp );
01149     if( d->screen != -1 )
01150         ret += TQString::fromLatin1( " SCREEN=%1" ).arg( d->screen );
01151     if( d->xinerama != -1 )
01152         ret += TQString::fromLatin1( " XINERAMA=%1" ).arg( d->xinerama );
01153     if( d->launched_by != 0 )
01154         ret += TQString::fromLatin1( " LAUNCHED_BY=%1" ).arg( d->launched_by );
01155     return ret;
01156     }
01157 
01158 TDEStartupInfoData::TDEStartupInfoData( const TQString& txt_P )
01159     {
01160     d = new TDEStartupInfoDataPrivate;
01161     TQStringList items = get_fields( txt_P );
01162     const TQString bin_str = TQString::fromLatin1( "BIN=" );
01163     const TQString name_str = TQString::fromLatin1( "NAME=" );
01164     const TQString description_str = TQString::fromLatin1( "DESCRIPTION=" );
01165     const TQString icon_str = TQString::fromLatin1( "ICON=" );
01166     const TQString desktop_str = TQString::fromLatin1( "DESKTOP=" );
01167     const TQString wmclass_str = TQString::fromLatin1( "WMCLASS=" );
01168     const TQString hostname_str = TQString::fromLatin1( "HOSTNAME=" ); // SELI nonstd
01169     const TQString pid_str = TQString::fromLatin1( "PID=" );  // SELI nonstd
01170     const TQString silent_str = TQString::fromLatin1( "SILENT=" );
01171     const TQString timestamp_str = TQString::fromLatin1( "TIMESTAMP=" );
01172     const TQString screen_str = TQString::fromLatin1( "SCREEN=" );
01173     const TQString xinerama_str = TQString::fromLatin1( "XINERAMA=" );
01174     const TQString launched_by_str = TQString::fromLatin1( "LAUNCHED_BY=" );
01175     for( TQStringList::Iterator it = items.begin();
01176          it != items.end();
01177          ++it )
01178         {
01179         if( ( *it ).startsWith( bin_str ))
01180             d->bin = get_str( *it );
01181         else if( ( *it ).startsWith( name_str ))
01182             d->name = get_str( *it );
01183         else if( ( *it ).startsWith( description_str ))
01184             d->description = get_str( *it );
01185         else if( ( *it ).startsWith( icon_str ))
01186             d->icon = get_str( *it );
01187         else if( ( *it ).startsWith( desktop_str ))
01188             {
01189             d->desktop = get_num( *it );
01190             if( d->desktop != NET::OnAllDesktops )
01191                 ++d->desktop; // spec counts from 0
01192             }
01193         else if( ( *it ).startsWith( wmclass_str ))
01194             d->wmclass = get_cstr( *it );
01195         else if( ( *it ).startsWith( hostname_str ))
01196             d->hostname = get_cstr( *it );
01197         else if( ( *it ).startsWith( pid_str ))
01198             addPid( get_num( *it ));
01199         else if( ( *it ).startsWith( silent_str ))
01200             d->silent = get_num( *it ) != 0 ? Yes : No;
01201         else if( ( *it ).startsWith( timestamp_str ))
01202             d->timestamp = get_unum( *it );
01203         else if( ( *it ).startsWith( screen_str ))
01204             d->screen = get_num( *it );
01205         else if( ( *it ).startsWith( xinerama_str ))
01206             d->xinerama = get_num( *it );
01207         else if( ( *it ).startsWith( launched_by_str ))
01208             d->launched_by = get_num( *it );
01209         }
01210     }
01211 
01212 TDEStartupInfoData::TDEStartupInfoData( const TDEStartupInfoData& data )
01213 {
01214     d = new TDEStartupInfoDataPrivate( *data.d );
01215 }
01216 
01217 TDEStartupInfoData& TDEStartupInfoData::operator=( const TDEStartupInfoData& data )
01218 {
01219     if( &data == this )
01220         return *this;
01221     delete d;
01222     d = new TDEStartupInfoDataPrivate( *data.d );
01223     return *this;
01224 }
01225 
01226 void TDEStartupInfoData::update( const TDEStartupInfoData& data_P )
01227     {
01228     if( !data_P.bin().isEmpty())
01229         d->bin = data_P.bin();
01230     if( !data_P.name().isEmpty() && name().isEmpty()) // don't overwrite
01231         d->name = data_P.name();
01232     if( !data_P.description().isEmpty() && description().isEmpty()) // don't overwrite
01233         d->description = data_P.description();
01234     if( !data_P.icon().isEmpty() && icon().isEmpty()) // don't overwrite
01235         d->icon = data_P.icon();
01236     if( data_P.desktop() != 0 && desktop() == 0 ) // don't overwrite
01237         d->desktop = data_P.desktop();
01238     if( !data_P.d->wmclass.isEmpty())
01239         d->wmclass = data_P.d->wmclass;
01240     if( !data_P.d->hostname.isEmpty())
01241         d->hostname = data_P.d->hostname;
01242     for( TQValueList< pid_t >::ConstIterator it = data_P.d->pids.begin();
01243          it != data_P.d->pids.end();
01244          ++it )
01245         addPid( *it );
01246     if( data_P.silent() != Unknown )
01247     d->silent = data_P.silent();
01248     if( data_P.timestamp() != -1U && timestamp() == -1U ) // don't overwrite
01249         d->timestamp = data_P.timestamp();
01250     if( data_P.screen() != -1 )
01251         d->screen = data_P.screen();
01252     if( data_P.xinerama() != -1 && xinerama() != -1 ) // don't overwrite
01253         d->xinerama = data_P.xinerama();
01254     if( data_P.launchedBy() != 0 && launchedBy() != 0 ) // don't overwrite
01255         d->launched_by = data_P.launchedBy();
01256     }
01257 
01258 TDEStartupInfoData::TDEStartupInfoData()
01259 {
01260     d = new TDEStartupInfoDataPrivate;
01261 }
01262 
01263 TDEStartupInfoData::~TDEStartupInfoData()
01264 {
01265     delete d;
01266 }
01267 
01268 void TDEStartupInfoData::setBin( const TQString& bin_P )
01269     {
01270     d->bin = bin_P;
01271     }
01272 
01273 const TQString& TDEStartupInfoData::bin() const
01274     {
01275     return d->bin;
01276     }
01277 
01278 void TDEStartupInfoData::setName( const TQString& name_P )
01279     {
01280     d->name = name_P;
01281     }
01282 
01283 const TQString& TDEStartupInfoData::name() const
01284     {
01285     return d->name;
01286     }
01287 
01288 const TQString& TDEStartupInfoData::findName() const
01289     {
01290     if( !name().isEmpty())
01291         return name();
01292     return bin();
01293     }
01294 
01295 void TDEStartupInfoData::setDescription( const TQString& desc_P )
01296     {
01297     d->description = desc_P;
01298     }
01299 
01300 const TQString& TDEStartupInfoData::description() const
01301     {
01302     return d->description;
01303     }
01304 
01305 const TQString& TDEStartupInfoData::findDescription() const
01306     {
01307     if( !description().isEmpty())
01308         return description();
01309     return name();
01310     }
01311 
01312 void TDEStartupInfoData::setIcon( const TQString& icon_P )
01313     {
01314     d->icon = icon_P;
01315     }
01316 
01317 const TQString& TDEStartupInfoData::findIcon() const
01318     {
01319     if( !icon().isEmpty())
01320         return icon();
01321     return bin();
01322     }
01323 
01324 const TQString& TDEStartupInfoData::icon() const
01325     {
01326     return d->icon;
01327     }
01328 
01329 void TDEStartupInfoData::setDesktop( int desktop_P )
01330     {
01331     d->desktop = desktop_P;
01332     }
01333 
01334 int TDEStartupInfoData::desktop() const
01335     {
01336     return d->desktop;
01337     }
01338 
01339 void TDEStartupInfoData::setWMClass( const TQCString& wmclass_P )
01340     {
01341     d->wmclass = wmclass_P;
01342     }
01343 
01344 const TQCString TDEStartupInfoData::findWMClass() const
01345     {
01346     if( !WMClass().isEmpty() && WMClass() != "0" )
01347         return WMClass();
01348     return bin().utf8();
01349     }
01350 
01351 const TQCString& TDEStartupInfoData::WMClass() const
01352     {
01353     return d->wmclass;
01354     }
01355 
01356 void TDEStartupInfoData::setHostname( const TQCString& hostname_P )
01357     {
01358     if( !hostname_P.isNull())
01359         d->hostname = hostname_P;
01360     else
01361         {
01362         char tmp[ 256 ];
01363         tmp[ 0 ] = '\0';
01364         if (!gethostname( tmp, 255 ))
01365         tmp[sizeof(tmp)-1] = '\0';
01366         d->hostname = tmp;
01367         }
01368     }
01369 
01370 const TQCString& TDEStartupInfoData::hostname() const
01371     {
01372     return d->hostname;
01373     }
01374 
01375 void TDEStartupInfoData::addPid( pid_t pid_P )
01376     {
01377     if( !d->pids.contains( pid_P ))
01378         d->pids.append( pid_P );
01379     }
01380 
01381 void TDEStartupInfoData::remove_pid( pid_t pid_P )
01382     {
01383     d->pids.remove( pid_P );
01384     }
01385 
01386 const TQValueList< pid_t >& TDEStartupInfoData::pids() const
01387     {
01388     return d->pids;
01389     }
01390 
01391 bool TDEStartupInfoData::is_pid( pid_t pid_P ) const
01392     {
01393     return d->pids.contains( pid_P );
01394     }
01395 
01396 void TDEStartupInfoData::setSilent( TriState state_P )
01397     {
01398     d->silent = state_P;
01399     }
01400 
01401 TDEStartupInfoData::TriState TDEStartupInfoData::silent() const
01402     {
01403     return d->silent;
01404     }
01405 
01406 void TDEStartupInfoData::setTimestamp( unsigned long time )
01407     {
01408     d->timestamp = time;
01409     }
01410 
01411 unsigned long TDEStartupInfoData::timestamp() const
01412     {
01413     return d->timestamp;
01414     }
01415 
01416 void TDEStartupInfoData::setScreen( int screen )
01417     {
01418     d->screen = screen;
01419     }
01420 
01421 int TDEStartupInfoData::screen() const
01422     {
01423     return d->screen;
01424     }
01425 
01426 void TDEStartupInfoData::setXinerama( int xinerama )
01427     {
01428     d->xinerama = xinerama;
01429     }
01430 
01431 int TDEStartupInfoData::xinerama() const
01432     {
01433     return d->xinerama;
01434     }
01435 
01436 void TDEStartupInfoData::setLaunchedBy( WId window )
01437     {
01438     d->launched_by = window;
01439     }
01440 
01441 WId TDEStartupInfoData::launchedBy() const
01442     {
01443     return d->launched_by;
01444     }
01445 
01446 static
01447 long get_num( const TQString& item_P )
01448     {
01449     unsigned int pos = item_P.find( '=' );
01450     return item_P.mid( pos + 1 ).toLong();
01451     }
01452 
01453 static
01454 unsigned long get_unum( const TQString& item_P )
01455     {
01456     unsigned int pos = item_P.find( '=' );
01457     return item_P.mid( pos + 1 ).toULong();
01458     }
01459 
01460 static
01461 TQString get_str( const TQString& item_P )
01462     {
01463     unsigned int pos = item_P.find( '=' );
01464     if( item_P.length() > pos + 2 && item_P[ pos + 1 ] == (QChar)'\"' )
01465         {
01466         int pos2 = item_P.left( pos + 2 ).find( '\"' );
01467         if( pos2 < 0 )
01468             return TQString::null;                      // 01234
01469         return item_P.mid( pos + 2, pos2 - 2 - pos );  // A="C"
01470         }
01471     return item_P.mid( pos + 1 );
01472     }
01473 
01474 static
01475 TQCString get_cstr( const TQString& item_P )
01476     {
01477     return get_str( item_P ).utf8();
01478     }
01479 
01480 static
01481 TQStringList get_fields( const TQString& txt_P )
01482     {
01483     TQString txt = txt_P.simplifyWhiteSpace();
01484     TQStringList ret;
01485     TQString item = "";
01486     bool in = false;
01487     bool escape = false;
01488     for( unsigned int pos = 0;
01489          pos < txt.length();
01490          ++pos )
01491         {
01492         if( escape )
01493             {
01494             item += txt[ pos ];
01495             escape = false;
01496             }
01497         else if( txt[ pos ] == '\\' )
01498             escape = true;
01499         else if( txt[ pos ] == '\"' )
01500             in = !in;
01501         else if( txt[ pos ] == ' ' && !in )
01502             {
01503             ret.append( item );
01504             item = "";
01505             }
01506         else
01507             item += txt[ pos ];
01508         }
01509     ret.append( item );
01510     return ret;
01511     }
01512 
01513 static TQString escape_str( const TQString& str_P )
01514     {
01515     TQString ret = "";
01516     for( unsigned int pos = 0;
01517      pos < str_P.length();
01518      ++pos )
01519     {
01520     if( str_P[ pos ] == (QChar)'\\'
01521         || str_P[ pos ] == (QChar)'"' )
01522         ret += '\\';
01523     ret += str_P[ pos ];
01524     }
01525     return ret;
01526     }
01527 
01528 #include "tdestartupinfo.moc"
01529 #endif

tdecore

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

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.7.1
This website is maintained by Timothy Pearson.