Warning, /education/labplot/src/doc/plugins.dox is written in an unsupported language. File is not indexed.
0001 /**\page plugins Plugins 0002 0003 0004 \section Plugins based on Qt's plugin system 0005 0006 This article is meant to explain the inner workings of the plugin system used in the backend to a degree where it completely loses any 'mystic aura'. 'Plugin system' may sound like something complicated, but it really isn't. All it takes is to know how to build and link libraries and to understand two macros (and to know how to use another two for implementing plugins). 0007 0008 \section How do Qt plugins work? 0009 0010 A Qt plugin is basically a library which uses a standardized way to access the so-called root component object, a normal C++ object which inherits from QObject. Once you have this root object, you use qobject_cast to check which of your predefined plugin interfaces it implements. See 'Q_DECLARE_INTERFACE' and 'Q_INTERFACES' in the Qt documentation for details. In short, these two macros register your interfaces (i.e., abstract C++ classes) to Qt's meta object system. 0011 0012 Such a library can be statically or dynamically linked into the application. 0013 0014 To understand how the plugin system works internally, one has to look at the involved macros defined in qplugin.h (to be found in /src/corelib/plugin in the official source archive): 0015 0016 @code 0017 Q_EXPORT_PLUGIN2 0018 @endcode 0019 and 0020 @code 0021 Q_IMPORT_PLUGIN 0022 @endcode 0023 . 0024 0025 These macros are different based on whether 'QT_STATICPLUGIN' is defined or not. Important to note here is that 'static plugin' does not mean statically linked but that there is a static (using the 'static' C++ keyword) object involved. Static plugins can also be linked as dynamic libraries. The difference to a dynamic plugin is that the application will not start if a static plugin is missing, it will run without dynamic plugins though. Since being optional is basically the whole point of plugins, static plugins are usually only used to unify the interface to mandatory and optional components. 0026 0027 \section Declaring a plugin: Q_EXPORT_PLUGIN2 0028 0029 The 'Q_EXPORT_PLUGIN2' macro is responsible for declaring the necessary code to access the plugin. It is defined in the code implementing the plugin. 0030 0031 For static plugins the 'Q_EXPORT_PLUGIN2(PLUGIN, PLUGINCLASS)' macro expands to roughly this (somewhat simplified): 0032 @code 0033 QObject *qt_plugin_instance_PLUGIN() 0034 { 0035 static QPointer _instance; 0036 if (!_instance) 0037 _instance = new PLUGINCLASS; 0038 return _instance; 0039 } 0040 @endcode 0041 So, basically, you have a static instance of the root object and a function named using a standard prefix followed by the plugin name to get a pointer to this instance. 0042 BTW: In this case (i.e., with 'QT_STATICPLUGIN' defined), 'Q_EXPORT_STATIC_PLUGIN2(PLUGIN, PLUGINCLASS)' is exactly the same as 'Q_EXPORT_PLUGIN2(PLUGIN, PLUGINCLASS)'. 0043 0044 For dynamic plugins, 'Q_EXPORT_PLUGIN2(PLUGIN, PLUGINCLASS)' expands to (also somewhat simplified): 0045 @code 0046 extern "C" { 0047 QObject * qt_plugin_instance(); 0048 { 0049 static QPointer _instance; 0050 if (!_instance) 0051 _instance = new PLUGINCLASS; 0052 return _instance; 0053 } 0054 } 0055 @endcode 0056 So it boils down to defining the root object access function as 'extern 'C''. In addition, a function called 'qt_plugin_query_verification_data()' is defined which is used to check whether the plugin is compatible with the application its loaded in (same Qt version etc.). 0057 BTW: 'Q_EXPORT_STATIC_PLUGIN2(PLUGIN, PLUGINCLASS)' does nothing if 'QT_STATICPLUGIN' is not defined. 0058 0059 \section Using static plugins: Q_IMPORT_PLUGIN 0060 0061 The 'Q_IMPORT_PLUGIN(PLUGIN)' macro, which is used in the code using the static plugin, expands to the following: 0062 @code 0063 extern QObject *qt_plugin_instance_##PLUGIN(); 0064 class Static##PLUGIN##PluginInstance { 0065 public: 0066 Static##PLUGIN##PluginInstance() { 0067 qRegisterStaticPluginInstanceFunction(qt_plugin_instance_##PLUGIN); 0068 } 0069 }; 0070 static Static##PLUGIN##PluginInstance static##PLUGIN##Instance; 0071 @endcode 0072 This is the static object I was talking about at the beginning. It is created during the static initialization of the application and registers the plugin root object access function to a global list. This list is used by 'static QObjectList QPluginLoader::staticInstances()' which returns all plugin root component objects. 0073 0074 The simplest way to make your static plugin available via 'QPluginLoader::staticInstances()' therefore is: 0075 @code 0076 #define QT_STATICPLUGIN 0077 Q_EXPORT_PLUGIN2(scidavis_standardcurvesymbolfactory, StandardCurveSymbolFactory) 0078 Q_IMPORT_PLUGIN(scidavis_standardcurvesymbolfactory) 0079 @endcode 0080 Together with 'Q_DECLARE_INTERFACE' and 'Q_INTERFACES' that's all it takes to define a static plugin. 0081 0082 \section Using dynamic plugins: QPluginLoader/PluginManager 0083 0084 As mentioned above, static plugins must be present for the application to run. They are completely normal library dependencies of the executable. Dynamic plugins are what plugins really should be: optional functionality which can be added at runtime. They are always compiled as dynamic libraries and then loaded at runtime by 'QPluginLoader' (no 'Q_IMPORT_PLUGIN' involved here). 'QPluginLoader' is well documented in the Qt docs, so I won't go into detail here, there is no need to know it anyway, neither when writing plugins nor building the application. 0085 0086 There exists a class called 'PluginManager' in the backend which encapsulates the whole usage of 'QPluginLoader'. All you need to do is call 'PluginManager::plugins()' which works like 'QPluginLoader::staticInstances()' but also includes all dynamically loaded plugins. You can enable and disable plugins permanently (or at least until someone deletes the application config file because QSettings are used to store the list of enabled plugins) by calling 'PluginManager::enablePlugin()' or 'PluginManager::disablePlugin()', respectively. 0087 0088 0089 */