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