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