You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tde-guidance/templates/kcm_module_stub.cpp.cmake

152 lines
5.1 KiB

/*
* 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.
TDE_EXPORT TDECModule* CPP_FACTORY(TQWidget *parent, const char *name)
{
return return_instance(parent, name);
}
}