00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "config.h"
00020
00021 #include <config.h>
00022 #include <tqclipboard.h>
00023 #include <tqfile.h>
00024 #include <tqdir.h>
00025 #include <tqtimer.h>
00026 #include <tqobjectdict.h>
00027
00028 #include "tdeapplication.h"
00029 #include "klibloader.h"
00030 #include "kstandarddirs.h"
00031 #include "kdebug.h"
00032 #include "tdelocale.h"
00033
00034 #include "ltdl.h"
00035
00036 LT_SCOPE int lt_dlopen_flag;
00037
00038 template class TQAsciiDict<KLibrary>;
00039
00040 #include <stdlib.h>
00041
00042
00043 #if HAVE_DLFCN_H
00044 # include <dlfcn.h>
00045 #endif
00046
00047 #ifdef RTLD_GLOBAL
00048 # define LT_GLOBAL RTLD_GLOBAL
00049 #else
00050 # ifdef DL_GLOBAL
00051 # define LT_GLOBAL DL_GLOBAL
00052 # endif
00053 #endif
00054 #ifndef LT_GLOBAL
00055 # define LT_GLOBAL 0
00056 #endif
00057
00058
00059 class KLibLoaderPrivate
00060 {
00061 public:
00062 TQPtrList<KLibWrapPrivate> loaded_stack;
00063 TQPtrList<KLibWrapPrivate> pending_close;
00064 enum {UNKNOWN, UNLOAD, DONT_UNLOAD} unload_mode;
00065
00066 TQString errorMessage;
00067 };
00068
00069 KLibLoader* KLibLoader::s_self = 0;
00070
00071
00072
00073 KLibFactory::KLibFactory( TQObject* parent, const char* name )
00074 : TQObject( parent, name )
00075 {
00076 }
00077
00078 KLibFactory::~KLibFactory()
00079 {
00080
00081 }
00082
00083 TQObject* KLibFactory::create( TQObject* parent, const char* name, const char* classname, const TQStringList &args )
00084 {
00085 TQObject* obj = createObject( parent, name, classname, args );
00086 if ( obj )
00087 emit objectCreated( obj );
00088 return obj;
00089 }
00090
00091
00092 TQObject* KLibFactory::createObject( TQObject*, const char*, const char*, const TQStringList &)
00093 {
00094 return 0;
00095 }
00096
00097
00098
00099
00100 KLibrary::KLibrary( const TQString& libname, const TQString& filename, void * handle )
00101 {
00102
00103 (void) KLibLoader::self();
00104 m_libname = libname;
00105 m_filename = filename;
00106 m_handle = handle;
00107 m_factory = 0;
00108 m_timer = 0;
00109 }
00110
00111 KLibrary::~KLibrary()
00112 {
00113
00114 if ( m_timer && m_timer->isActive() )
00115 m_timer->stop();
00116
00117
00118 if ( m_objs.count() > 0 )
00119 {
00120 TQPtrListIterator<TQObject> it( m_objs );
00121 for ( ; it.current() ; ++it )
00122 {
00123 kdDebug(150) << "Factory still has object " << it.current() << " " << it.current()->name () << " Library = " << m_libname << endl;
00124 disconnect( it.current(), TQT_SIGNAL( destroyed() ),
00125 this, TQT_SLOT( slotObjectDestroyed() ) );
00126 }
00127 m_objs.setAutoDelete(true);
00128 m_objs.clear();
00129 }
00130
00131 if ( m_factory ) {
00132
00133 delete m_factory;
00134 m_factory = 0L;
00135 }
00136 }
00137
00138 TQString KLibrary::name() const
00139 {
00140 return m_libname;
00141 }
00142
00143 TQString KLibrary::fileName() const
00144 {
00145 return m_filename;
00146 }
00147
00148 KLibFactory* KLibrary::factory()
00149 {
00150 if ( m_factory )
00151 return m_factory;
00152
00153 TQCString symname;
00154 symname.sprintf("init_%s", name().latin1() );
00155
00156 void* sym = symbol( symname );
00157 if ( !sym )
00158 {
00159 KLibLoader::self()->d->errorMessage = i18n( "The library %1 does not offer an %2 function." ).arg( name(), "init_" + name() );
00160 kdWarning(150) << KLibLoader::self()->d->errorMessage << endl;
00161 return 0;
00162 }
00163
00164 typedef KLibFactory* (*t_func)();
00165 t_func func = (t_func)sym;
00166 m_factory = func();
00167
00168 if( !m_factory )
00169 {
00170 KLibLoader::self()->d->errorMessage = i18n( "The library %1 does not offer a TDE compatible factory." ).arg( name() );
00171 kdWarning(150) << KLibLoader::self()->d->errorMessage << endl;
00172 return 0;
00173 }
00174
00175 connect( m_factory, TQT_SIGNAL( objectCreated( TQObject * ) ),
00176 this, TQT_SLOT( slotObjectCreated( TQObject * ) ) );
00177
00178 return m_factory;
00179 }
00180
00181 void* KLibrary::symbol( const char* symname ) const
00182 {
00183 void* sym = lt_dlsym( (lt_dlhandle) m_handle, symname );
00184 if ( !sym )
00185 {
00186 KLibLoader::self()->d->errorMessage = "KLibrary: " + TQString::fromLocal8Bit( lt_dlerror() ) + i18n( " %1 %2" ).arg( name() ).arg( symname );
00187 kdWarning(150) << KLibLoader::self()->d->errorMessage << endl;
00188 return 0;
00189 }
00190
00191 return sym;
00192 }
00193
00194 bool KLibrary::hasSymbol( const char* symname ) const
00195 {
00196 void* sym = lt_dlsym( (lt_dlhandle) m_handle, symname );
00197 return (sym != 0L );
00198 }
00199
00200 void KLibrary::unload() const
00201 {
00202 if (KLibLoader::s_self)
00203 KLibLoader::s_self->unloadLibrary(TQFile::encodeName(name()));
00204 }
00205
00206 void KLibrary::slotObjectCreated( TQObject *obj )
00207 {
00208 if ( !obj )
00209 return;
00210
00211 if ( m_timer && m_timer->isActive() )
00212 m_timer->stop();
00213
00214 if ( m_objs.containsRef( obj ) )
00215 return;
00216
00217 connect( obj, TQT_SIGNAL( destroyed() ),
00218 this, TQT_SLOT( slotObjectDestroyed() ) );
00219
00220 m_objs.append( obj );
00221 }
00222
00223 void KLibrary::slotObjectDestroyed()
00224 {
00225 m_objs.removeRef( TQT_TQOBJECT_CONST(sender()) );
00226
00227 if ( m_objs.count() == 0 )
00228 {
00229
00230
00231
00232 if ( !m_timer )
00233 {
00234 m_timer = new TQTimer( this, "klibrary_shutdown_timer" );
00235 connect( m_timer, TQT_SIGNAL( timeout() ),
00236 this, TQT_SLOT( slotTimeout() ) );
00237 }
00238
00239
00240
00241
00242 m_timer->start( 1000*10, true );
00243 }
00244 }
00245
00246 void KLibrary::slotTimeout()
00247 {
00248 if ( m_objs.count() != 0 )
00249 return;
00250
00251
00252
00253
00254
00255 delete this;
00256 }
00257
00258
00259
00260
00261
00262
00263 class KLibWrapPrivate
00264 {
00265 public:
00266 KLibWrapPrivate(KLibrary *l, lt_dlhandle h);
00267
00268 KLibrary *lib;
00269 enum {UNKNOWN, UNLOAD, DONT_UNLOAD} unload_mode;
00270 int ref_count;
00271 lt_dlhandle handle;
00272 TQString name;
00273 TQString filename;
00274 };
00275
00276 KLibWrapPrivate::KLibWrapPrivate(KLibrary *l, lt_dlhandle h)
00277 : lib(l), ref_count(1), handle(h), name(l->name()), filename(l->fileName())
00278 {
00279 unload_mode = UNKNOWN;
00280 if (lt_dlsym(handle, "__kde_do_not_unload") != 0) {
00281
00282 unload_mode = DONT_UNLOAD;
00283 } else if (lt_dlsym(handle, "__kde_do_unload") != 0) {
00284 unload_mode = UNLOAD;
00285 }
00286 }
00287
00288 KLibLoader* KLibLoader::self()
00289 {
00290 if ( !s_self )
00291 s_self = new KLibLoader;
00292 return s_self;
00293 }
00294
00295 void KLibLoader::cleanUp()
00296 {
00297 if ( !s_self )
00298 return;
00299
00300 delete s_self;
00301 s_self = 0L;
00302 }
00303
00304 KLibLoader::KLibLoader( TQObject* parent, const char* name )
00305 : TQObject( parent, name )
00306 {
00307 s_self = this;
00308 d = new KLibLoaderPrivate;
00309 lt_dlinit();
00310 d->unload_mode = KLibLoaderPrivate::UNKNOWN;
00311 if (getenv("TDE_NOUNLOAD") != 0)
00312 d->unload_mode = KLibLoaderPrivate::DONT_UNLOAD;
00313 else if (getenv("TDE_DOUNLOAD") != 0)
00314 d->unload_mode = KLibLoaderPrivate::UNLOAD;
00315 d->loaded_stack.setAutoDelete( true );
00316 }
00317
00318 KLibLoader::~KLibLoader()
00319 {
00320
00321
00322 TQAsciiDictIterator<KLibWrapPrivate> it( m_libs );
00323 for (; it.current(); ++it )
00324 {
00325 kdDebug(150) << "The KLibLoader contains the library " << it.current()->name
00326 << " (" << it.current()->lib << ")" << endl;
00327 d->pending_close.append(it.current());
00328 }
00329
00330 close_pending(0);
00331
00332 delete d;
00333 d = 0L;
00334 }
00335
00336 static inline TQCString makeLibName( const char* name )
00337 {
00338 TQCString libname(name);
00339
00340
00341
00342 int pos = libname.findRev('/');
00343 if (pos < 0)
00344 pos = 0;
00345 if (libname.find('.', pos) < 0)
00346 libname += ".la";
00347 return libname;
00348 }
00349
00350
00351 TQString KLibLoader::findLibrary( const char * name, const TDEInstance * instance )
00352 {
00353 TQCString libname = makeLibName( name );
00354
00355
00356
00357 TQString libfile;
00358 if (!TQDir::isRelativePath(libname))
00359 libfile = TQFile::decodeName( libname );
00360 else
00361 {
00362 libfile = instance->dirs()->findResource( "module", libname );
00363 if ( libfile.isEmpty() )
00364 {
00365 libfile = instance->dirs()->findResource( "lib", libname );
00366 #ifndef NDEBUG
00367 if ( !libfile.isEmpty() && libname.left(3) == "lib" )
00368 kdDebug(150) << "library " << libname << " not found under 'module' but under 'lib'" << endl;
00369 #endif
00370 }
00371 }
00372 return libfile;
00373 }
00374
00375
00376 KLibrary* KLibLoader::globalLibrary( const char *name )
00377 {
00378 KLibrary *tmp;
00379 int olt_dlopen_flag = lt_dlopen_flag;
00380
00381 lt_dlopen_flag |= LT_GLOBAL;
00382 kdDebug(150) << "Loading the next library global with flag "
00383 << lt_dlopen_flag
00384 << "." << endl;
00385 tmp = library(name);
00386 lt_dlopen_flag = olt_dlopen_flag;
00387
00388 return tmp;
00389 }
00390
00391
00392 KLibrary* KLibLoader::library( const char *name )
00393 {
00394 if (!name)
00395 return 0;
00396
00397 KLibWrapPrivate* wrap = m_libs[name];
00398 if (wrap) {
00399
00400 wrap->ref_count++;
00401 return wrap->lib;
00402 }
00403
00404
00405
00406 TQPtrListIterator<KLibWrapPrivate> it(d->loaded_stack);
00407 for (; it.current(); ++it) {
00408 if (it.current()->name == name)
00409 wrap = it.current();
00410 }
00411
00412 if (wrap) {
00413 d->pending_close.removeRef(wrap);
00414 if (!wrap->lib) {
00415
00416 wrap->lib = new KLibrary( name, wrap->filename, wrap->handle );
00417 }
00418 wrap->ref_count++;
00419 } else {
00420 TQString libfile = findLibrary( name );
00421 if ( libfile.isEmpty() )
00422 {
00423 const TQCString libname = makeLibName( name );
00424 #ifndef NDEBUG
00425 kdDebug(150) << "library=" << name << ": No file named " << libname << " found in paths." << endl;
00426 #endif
00427 d->errorMessage = i18n("Library files for \"%1\" not found in paths.").arg(TQString(libname));
00428 return 0;
00429 }
00430
00431 lt_dlhandle handle = lt_dlopen( TQFile::encodeName(libfile) );
00432 if ( !handle )
00433 {
00434 const char* errmsg = lt_dlerror();
00435 if(errmsg)
00436 d->errorMessage = TQString::fromLocal8Bit(errmsg);
00437 else
00438 d->errorMessage = TQString::null;
00439 return 0;
00440 }
00441 else
00442 d->errorMessage = TQString::null;
00443
00444 KLibrary *lib = new KLibrary( name, libfile, handle );
00445 wrap = new KLibWrapPrivate(lib, handle);
00446 d->loaded_stack.prepend(wrap);
00447 }
00448 m_libs.insert( name, wrap );
00449
00450 connect( wrap->lib, TQT_SIGNAL( destroyed() ),
00451 this, TQT_SLOT( slotLibraryDestroyed() ) );
00452
00453 return wrap->lib;
00454 }
00455
00456 TQString KLibLoader::lastErrorMessage() const
00457 {
00458 return d->errorMessage;
00459 }
00460
00461 void KLibLoader::unloadLibrary( const char *libname )
00462 {
00463 KLibWrapPrivate *wrap = m_libs[ libname ];
00464 if (!wrap)
00465 return;
00466 if (--wrap->ref_count)
00467 return;
00468
00469
00470
00471 m_libs.remove( libname );
00472
00473 disconnect( wrap->lib, TQT_SIGNAL( destroyed() ),
00474 this, TQT_SLOT( slotLibraryDestroyed() ) );
00475 close_pending( wrap );
00476 }
00477
00478 KLibFactory* KLibLoader::factory( const char* name )
00479 {
00480 KLibrary* lib = library( name );
00481 if ( !lib )
00482 return 0;
00483
00484 return lib->factory();
00485 }
00486
00487 void KLibLoader::slotLibraryDestroyed()
00488 {
00489 const KLibrary *lib = static_cast<const KLibrary *>( sender() );
00490
00491 TQAsciiDictIterator<KLibWrapPrivate> it( m_libs );
00492 for (; it.current(); ++it )
00493 if ( it.current()->lib == lib )
00494 {
00495 KLibWrapPrivate *wrap = it.current();
00496 wrap->lib = 0;
00497 m_libs.remove( it.currentKey() );
00498 close_pending( wrap );
00499 return;
00500 }
00501 }
00502
00503 void KLibLoader::close_pending(KLibWrapPrivate *wrap)
00504 {
00505 if (wrap && !d->pending_close.containsRef( wrap ))
00506 d->pending_close.append( wrap );
00507
00508
00509
00510 TQPtrListIterator<KLibWrapPrivate> it(d->pending_close);
00511 for (; it.current(); ++it) {
00512 wrap = it.current();
00513 if (wrap->lib) {
00514 disconnect( wrap->lib, TQT_SIGNAL( destroyed() ),
00515 this, TQT_SLOT( slotLibraryDestroyed() ) );
00516 KLibrary* to_delete = wrap->lib;
00517 wrap->lib = 0L;
00518 delete to_delete;
00519 }
00520 }
00521
00522 if (d->unload_mode == KLibLoaderPrivate::DONT_UNLOAD) {
00523 d->pending_close.clear();
00524 return;
00525 }
00526
00527 bool deleted_one = false;
00528 while ((wrap = d->loaded_stack.first())) {
00529
00530
00531
00532
00533 if (d->unload_mode != KLibLoaderPrivate::UNLOAD
00534 && wrap->unload_mode != KLibWrapPrivate::UNLOAD)
00535 break;
00536
00537
00538
00539 if (!d->pending_close.containsRef( wrap )) {
00540 if (!deleted_one)
00541
00542
00543 break;
00544 }
00545
00546
00547
00548 if ( !deleted_one ) {
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558 if( kapp->clipboard()->ownsSelection()) {
00559 kapp->clipboard()->setText(
00560 kapp->clipboard()->text( TQClipboard::Selection ), TQClipboard::Selection );
00561 }
00562 if( kapp->clipboard()->ownsClipboard()) {
00563 kapp->clipboard()->setText(
00564 kapp->clipboard()->text( TQClipboard::Clipboard ), TQClipboard::Clipboard );
00565 }
00566 }
00567
00568 deleted_one = true;
00569 lt_dlclose(wrap->handle);
00570 d->pending_close.removeRef(wrap);
00571
00572 d->loaded_stack.remove();
00573 }
00574 }
00575
00576 void KLibLoader::virtual_hook( int, void* )
00577 { }
00578
00579 void KLibFactory::virtual_hook( int, void* )
00580 { }
00581
00582 #include "klibloader.moc"