diff options
Diffstat (limited to 'templates/kcm_module_stub.cpp.cmake')
-rw-r--r-- | templates/kcm_module_stub.cpp.cmake | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/templates/kcm_module_stub.cpp.cmake b/templates/kcm_module_stub.cpp.cmake new file mode 100644 index 0000000..91536c7 --- /dev/null +++ b/templates/kcm_module_stub.cpp.cmake @@ -0,0 +1,151 @@ +/* + * pykcm_launcher.cpp + * + * Launch Control Centre modules written in Python using an embedded Python + * interpreter. + * Based on David Boddie's PyTDE-components. + */ + +// pythonize.h must be included first. +#include <pythonize.h> +#include <tdecmodule.h> +#include <tdeglobal.h> +#include <tdelocale.h> +#include <klibloader.h> +#include <kstandarddirs.h> +#include <ksimpleconfig.h> +#include <tqstring.h> +#include <sip-tqt.h> + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif // _GNU_SOURCE +#include <dlfcn.h> + +#define MODULE_DIR "@_MODULEDIR_@" +#define EXTRA_MODULE_DIR "@_EXTRAMODULE_@" +#define MODULE_NAME "@_MODULENAME_@" +#define FACTORY "@_FACTORYFUNCTION_@" +#define CPP_FACTORY @_FACTORYFUNCTION_@ +#define debug 1 + +static TDECModule *report_error(const char *msg) { + if (debug) printf ("error: %s\n", msg); + return NULL; +} + +static TDECModule* return_instance( TQWidget *parent, const char *name ) { + TDECModule* tdecmodule; + PyObject *pyTDECModuleTuple; + PyObject *pyTDECModule; + Pythonize *pyize; // Pythonize object to manage the Python interpreter. + + // Try to determine what py script we're loading. Note that "name" + // typically appears to be NULL. + TQString script(MODULE_NAME); + + // Reload this module, but this time tell the runtime linker to make the + // symbols global and available for later loaded libraries/module. + Dl_info info; + if (!dladdr((const void *)(&return_instance), &info) || !info.dli_fname || !dlopen(info.dli_fname, RTLD_GLOBAL|RTLD_NOW)) { + return report_error ("***Unable to export symbols\n"); + } + + // Start the interpreter. + pyize = initialize(); + if (!pyize) { + return report_error ("***Failed to start interpreter\n"); + } + + // Add the path to the python script to the interpreter search path. + TQString path = TQString(MODULE_DIR); + if(path == TQString::null) { + return report_error ("***Failed to locate script path"); + } + if(!pyize->appendToSysPath (path.latin1 ())) { + return report_error ("***Failed to set sys.path\n"); + } + + // Add the extra path to the python script to the interpreter search path. + TQString extrapath = TQString(EXTRA_MODULE_DIR); + if(!pyize->appendToSysPath (extrapath.latin1 ())) { + return report_error ("***Failed to set extra sys.path\n"); + } + + // Load the Python script. + PyObject *pyModule = pyize->importModule ((char *)script.latin1 ()); + if(!pyModule) { + PyErr_Print(); + return report_error ("***failed to import module\n"); + } + + // Inject a helper function + TQString bridge = TQString("import sip_tqt\n" + "from PyTQt import tqt\n" + "def kcontrol_bridge_" FACTORY "(parent,name):\n" + " if parent!=0:\n" + " wparent = sip_tqt.wrapinstance(parent,tqt.TQWidget)\n" + " else:\n" + " wparent = None\n" + " inst = " FACTORY "(wparent, name)\n" + " return (inst,sip_tqt.unwrapinstance(inst))\n"); + PyRun_String(bridge.latin1(),Py_file_input,PyModule_GetDict(pyModule),PyModule_GetDict(pyModule)); + + // Get the Python module's factory function. + PyObject *kcmFactory = pyize->getNewObjectRef(pyModule, "kcontrol_bridge_" FACTORY); + if(!kcmFactory) { + return report_error ("***failed to find module factory\n"); + } + + // Call the factory function. Set up the args. + PyObject *pyParent = PyLong_FromVoidPtr(parent); + PyObject *pyName = PyBytes_FromString(MODULE_NAME); + // Using NN here is effect gives our references to the arguement away. + PyObject *args = Py_BuildValue ("NN", pyParent, pyName); + if(pyName && pyParent && args) { + // run the factory function + pyTDECModuleTuple = pyize->runFunction(kcmFactory, args); + if(!pyTDECModuleTuple) { + PyErr_Print(); + return report_error ("*** runFunction failure\n;"); + } + } else { + return report_error ("***failed to create args\n"); + } + // cleanup a bit + pyize->decref(args); + pyize->decref(kcmFactory); + + // Stop this from getting garbage collected. + Py_INCREF(PyTuple_GET_ITEM(pyTDECModuleTuple,0)); + + // convert the TDECModule PyObject to a real C++ TDECModule *. + pyTDECModule = PyTuple_GET_ITEM(pyTDECModuleTuple,1); + tdecmodule = (TDECModule *)PyLong_AsVoidPtr(pyTDECModule); + if(!tdecmodule) { + return report_error ("***failed sip-tqt conversion to C++ pointer\n"); + } + pyize->decref(pyTDECModuleTuple); + + // PyTDE can't run the module without this - Pythonize + // grabs the lock at initialization and we have to give + // it back before exiting. At this point, we no longer need + // it. + //pyize->releaseLock (); + + // take care of any translation info + TDEGlobal::locale()->insertCatalogue(script); + + // Return the pointer to our new TDECModule + return tdecmodule; +} + +extern "C" +{ + // Factory function that kcontrol will call. + KDE_EXPORT TDECModule* CPP_FACTORY(TQWidget *parent, const char *name) + { + return return_instance(parent, name); + } +} + |