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