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