View Issue Details

IDProjectCategoryView StatusLast Update
0002166ScribusInternalpublic2005-07-06 04:42
Reporterjghali Assigned Toringerc 
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionfixed 
PlatformWindowsOSWindowsOS Version2000 SP4
Product Version1.3.0cvs 
Fixed in Version1.3.0cvs 
Summary0002166: Platform independent library loading
Descriptionscribus.cpp scribus.h pluginmanager.cpp and pluginmanager.h modified to use qlibrary instead of dlfcn. Patch supplied for 1.3.0cvs.

Removed additionnaly a non portable construct in scribus.cpp (same variable name used for two different variable types) :

for( QMap<QString, QGuardedPtr<ScrAction> >::Iterator it = scrLayersActions.begin(); it!=scrLayersActions.end(); ++it )
            scrMenuMgr->removeMenuItem((*it), layerMenuName);
scrLayersActions.clear();
uint a;
QValueList<Layer>::iterator it;

Renamed the first it to it0
TagsNo tags attached.
Patch

Relationships

child of 0000015 closedjghali Windows Port 

Activities

ringerc

2005-06-30 13:28

reporter   ~0005271

Last edited: 2005-06-30 13:31

Your patch seems to be corrupt ... at least, I can't apply it here. Most of the hunks are fine, but the pluginmanager.h diff doesn't work. I'll apply that one manually, so don't worry - just FYI. Did you edit it by hand after generating it perhaps? It seems to be double-spaced.

[Edit: s/pageitem/pluginmanager/g . Too much work on PageItem recently I guess. ]

jghali

2005-06-30 13:37

administrator   ~0005272

Using WinCVS, the final step to produce the patch is doing a copy - paste in wordpad. This is the only manual thing I've done.

jghali

2005-06-30 13:53

administrator   ~0005273

I just remarked a potential bug in PluginManager::DLLname.
Replace :
demo3 = (sdem3) mo->resolve("actionEnabledOnStartup");
if ( demo == NULL )
By :
demo3 = (sdem3) mo->resolve("actionEnabledOnStartup");
if ( demo3 == NULL )
Sorry...

ringerc

2005-06-30 14:01

reporter   ~0005274

I've applied the patch here. With it, plug-ins silently fail to load, or fail to run. Not sure which yet; I'll investigate.

On a plug-in related matter, your opinion on http://wiki.scribus.net/index.php/New_plug-in_API would be much appreciated. Any win32 boobytraps you see? Any design suggestions/improvements?

ringerc

2005-06-30 14:07

reporter   ~0005275

That portability tweak is in CVS now.

I was pretty sure the C++ standard required that the control variable in a for loop, if declared in the for construct, had to have its own scope. Is this not the case for MSVC++ or is there something else going on here? (I'm no C++ expert).

jghali

2005-06-30 14:21

administrator   ~0005276

The protability problem is not with variable scope. MSVC compiler doesn't allow for example :
for( int i = 0; i < 10; i++ )
{
   ..//do something
}
i = 0;
But when you declare after your loop a variable with same name and different type, MSVC.net compiler get lost. It's not a problem with C++ Standard conformance.

jghali

2005-06-30 14:28

administrator   ~0005277

Another error on my side in PluginManager::DLLname (sorry my windows build is currently broken) :
replace line with :
if ( !demo == NULL)
by :
if ( demo == NULL )

jghali

2005-06-30 14:37

administrator   ~0005278

Updated diff for pluginmanager.cpp

jghali

2005-06-30 14:38

administrator   ~0005279

Oops. Forgot to upload the file...

ringerc

2005-06-30 15:04

reporter   ~0005281

That version works much better. Things work here without fuss, except for one odd problem with the script plugin:

Traceback (most recent call last):
  File "<string>", line 3, in ?
ImportError: /usr/lib/python2.4/lib-dynload/cStringIO.so: undefined symbol: _Py_TrueStruct

It looks like moving to QLibrary has somehow broken Python's dynamic module loading. I suspect it may well be to do with the fact that we dlopen with RTLD_LAZY|RTLD_GLOBAL but QLibrary uses just RTLD_LAZY, though I'm not sure yet.

2005-06-30 15:04

 

plugins_to_qlibrary.diff (13,277 bytes)   
? isTableItem
? plugins/monitorprofile
Index: pluginmanager.cpp
===================================================================
RCS file: /cvs/Scribus/scribus/Attic/pluginmanager.cpp,v
retrieving revision 1.1.2.14
diff -u -r1.1.2.14 pluginmanager.cpp
--- pluginmanager.cpp	9 Jun 2005 00:07:01 -0000	1.1.2.14
+++ pluginmanager.cpp	30 Jun 2005 17:01:26 -0000
@@ -1,7 +1,8 @@
 #include "pluginmanager.h"
 #include "pluginmanager.moc"
-#include <dlfcn.h>
+
 #include <qdir.h>
+
 #include "scribus.h"
 #include "scribusapp.h"
 #include "menumanager.h"
@@ -119,8 +120,7 @@
 
 void PluginManager::callDLL(int pluginID)
 {
-	void *mo;
-	const char *error;
+	QLibrary *qlib;
 	struct PluginData pda;
 	pda = pluginMap[pluginID];
 	typedef void (*sdem)(QWidget *d, ScribusApp *plug);
@@ -129,79 +129,72 @@
 	if (pda.type != 4 && pda.type !=5)
 	{
 		plugDir += pda.pluginFile;
-		mo = dlopen(plugDir, RTLD_LAZY | RTLD_GLOBAL);
-		if (!mo)
-		{
-			qDebug( tr("Cannot find plugin"), "plugin manager");
-			return;
-		}
+		qlib = new QLibrary(plugDir);
 	}
 	else
-		mo = pda.index;
-	dlerror();
-	demo = (sdem)dlsym(mo, "run");
-	if ((error = dlerror()) != NULL)
+		qlib = pda.index;
+
+	demo = (sdem) qlib->resolve("run");
+	if ( !demo )
 	{
-		qDebug( tr(QString("Cannot find symbol (%1)").arg(error)), "plugin manager");
-		dlclose(mo);
+		qDebug( tr(QString("Cannot find symbol (%1) or plugin missing").arg("run")), "plugin manager");
+		delete qlib;
 		return;
 	}
 	(*demo)(ScApp, ScApp);
 	// FIXME: how is the menu organized? (*demo)(ScApp->scrActions[pluginMap[pluginID].actName], ScApp);
 	if (pda.type != 4 && pda.type != 5)
-		dlclose(mo);
+	{
+		pda.index = NULL;
+		delete qlib;
+	}
 	if (ScApp->HaveDoc)
 		ScApp->view->DrawNew();
 }
 
 QString PluginManager::callDLLForNewLanguage(int pluginID)
 {
-	void *mo;
-	const char *error;
+	QLibrary *qlib;
+	bool qdel = false;
 	struct PluginData pda;
 	pda = pluginMap[pluginID];
 	typedef QString (*sdem)();
 	typedef void (*sdem0)();
-	sdem demo;
-	sdem0 demo0;
+	sdem demo = NULL;
+	sdem0 demo0 = NULL;
 	QString plugDir = ScPaths::instance().pluginDir();
+	
 	if (pda.type != 4 && pda.type !=5)
 	{
 		plugDir += pda.pluginFile;
-		mo = dlopen(plugDir, RTLD_LAZY | RTLD_GLOBAL);
-		if (!mo)
-		{
-			qDebug( tr("Cannot find plugin"), "plugin manager");
-			return QString::null;
-		}
+		qlib = new QLibrary(plugDir);
+		qdel = true;
 	}
 	else
-		mo = pda.index;
-	dlerror();
-	// Grab the menu string from the plugin again
-	demo = (sdem)dlsym(mo, "name");
-	if ((error = dlerror()) != NULL)
+		qlib = pda.index;
+
+	demo = (sdem) qlib->resolve("name");
+	if ( !demo)
 	{
-		qDebug( tr(QString("Cannot find symbol (%1)").arg(error)), "plugin manager");
-		//dlclose(mo);
+		qDebug( tr(QString("Cannot find symbol (%1) or plugin missing").arg("name")), "plugin manager");
+		if( qdel ) delete(qlib);
 		return QString::null;
 	}
 	QString retVal=(*demo)();	
 	//If scripter, get it to update its scrActions.
 	if (pluginID==8)
 	{
-		dlerror();
-		demo0 = (sdem0)dlsym(mo, "languageChange");
-		if ((error = dlerror()) != NULL)
+		demo0 = (sdem0) qlib->resolve("languageChange");
+		if ( !demo0 )
 		{
-			dlclose(mo);
-			return false;
+			if( qdel ) delete qlib;
+			return QString::null;
 		}
 		(*demo0)();
 	}
 
 	if (pda.type != 4 && pda.type != 5)
-		dlclose(mo);
+		delete qlib;
 	return retVal;
 }
 
@@ -225,10 +218,9 @@
 	}
 }
 
-bool PluginManager::DLLname(QString name, QString *pluginName, PluginType *type, void **index, int *idNr, QString *actName, QString *actKeySequence, QString *actMenu, QString *actMenuAfterName, bool *actEnabledOnStartup, bool loadPlugin)
+bool PluginManager::DLLname(QString name, QString *pluginName, PluginType *type, QLibrary **index, int *idNr, QString *actName, QString *actKeySequence, QString *actMenu, QString *actMenuAfterName, bool *actEnabledOnStartup, bool loadPlugin)
 {
-	void *mo;
-	const char *error;
+	QLibrary *mo;
 	typedef QString (*sdem0)();
 	typedef PluginType (*sdem1)();
 	typedef void (*sdem2)(QWidget *d, ScribusApp *plug);
@@ -242,75 +234,67 @@
 	QString plugName = ScPaths::instance().pluginDir();
 	plugName += name;
 
-	mo = dlopen(plugName, RTLD_LAZY | RTLD_GLOBAL);
-	if (!mo)
-	{
-		qDebug( tr(QString("Error: %1").arg(dlerror())), "plugin manager");
-		return false;
-	}
-	dlerror();
-	demo = (sdem0)dlsym(mo, "name");
-	if ((error = dlerror()) != NULL)
+	mo = new QLibrary(plugName);
+	demo = (sdem0) mo->resolve("name");
+	if ( !demo )
 	{
-		dlclose(mo);
+		delete mo;
 		return false;
 	}
 	*pluginName = (*demo)();
-	dlerror();
-	demo1 = (sdem1)dlsym(mo, "type");
-	if ((error = dlerror()) != NULL)
+
+	demo1 = (sdem1) mo->resolve("type");
+	if ( !demo1 )
 	{
-		dlclose(mo);
+		delete mo;
 		return false;
 	}
 	*type = (*demo1)();
 	*index = mo;
-	plugID = (sdemID)dlsym(mo, "ID");
-	if ((error = dlerror()) != NULL)
+
+	plugID = (sdemID) mo->resolve("ID");
+	if( !plugID )
 	{
-		dlclose(mo);
+		delete mo;
 		return false;
 	}
 	*idNr = (*plugID)();
+
 	//ScrAction based plugins
 	if (*type == Persistent || *type == Standard || *type == Import)
 	{
-		demo = (sdem0)dlsym(mo, "actionName");
-		if ((error = dlerror()) != NULL)
+		demo = (sdem0) mo->resolve("actionName");
+		if ( !demo )
 		{
-			dlclose(mo);
+			delete (mo);
 			return false;
 		}
 		*actName = (*demo)();
-		dlerror();
-		demo = (sdem0)dlsym(mo, "actionKeySequence");
-		if ((error = dlerror()) != NULL)
+		demo = (sdem0) mo->resolve("actionKeySequence");
+		if ( !demo )
 		{
-			dlclose(mo);
+			delete (mo);
 			return false;
 		}
 		*actKeySequence = (*demo)();
-		dlerror();
-		demo = (sdem0)dlsym(mo, "actionMenu");
-		if ((error = dlerror()) != NULL)
+		demo = (sdem0) mo->resolve("actionMenu");
+		if ( !demo )
 		{
-			dlclose(mo);
+			delete mo;
 			return false;
 		}
 		*actMenu = (*demo)();
-		dlerror();
-		demo = (sdem0)dlsym(mo, "actionMenuAfterName");
-		if ((error = dlerror()) != NULL)
+		demo = (sdem0) mo->resolve("actionMenuAfterName");
+		if ( !demo )
 		{
-			dlclose(mo);
+			delete mo;
 			return false;
 		}
 		*actMenuAfterName = (*demo)();
-		dlerror();
-		demo3 = (sdem3)dlsym(mo, "actionEnabledOnStartup");
-		if ((error = dlerror()) != NULL)
+		demo3 = (sdem3) mo->resolve("actionEnabledOnStartup");
+		if ( !demo3 )
 		{
-			dlclose(mo);
+			delete mo;
 			return false;
 		}
 		*actEnabledOnStartup = (*demo3)();
@@ -324,16 +308,15 @@
 		*actEnabledOnStartup = false;
 	}
 	if (*type != Persistent && *type!= Type5)
-		dlclose(mo);
+		delete mo;
 	else
 	{
 		if (loadPlugin)
 		{
-			dlerror();
-			demo2 = (sdem2)dlsym(mo, "initPlug");
-			if ((error = dlerror()) != NULL)
+			demo2 = (sdem2) mo->resolve("initPlug");
+			if ( demo2 == NULL)
 			{
-				dlclose(mo);
+				delete mo;
 				return false;
 			}
 			(*demo2)(ScApp, ScApp);
@@ -352,21 +335,17 @@
 
 void PluginManager::finalizePlug(int pluginID)
 {
-	const char *error;
 	struct PluginData pda;
 	typedef void (*sdem2)();
 	sdem2 demo2;
 	PluginData plug = pluginMap[pluginID];
 	if (plug.type == Persistent || plug.type == Type5)
 	{
-		dlerror();
-		demo2 = (sdem2)dlsym(plug.index, "cleanUpPlug");
-		if ((error = dlerror()) != NULL)
-		{
-			dlclose(plug.index);
-		}
-		else
+		QLibrary* qlib = plug.index;
+		demo2 = (sdem2) qlib->resolve("cleanUpPlug");
+		if ( demo2 )
 			(*demo2)();
+		delete(plug.index);
 	}
 }
 
@@ -403,6 +382,8 @@
 
 	//return "dylib";
 	return "so";
+#elif defined(_WIN32) || defined(_WIN64)
+	return "dll";
 #else
 	// Generic *NIX
 	return "so";
Index: pluginmanager.h
===================================================================
RCS file: /cvs/Scribus/scribus/Attic/pluginmanager.h,v
retrieving revision 1.1.2.9
diff -u -r1.1.2.9 pluginmanager.h
--- pluginmanager.h	22 May 2005 20:41:25 -0000	1.1.2.9
+++ pluginmanager.h	30 Jun 2005 17:01:26 -0000
@@ -3,7 +3,7 @@
 
 #include <qobject.h>
 #include <qstring.h>
-#include <qmap.h>
+#include <qlibrary.h>
 #include "scribus.h"
 
 /**
@@ -48,7 +48,7 @@
 	{
 		QString pluginFile;// Datei;
 		QString name;
-		void *index; //Zeiger;
+		QLibrary *index; //Zeiger;
 		PluginType type;
 		int menuID;
 		QString actName;
@@ -76,7 +76,7 @@
 	/*! unused/obsolete */
 	void callDLLbyMenu(int pluginID);
 	/*! \brief Reads available info and fills PluginData structure */
-	bool DLLname(QString name, QString *pluginName, PluginType *type, void **index, int *idNr, QString *actName, QString *actKeySequence, QString *actMenu, QString *actMenuAfterName, bool *actEnabledOnStartup, bool loadPlugin);
+	bool DLLname(QString name, QString *pluginName, PluginType *type, QLibrary **index, int *idNr, QString *actName, QString *actKeySequence, QString *actMenu, QString *actMenuAfterName, bool *actEnabledOnStartup, bool loadPlugin);
 	/*! \brief Shutdowns all plugins. Called at scribus quit */
 	void finalizePlugs();
 	/*! \brief Shutdowns one plugin.
Index: scribus.cpp
===================================================================
RCS file: /cvs/Scribus/scribus/scribus.cpp,v
retrieving revision 1.228.2.394
diff -u -r1.228.2.394 scribus.cpp
--- scribus.cpp	30 Jun 2005 16:06:10 -0000	1.228.2.394
+++ scribus.cpp	30 Jun 2005 17:01:29 -0000
@@ -33,13 +33,19 @@
 #include <cstdio>
 #include <cstdlib>
 #include <cmath>
+
+#ifdef HAVE_DLFCN_H
 #include <dlfcn.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
+
 #include <iostream>
 #include <signal.h>
 #include <string>
 
-
 #include "scribusapp.h"
 #include "scribus.h"
 #include "scribus.moc"
@@ -5479,7 +5485,7 @@
 		}
 		else
 			retw = false;
-		delete dd;
+		delete dd; // Not Windows friendly, should be something like dd->destroyInstance();
 		closePSDriver();
 	}
 	fileWatcher->start();
@@ -8638,6 +8644,8 @@
 	raise();
 }
 
+#ifdef HAVE_DLFCN_H
+
 PSLib* ScribusApp::getPSDriver(bool psart, SCFonts &AllFonts, QMap<QString,QFont> DocFonts, ColorList DocColors, bool pdf)
 {
 	const char *error;
@@ -8662,9 +8670,34 @@
 	return dia;
 }
 
+#else
+
+PSLib* ScribusApp::getPSDriver(bool psart, SCFonts &AllFonts, QMap<QString,QFont> DocFonts, ColorList DocColors, bool pdf)
+{
+	typedef PSLib* (*sdem)(bool psart, SCFonts &AllFonts, QMap<QString,QFont> DocFonts, ColorList DocColors, bool pdf);
+	sdem pfunc;
+	QString pfad = QString("%1/libs/libpostscript.%3").arg(ScPaths::instance().libDir()).arg(PluginManager::platformDllExtension());
+	PSDriver = new QLibrary(pfad);
+	pfunc = (sdem) PSDriver->resolve("Run");
+	if ( !pfunc )
+	{
+		std::cout << "Cannot find symbol or driver missing" << endl;
+		delete PSDriver;
+		return NULL;
+	}
+	PSLib *dia = (*pfunc)(psart, AllFonts, DocFonts, DocColors, pdf);
+	return dia;
+}
+
+#endif
+
 void ScribusApp::closePSDriver()
 {
+#ifdef HAVE_DLFCN_H
 	dlclose(PSDriver);
+#else
+	delete PSDriver;
+#endif
 }
 
 bool ScribusApp::DoSaveAsEps(QString fn)
@@ -8686,7 +8719,7 @@
 			dd->CreatePS(doc, view, pageNs, false, tr("All"), true, false, false, true, Prefs.GCRMode, false);
 		else
 			return_value = false;
-		delete dd;
+		delete dd; // Not Windows friendly, should be something like dd->destroyInstance();
 		closePSDriver();
 		qApp->setOverrideCursor(QCursor(arrowCursor), true);
 	}
@@ -8763,6 +8796,8 @@
 	}
 }
 
+#ifdef HAVE_DLFCN_H
+
 bool ScribusApp::getPDFDriver(QString fn, QString nam, int Components, std::vector<int> &pageNs, QMap<int,QPixmap> thumbs)
 {
 	bool ret = false;
@@ -8793,6 +8828,33 @@
 	return ret;
 }
 
+#else
+
+bool ScribusApp::getPDFDriver(QString fn, QString nam, int Components, std::vector<int> &pageNs, QMap<int,QPixmap> thumbs)
+{
+	bool ret = false;
+	QLibrary *PDFDriver;
+	typedef bool (*sdem)(ScribusApp *plug, QString fn, QString nam, int Components, std::vector<int> &pageNs, QMap<int,QPixmap> thumbs, QProgressBar *dia2);
+	sdem pfunc;
+	QString pfad = QString("%1/libs/libpdf.%3").arg(ScPaths::instance().libDir()).arg(PluginManager::platformDllExtension());
+	PDFDriver = new QLibrary(pfad);
+	pfunc = (sdem) PDFDriver->resolve("Run");
+	if ( !pfunc )
+	{
+		std::cout << "Cannot find symbol or driver missing" << endl;
+		delete PDFDriver;
+		return false;
+	}
+	fileWatcher->forceScan();
+	fileWatcher->stop();
+	ret = (*pfunc)(this, fn, nam, Components, pageNs, thumbs, mainWindowProgressBar);
+	delete PDFDriver;
+	fileWatcher->start();
+	return ret;
+}
+
+#endif
+
 void ScribusApp::SaveAsPDF()
 {
 	if (doc->checkerProfiles[doc->curCheckProfile].autoCheck)
Index: scribus.h
===================================================================
RCS file: /cvs/Scribus/scribus/scribus.h,v
retrieving revision 1.60.2.111
diff -u -r1.60.2.111 scribus.h
--- scribus.h	26 Jun 2005 11:06:39 -0000	1.60.2.111
+++ scribus.h	30 Jun 2005 17:01:29 -0000
@@ -50,6 +50,18 @@
 #include <qclipboard.h>
 #include <qprocess.h>
 
+#ifdef _MSC_VER
+ #if (_MSC_VER >= 1200)
+  #include "win-config.h"
+ #endif
+#else
+ #include "config.h"
+#endif
+
+#ifndef HAVE_DLFCN_H
+#include <qlibrary.h>
+#endif
+
 // application specific includes
 #include "scribusview.h"
 #include "scribusdoc.h"
@@ -545,7 +557,11 @@
 	void addNewPages(int wo, int where, int numPages, QString based1 = tr("Normal"), QString based2 = tr("Normal"));
 	QMap<int,QString> FontID;
 	int HaveGS;
+#ifdef HAVE_DLFCN_H
 	void *PSDriver;
+#else
+	QLibrary *PSDriver;
+#endif
 	int DocNr;
 	QStringList RecentDocs;
 	UndoManager *undoManager;
plugins_to_qlibrary.diff (13,277 bytes)   

ringerc

2005-06-30 15:05

reporter   ~0005282

Uploaded new full diff; this one should apply cleanly too.

ringerc

2005-06-30 15:07

reporter   ~0005283

from `man dlfcn.h':

       The <dlfcn.h> header shall define at least the following macros for use in the construction of a dlopen() mode argument:

       RTLD_LAZY
              Relocations are performed at an implementation-defined time.

       RTLD_NOW
              Relocations are performed when the object is loaded.

       RTLD_GLOBAL
              All symbols are available for relocation processing of other modules.

       RTLD_LOCAL
              All symbols are not made available for relocation processing by other modules.

cbradney

2005-06-30 15:12

administrator   ~0005284

Oh how MSVC is so broken!

ringerc

2005-06-30 16:25

reporter   ~0005287

For all we know it might be gcc being more permissive than the standard requires ;-) . Not important - simple compiler compat fixes like this are always desirable.

The issues with the rest of the patch look like they have much more to do with QLibrary than the patch its self, unfortunately.

ringerc

2005-06-30 16:26

reporter   ~0005288

Removed older files.

jghali

2005-06-30 16:28

administrator   ~0005289

So we should maybe change our way of doing. I suggest to implement 3 static method in pluginmanager :
- loadDLL( QString plugin )
- resolveSym( void* plugin, const char* sym )
- unloadDLL( void* plugin )
These tree method would have plateform dependant implementation, using dlfcn on unix system, native api or qLibrary on choice. What do you think about that?

ringerc

2005-06-30 16:38

reporter   ~0005290

That seems reasonable. It's most unfortunate that it looks like we'll have to add another layer of abstraction over QLibrary, which after all just abstracts platform APIs. I guess that'll let better win32-specific code be added later too, though.

jghali

2005-06-30 16:52

administrator   ~0005292

Last edited: 2005-06-30 16:52

Yes, it's a pity QLibrary doesn't make it. I planed something like this :

#ifdef HAVE_DLFCN_H
// use dlfcn functions
#elif defined(DLL_USE_NATIVE_API) && defined(_WIN32)
// win32 specific code
#else
// use QLibrary
#endif

win32 specific code is quite straightforward. Going to be available with next patches. Going to do this tonight.

ringerc

2005-06-30 16:56

reporter   ~0005293

Retaining dl* on *nix will let us keep dlerror() too, which is nice. It'll be possible to use the *nix code on Mac OS X too, since dlcompat is present there.

Btw, when trying to get Python support working it's entirely possible you'll run into the same issue I did with QLibrary. One possible symptom is that simple commands will silently fail to do anything in the script console, though the script console will be available. That's because we can't load cStringIO - Python as to dynamically load it - and we need that to capture error messages. If Python logs stderr/stdout to somewhere you can get to it on win32, you should see an exception from it as well.

If you have issues with Qt, by the way, you may find it useful to build Qt with QT_DEBUG and/or QT_DEBUG_COMPONENT defined. That'll make it *much* more verbose about things, but make it easier to see what's going on. For example, it should actually report library errors - the only way you're likely to get at those errors given that it doesn't give apps any API to access to the error messages.

Anyway, I just noticed it's 3:00am here (ugh) so I'm going to crash. Let me know if you want me to do the conversion to use QLibrary on win32 and dl*, or if you want to do it.

ringerc

2005-06-30 16:57

reporter   ~0005294

OK, just noticed your comment re you already working on it. Great. Thanks very much for this. I'll check back in the morning and see how things go.

2005-06-30 21:14

 

pluginmanager_platfindep.diff (9,399 bytes)   
Index: pluginmanager.cpp
===================================================================
RCS file: /cvs/Scribus/scribus/Attic/pluginmanager.cpp,v
retrieving revision 1.1.2.14
diff -u -r1.1.2.14 pluginmanager.cpp
--- pluginmanager.cpp	9 Jun 2005 00:07:01 -0000	1.1.2.14
+++ pluginmanager.cpp	30 Jun 2005 23:10:24 -0000
@@ -1,7 +1,16 @@
 #include "pluginmanager.h"
 #include "pluginmanager.moc"
-#include <dlfcn.h>
+
 #include <qdir.h>
+
+#ifdef _MSC_VER
+ #if (_MSC_VER >= 1200)
+  #include "win-config.h"
+ #endif
+#else
+ #include "config.h"
+#endif
+
 #include "scribus.h"
 #include "scribusapp.h"
 #include "menumanager.h"
@@ -12,6 +21,14 @@
 #include "prefsfile.h"
 #include "scpaths.h"
 
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#elif defined(DLL_USE_NATIVE_API) && defined(_WIN32)
+#include <windows.h>
+#else
+#include <qlibrary.h>
+#endif
+
 extern ScribusApp *ScApp;
 extern ScribusQApp *ScQApp;
 extern PrefsFile *prefsFile;
@@ -28,6 +45,71 @@
 {
 }
 
+void* PluginManager::loadDLL( QString plugin )
+{
+	void* lib = NULL;
+#ifdef HAVE_DLFCN_H
+	QString libpath = QDir::convertSeparators( plugin );
+	lib = dlopen(libpath, RTLD_LAZY | RTLD_GLOBAL);
+	if (!lib)
+	{
+		qDebug( "Cannot find plugin", "plugin manager");
+	}
+	dlerror();
+#elif defined(DLL_USE_NATIVE_API) && defined(_WIN32)
+	QString libpath = QDir::convertSeparators( plugin );
+	HINSTANCE hdll = LoadLibrary( (const char*) libpath );
+	lib = (void*) hdll;
+#else
+	if( QFile::exists(plugin) )
+		lib = (void*) new QLibrary( plugin );
+	else
+		qDebug( "Cannot find plugin", "plugin manager");
+#endif
+	return lib;
+}
+
+void* PluginManager::resolveSym( void* plugin, const char* sym )
+{
+	void* symAddr = NULL;
+#ifdef HAVE_DLFCN_H
+	const char* error;
+	dlerror();
+	symAddr = dlsym( plugin, sym );
+	if ((error = dlerror()) != NULL)
+	{
+		qDebug( QString("Cannot find symbol (%1)").arg(error), "plugin manager");
+		symAddr = NULL;
+	}
+#elif defined(DLL_USE_NATIVE_API) && defined(_WIN32)
+	symAddr = (void* ) GetProcAddress( (HMODULE) plugin, sym);
+	if ( symAddr == NULL)
+	{
+		qDebug( QString("Cannot find symbol (%1)").arg(sym), "plugin manager");
+	}
+#else
+	QLibrary* qlib = (QLibrary*) plugin;
+	if( plugin ) symAddr = qlib->resolve(sym);
+	if ( symAddr == NULL)
+	{
+		qDebug( QString("Cannot find symbol (%1)").arg(sym), "plugin manager");
+	}
+#endif
+	return symAddr;
+}
+
+void  PluginManager::unloadDLL( void* plugin )
+{
+#ifdef HAVE_DLFCN_H
+	dlclose( plugin );
+	dlerror();
+#elif defined(DLL_USE_NATIVE_API) && defined(_WIN32)
+	FreeLibrary( (HMODULE) plugin );
+#else
+	delete ( (QLibrary*) plugin );
+#endif
+}
+
 void PluginManager::savePreferences()
 {
 	// write configuration
@@ -120,7 +202,6 @@
 void PluginManager::callDLL(int pluginID)
 {
 	void *mo;
-	const char *error;
 	struct PluginData pda;
 	pda = pluginMap[pluginID];
 	typedef void (*sdem)(QWidget *d, ScribusApp *plug);
@@ -129,27 +210,22 @@
 	if (pda.type != 4 && pda.type !=5)
 	{
 		plugDir += pda.pluginFile;
-		mo = dlopen(plugDir, RTLD_LAZY | RTLD_GLOBAL);
-		if (!mo)
-		{
-			qDebug( tr("Cannot find plugin"), "plugin manager");
-			return;
-		}
+		mo = loadDLL(plugDir);
+		if (!mo) return;
 	}
 	else
 		mo = pda.index;
-	dlerror();
-	demo = (sdem)dlsym(mo, "run");
-	if ((error = dlerror()) != NULL)
+
+	demo = (sdem) resolveSym(mo, "run");
+	if ( !demo )
 	{
-		qDebug( tr(QString("Cannot find symbol (%1)").arg(error)), "plugin manager");
-		dlclose(mo);
+		unloadDLL(mo);
 		return;
 	}
 	(*demo)(ScApp, ScApp);
 	// FIXME: how is the menu organized? (*demo)(ScApp->scrActions[pluginMap[pluginID].actName], ScApp);
 	if (pda.type != 4 && pda.type != 5)
-		dlclose(mo);
+		unloadDLL(mo);
 	if (ScApp->HaveDoc)
 		ScApp->view->DrawNew();
 }
@@ -157,7 +233,7 @@
 QString PluginManager::callDLLForNewLanguage(int pluginID)
 {
 	void *mo;
-	const char *error;
+	bool unload = false;
 	struct PluginData pda;
 	pda = pluginMap[pluginID];
 	typedef QString (*sdem)();
@@ -168,40 +244,36 @@
 	if (pda.type != 4 && pda.type !=5)
 	{
 		plugDir += pda.pluginFile;
-		mo = dlopen(plugDir, RTLD_LAZY | RTLD_GLOBAL);
+		mo = loadDLL(plugDir);
 		if (!mo)
-		{
-			qDebug( tr("Cannot find plugin"), "plugin manager");
 			return QString::null;
-		}
+		unload = true;
 	}
 	else
 		mo = pda.index;
-	dlerror();
+
 	// Grab the menu string from the plugin again
-	demo = (sdem)dlsym(mo, "name");
-	if ((error = dlerror()) != NULL)
+	demo = (sdem) resolveSym(mo, "name");
+	if ( !demo )
 	{
-		qDebug( tr(QString("Cannot find symbol (%1)").arg(error)), "plugin manager");
-		//dlclose(mo);
+		if(unload) unloadDLL(mo);
 		return QString::null;
 	}
-	QString retVal=(*demo)();	
+	QString retVal= (*demo)();	
 	//If scripter, get it to update its scrActions.
 	if (pluginID==8)
 	{
-		dlerror();
-		demo0 = (sdem0)dlsym(mo, "languageChange");
-		if ((error = dlerror()) != NULL)
+		demo0 = (sdem0) resolveSym(mo, "languageChange");
+		if ( !demo0 )
 		{
-			dlclose(mo);
-			return false;
+			if(unload) unloadDLL(mo);
+			return QString::null;
 		}
 		(*demo0)();
 	}
 
 	if (pda.type != 4 && pda.type != 5)
-		dlclose(mo);
+		unloadDLL(mo);
 	return retVal;
 }
 
@@ -228,7 +300,6 @@
 bool PluginManager::DLLname(QString name, QString *pluginName, PluginType *type, void **index, int *idNr, QString *actName, QString *actKeySequence, QString *actMenu, QString *actMenuAfterName, bool *actEnabledOnStartup, bool loadPlugin)
 {
 	void *mo;
-	const char *error;
 	typedef QString (*sdem0)();
 	typedef PluginType (*sdem1)();
 	typedef void (*sdem2)(QWidget *d, ScribusApp *plug);
@@ -242,75 +313,69 @@
 	QString plugName = ScPaths::instance().pluginDir();
 	plugName += name;
 
-	mo = dlopen(plugName, RTLD_LAZY | RTLD_GLOBAL);
+	mo = loadDLL(plugName);
 	if (!mo)
 	{
-		qDebug( tr(QString("Error: %1").arg(dlerror())), "plugin manager");
 		return false;
 	}
-	dlerror();
-	demo = (sdem0)dlsym(mo, "name");
-	if ((error = dlerror()) != NULL)
+
+	demo = (sdem0) resolveSym(mo, "name");
+	if ( !demo )
 	{
-		dlclose(mo);
+		unloadDLL(mo);
 		return false;
 	}
 	*pluginName = (*demo)();
-	dlerror();
-	demo1 = (sdem1)dlsym(mo, "type");
-	if ((error = dlerror()) != NULL)
+	demo1 = (sdem1) resolveSym(mo, "type");
+	if ( !demo1 )
 	{
-		dlclose(mo);
+		unloadDLL(mo);
 		return false;
 	}
 	*type = (*demo1)();
 	*index = mo;
-	plugID = (sdemID)dlsym(mo, "ID");
-	if ((error = dlerror()) != NULL)
+	plugID = (sdemID) resolveSym(mo, "ID");
+	if ( !plugID)
 	{
-		dlclose(mo);
+		unloadDLL(mo);
 		return false;
 	}
 	*idNr = (*plugID)();
 	//ScrAction based plugins
 	if (*type == Persistent || *type == Standard || *type == Import)
 	{
-		demo = (sdem0)dlsym(mo, "actionName");
-		if ((error = dlerror()) != NULL)
+		demo = (sdem0) resolveSym(mo, "actionName");
+		if ( !demo )
 		{
-			dlclose(mo);
+			unloadDLL(mo);
 			return false;
 		}
 		*actName = (*demo)();
-		dlerror();
-		demo = (sdem0)dlsym(mo, "actionKeySequence");
-		if ((error = dlerror()) != NULL)
+		demo = (sdem0) resolveSym(mo, "actionKeySequence");
+		if ( !demo )
 		{
-			dlclose(mo);
+			unloadDLL(mo);
 			return false;
 		}
 		*actKeySequence = (*demo)();
-		dlerror();
-		demo = (sdem0)dlsym(mo, "actionMenu");
-		if ((error = dlerror()) != NULL)
+		demo = (sdem0) resolveSym(mo, "actionMenu");
+		if ( !demo )
 		{
-			dlclose(mo);
+			unloadDLL(mo);
 			return false;
 		}
 		*actMenu = (*demo)();
-		dlerror();
-		demo = (sdem0)dlsym(mo, "actionMenuAfterName");
-		if ((error = dlerror()) != NULL)
+		demo = (sdem0) resolveSym(mo, "actionMenuAfterName");
+		if ( !demo )
 		{
-			dlclose(mo);
+			unloadDLL(mo);
 			return false;
 		}
 		*actMenuAfterName = (*demo)();
-		dlerror();
-		demo3 = (sdem3)dlsym(mo, "actionEnabledOnStartup");
-		if ((error = dlerror()) != NULL)
+		demo3 = (sdem3) resolveSym(mo, "actionEnabledOnStartup");
+		if ( !demo3 )
 		{
-			dlclose(mo);
+			unloadDLL(mo);
 			return false;
 		}
 		*actEnabledOnStartup = (*demo3)();
@@ -324,16 +389,15 @@
 		*actEnabledOnStartup = false;
 	}
 	if (*type != Persistent && *type!= Type5)
-		dlclose(mo);
+		unloadDLL(mo);
 	else
 	{
 		if (loadPlugin)
 		{
-			dlerror();
-			demo2 = (sdem2)dlsym(mo, "initPlug");
-			if ((error = dlerror()) != NULL)
+			demo2 = (sdem2) resolveSym(mo, "initPlug");
+			if ( !demo2)
 			{
-				dlclose(mo);
+				unloadDLL(mo);
 				return false;
 			}
 			(*demo2)(ScApp, ScApp);
@@ -352,21 +416,16 @@
 
 void PluginManager::finalizePlug(int pluginID)
 {
-	const char *error;
 	struct PluginData pda;
 	typedef void (*sdem2)();
 	sdem2 demo2;
 	PluginData plug = pluginMap[pluginID];
 	if (plug.type == Persistent || plug.type == Type5)
 	{
-		dlerror();
-		demo2 = (sdem2)dlsym(plug.index, "cleanUpPlug");
-		if ((error = dlerror()) != NULL)
-		{
-			dlclose(plug.index);
-		}
-		else
+		demo2 = (sdem2) resolveSym(plug.index, "cleanUpPlug");
+		if ( demo2 )
 			(*demo2)();
+		unloadDLL(plug.index);
 	}
 }
 
@@ -403,6 +462,8 @@
 
 	//return "dylib";
 	return "so";
+#elif defined(_WIN32) || defined(_WIN64)
+	return "dll";
 #else
 	// Generic *NIX
 	return "so";
pluginmanager_platfindep.diff (9,399 bytes)   

2005-06-30 21:14

 

pluginmanager.h (3,620 bytes)   
#ifndef _PLUGIN_MANAGER_
#define _PLUGIN_MANAGER_

#include <qobject.h>
#include <qstring.h>
#include <qmap.h>
#include "scribus.h"

/**
 * \brief PluginManager handles plugin loading, unloading, and running.
 *
 * It contains methods and attributes for plugin running and its settings
 * and returning values.
 *
 * Derived from Franz's ScribusApp stuff (petr vanek)
 *
 */

class PluginManager : public QObject
{

	Q_OBJECT

public:

	/** \brief Human readable enumertion of the plugin types */
	// FIXME: what the hell is type5?
	enum PluginType {
		Persistent = 4,
		Import = 7,
		Standard = 6,
		Type5 = 5
	};

	/**
	 * \brief PluginData is structure for plugin related informations.
	 * \param pluginFile path to the share library (with name).
	 * \param name a string which will be shown at menu
	 * \param index black magic? FIXME
	 * \param type PluginType element
	 * \param menuID id for menu system
	 * \param actName name of the action for this plugin
	 * \param actKeySequence menu GUI key combination
	 * \param actMenu first level menu
	 * \param actMenuAfterName 2nd level menu
	 * \param actEnabledOnStartup run it at start FIXME
	 * \param loadPlugin enable or disable plugin for user
	 * \param loaded is the plug really loaded?
	 */

	struct PluginData
	{
		QString pluginFile;// Datei;
		QString name;
		void *index; //Zeiger;
		PluginType type;
		int menuID;
		QString actName;
		QString actMenuText;
		QString actKeySequence;
		QString actMenu;
		QString actMenuAfterName;
		bool actEnabledOnStartup;
		bool loadPlugin;
		bool loaded;
	};

	PluginManager();
	~PluginManager();

	// Static methods for loading, unloading plugins and resolving symbols
	// These methods are plateform independent but implemented in a plateform dependent way
	static void* loadDLL( QString plugin );
	static void* resolveSym( void* plugin, const char* sym );
	static void  unloadDLL( void* plugin );

	/*! \brief Ininitalization of all plugins. It's called at scribus start. */
	void initPlugs();

	/*! \brief Run plugin by its id from pluginMap */
	void callDLL(int pluginID);

	/*! \brief Runs plugin's languageChange() method, and returns main menu item text if one exists */	
	QString callDLLForNewLanguage(int pluginID);

	/*! \brief Checks if is the plug in plugin map.
	 * \return bool
	 */
	bool DLLexists(int pluginID);

	/*! unused/obsolete */
	void callDLLbyMenu(int pluginID);

	/*! \brief Reads available info and fills PluginData structure */
	bool DLLname(QString name, QString *pluginName, PluginType *type, void **index, int *idNr, QString *actName, QString *actKeySequence, QString *actMenu, QString *actMenuAfterName, bool *actEnabledOnStartup, bool loadPlugin);

	/*! \brief Shutdowns all plugins. Called at scribus quit */
	void finalizePlugs();

	/*! \brief Shutdowns one plugin.
	 * \param pluginID key from the pluginMap. Plugin identifier
	 */

	void finalizePlug(int pluginID);
	/** \brief Returns human readable plugin type */
	QString getPluginType(PluginType aType);
	/** \brief Saves plugin preferences */
	void savePreferences();

	/*! \brief Input variable to the plug. */
	QString dllInput;
	/*! \brief Returning variable from the plug. */
	QString dllReturn;

	/*! \brief Plugin mapping.
	 * Each plugin has its record key() -> PluginData */
	QMap<int, PluginData> pluginMap;

	/*! \brief Return file extension used for shared libs on this platform */
	static QCString platformDllExtension();

public slots:

	/*! not at all obsolete! */
	void callDLLBySlot(int pluginID);
	void languageChange();

private:

	/** \brief Configuration structure */
	PrefsContext* prefs;

};

#endif

pluginmanager.h (3,620 bytes)   

2005-06-30 21:46

 

scribus_platfindep.diff (3,429 bytes)   
Index: scribus.cpp
===================================================================
RCS file: /cvs/Scribus/scribus/scribus.cpp,v
retrieving revision 1.228.2.394
diff -u -r1.228.2.394 scribus.cpp
--- scribus.cpp	30 Jun 2005 16:06:10 -0000	1.228.2.394
+++ scribus.cpp	30 Jun 2005 23:39:58 -0000
@@ -33,8 +33,23 @@
 #include <cstdio>
 #include <cstdlib>
 #include <cmath>
+
+#ifdef _MSC_VER
+ #if (_MSC_VER >= 1200)
+  #include "win-config.h"
+ #endif
+#else
+ #include "config.h"
+#endif
+
+#ifdef HAVE_DLFCN_H
 #include <dlfcn.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
+
 #include <iostream>
 #include <signal.h>
 #include <string>
@@ -97,13 +112,6 @@
 #include "pageitemattributes.h"
 #include "tocindexprefs.h"
 #include "tocgenerator.h"
-#ifdef _MSC_VER
- #if (_MSC_VER >= 1200)
-  #include "win-config.h"
- #endif
-#else
- #include "config.h"
-#endif
 
 #include "fpoint.h"
 #include "fpointarray.h"
@@ -8640,22 +8648,20 @@
 
 PSLib* ScribusApp::getPSDriver(bool psart, SCFonts &AllFonts, QMap<QString,QFont> DocFonts, ColorList DocColors, bool pdf)
 {
-	const char *error;
 	typedef PSLib* (*sdem)(bool psart, SCFonts &AllFonts, QMap<QString,QFont> DocFonts, ColorList DocColors, bool pdf);
 	sdem demo;
 	QString pfad = QString("%1/libs/libpostscript.%3").arg(ScPaths::instance().libDir()).arg(PluginManager::platformDllExtension());
-	PSDriver = dlopen(pfad, RTLD_LAZY);
+	PSDriver = PluginManager::loadDLL(pfad);
 	if (!PSDriver)
 	{
 		std::cout << "Cannot find the Scribus PostScript library plugin" << endl;
 		return NULL;
 	}
-	dlerror();
-	demo = (sdem)dlsym(PSDriver, "Run");
-	if ((error = dlerror()) != NULL)
+	demo = (sdem) PluginManager::resolveSym(PSDriver, "Run");
+	if ( !demo )
 	{
 		std::cout << "Cannot find symbol" << endl;
-		dlclose(PSDriver);
+		PluginManager::unloadDLL(PSDriver);
 		return NULL;
 	}
 	PSLib *dia = (*demo)(psart, AllFonts, DocFonts, DocColors, pdf);
@@ -8664,7 +8670,7 @@
 
 void ScribusApp::closePSDriver()
 {
-	dlclose(PSDriver);
+	PluginManager::unloadDLL(PSDriver);
 }
 
 bool ScribusApp::DoSaveAsEps(QString fn)
@@ -8766,29 +8772,27 @@
 bool ScribusApp::getPDFDriver(QString fn, QString nam, int Components, std::vector<int> &pageNs, QMap<int,QPixmap> thumbs)
 {
 	bool ret = false;
-	const char *error;
 	void *PDFDriver;
 	typedef bool (*sdem)(ScribusApp *plug, QString fn, QString nam, int Components, std::vector<int> &pageNs, QMap<int,QPixmap> thumbs, QProgressBar *dia2);
 	sdem demo;
 	QString pfad = QString("%1/libs/libpdf.%3").arg(ScPaths::instance().libDir()).arg(PluginManager::platformDllExtension());
-	PDFDriver = dlopen(pfad, RTLD_NOW);
+	PDFDriver = PluginManager::loadDLL(pfad);
 	if (!PDFDriver)
 	{
 		std::cout << "Cannot find the Scribus PDF plugin" << endl;
 		return false;
 	}
-	dlerror();
-	demo = (sdem)dlsym(PDFDriver, "Run");
-	if ((error = dlerror()) != NULL)
+	demo = (sdem) PluginManager::resolveSym(PDFDriver, "Run");
+	if( !demo )
 	{
 		std::cout << "Cannot find symbol" << endl;
-		dlclose(PDFDriver);
+		PluginManager::unloadDLL(PDFDriver);
 		return false;
 	}
 	fileWatcher->forceScan();
 	fileWatcher->stop();
 	ret = (*demo)(this, fn, nam, Components, pageNs, thumbs, mainWindowProgressBar);
-	dlclose(PDFDriver);
+	PluginManager::unloadDLL(PDFDriver);
 	fileWatcher->start();
 	return ret;
 }
scribus_platfindep.diff (3,429 bytes)   

jghali

2005-06-30 21:53

administrator   ~0005297

I have uploaded the new plugin manager diff and the new scribus diff so you can test it. The pluginmanager.h as been uploaded separately 'cause the one on CVS has bad new lines (CR - CR - LF ). It's maybe the reason why the first diff failed.

So, as decided, the PluginManager class has three new static methods :
static void* loadDLL( QString plugin );
static void* resolveSym( void* plugin, const char* sym );
static void unloadDLL( void* plugin );
For each I provided dlfcn, win32, and QLibrary implementation. Error messages are handled inside the functions.

It's now my turn to go to bed. It's nearly 2.00 AM.

ringerc

2005-07-01 11:27

reporter   ~0005314

That works great here ; no problems at all.

Andreas, any chance of testing on Mac OS X? You need to apply pluginmanager_platfindep.diff and scribus_platfindep.diff then replace pluginmanager.h with the supplied one.

By the way, a diff will be fine for pluginmanager.h in future, I fixed the line endings.

ringerc

2005-07-01 11:33

reporter   ~0005315

Reminder sent to: avox

Andreas, just adding you to the monitor list on this bug.

Any chance of working this into your next build and seeing how it behaves? should be fuss-free, since it'll use dlcompat on Mac OS X just like before.

If it all works out I'll convert gettext to use this too.

ringerc

2005-07-01 12:48

reporter   ~0005316

avox ringerc: Scribus works with QLibrary patch. I didn't reconfigure tho. Is HAVE_DLFCN_H set by default?
ringerc on Mac OS X, it should be. check config.h to confirm, though.
ringerc Glad to hear it works too.... clears the way to merge it for 1.3.0 or maybe just after, depending on what the others say. Then I can get on to my plugin api work.
avox Yep

ringerc

2005-07-01 13:10

reporter   ~0005317

Applied to 1.3cvs . Thanks Jean!

Issue History

Date Modified Username Field Change
2005-06-30 11:34 jghali New Issue
2005-06-30 11:34 jghali File Added: qlibrary_plugins_13x.diff
2005-06-30 13:06 ringerc Status new => assigned
2005-06-30 13:06 ringerc Assigned To => ringerc
2005-06-30 13:28 ringerc Note Added: 0005271
2005-06-30 13:31 ringerc Note Edited: 0005271
2005-06-30 13:37 jghali Note Added: 0005272
2005-06-30 13:53 jghali Note Added: 0005273
2005-06-30 14:01 ringerc Note Added: 0005274
2005-06-30 14:07 ringerc Note Added: 0005275
2005-06-30 14:21 jghali Note Added: 0005276
2005-06-30 14:28 jghali Note Added: 0005277
2005-06-30 14:37 jghali Note Added: 0005278
2005-06-30 14:38 jghali File Added: pluginmanager_qlib_13x.diff
2005-06-30 14:38 jghali Note Added: 0005279
2005-06-30 15:04 ringerc Note Added: 0005281
2005-06-30 15:04 ringerc File Added: plugins_to_qlibrary.diff
2005-06-30 15:05 ringerc Note Added: 0005282
2005-06-30 15:07 ringerc Note Added: 0005283
2005-06-30 15:12 cbradney Note Added: 0005284
2005-06-30 16:25 ringerc Note Added: 0005287
2005-06-30 16:26 ringerc File Deleted: qlibrary_plugins_13x.diff
2005-06-30 16:26 ringerc File Deleted: pluginmanager_qlib_13x.diff
2005-06-30 16:26 ringerc Note Added: 0005288
2005-06-30 16:28 jghali Note Added: 0005289
2005-06-30 16:38 ringerc Note Added: 0005290
2005-06-30 16:52 jghali Note Added: 0005292
2005-06-30 16:52 jghali Note Edited: 0005292
2005-06-30 16:56 ringerc Note Added: 0005293
2005-06-30 16:57 ringerc Note Added: 0005294
2005-06-30 21:14 jghali File Added: pluginmanager_platfindep.diff
2005-06-30 21:14 jghali File Added: pluginmanager.h
2005-06-30 21:46 jghali File Added: scribus_platfindep.diff
2005-06-30 21:53 jghali Note Added: 0005297
2005-07-01 11:27 ringerc Note Added: 0005314
2005-07-01 11:29 ringerc Severity tweak => minor
2005-07-01 11:29 ringerc Summary Provide QLibrary based plugin management => Platform independent library loading
2005-07-01 11:33 ringerc Note Added: 0005315
2005-07-01 12:48 ringerc Note Added: 0005316
2005-07-01 13:10 ringerc Status assigned => resolved
2005-07-01 13:10 ringerc Fixed in Version => 1.3.0cvs
2005-07-01 13:10 ringerc Resolution open => fixed
2005-07-01 13:10 ringerc Note Added: 0005317
2005-07-03 09:17 cbradney Status resolved => closed
2005-07-06 04:42 ringerc Relationship added child of 0000015