summaryrefslogtreecommitdiffstats
path: root/templates/kcm_module_stub.cpp.cmake
blob: 584ac73d37470ec33f83030a18ca360a615d3449 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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.
    TDE_EXPORT TDECModule* CPP_FACTORY(TQWidget *parent, const char *name)
    {
        return return_instance(parent, name);
    }
}