summaryrefslogtreecommitdiffstats
path: root/wineconfig/kcm_wineconfig.cpp
blob: bfd9217c3bdc01b9556b8e6b503508dddd2d17c7 (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
152
153
154
155
156

/*
 * pykcm_launcher.cpp
 * 
 * Launch Control Centre modules written in Python using an embedded Python
 * interpreter.
 * Based on David Boddie's PyKDE-components.
 */

// pythonize.h must be included first.
#include <pythonize.h>
#include <kcmodule.h>
#include <kglobal.h>
#include <klocale.h>
#include <klibloader.h>
#include <kstandarddirs.h>
#include <ksimpleconfig.h>
#include <qstring.h>
#include <sip.h>

#define MODULE_DIR "/opt/kde3/share/apps/guidance"
#define EXTRA_MODULE_DIR "/opt/kde3/share/python-support/kde-guidance-kde3"
#define EXTRA_MODULE_DIR_TWO "/opt/kde3/share/python-support/guidance-backends-kde3"
#define EXTRA_MODULE_DIR_THREE "/opt/kde3/share/python-support/kde-guidance-powermanager-kde3"
#define MODULE_NAME "wineconfig"
#define FACTORY "create_wineconfig"
#define CPP_FACTORY create_wineconfig
#define LIB_PYTHON "libpython2.5.so"
#define debug 1

static KCModule *report_error(char *msg) {
    if (debug) printf ("error: %s\n", msg);
    return NULL;
}

static KCModule* return_instance( QWidget *parent, const char *name ) {
    KCModule* kcmodule;
    PyObject *pyKCModuleTuple; 
    PyObject *pyKCModule;
    Pythonize *pyize;  // Pythonize object to manage the Python interpreter.
    int isErr;
    
    // Try to determine what py script we're loading. Note that "name"
    // typically appears to be NULL.
    QString script(MODULE_NAME);

    // Reload libpython, but this time tell the runtime linker to make the
    // symbols global and available for later loaded libraries/module.
    KLibLoader::self()->globalLibrary(LIB_PYTHON);
    
    // 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.
    QString path = QString(MODULE_DIR);
    if(path == QString::null) {
        return report_error ("***Failed to locate script path");
    }
    if(!pyize->appendToSysPath (path.latin1 ())) {
        return report_error ("***Failed to set sys.path\n");
    }
    QString extrapath = QString(EXTRA_MODULE_DIR);
    if(!pyize->appendToSysPath (extrapath.latin1 ())) {
        return report_error ("***Failed to set extra sys.path\n");
    }
    QString extrapath_two = QString(EXTRA_MODULE_DIR_TWO);
    if(!pyize->appendToSysPath (extrapath_two.latin1 ())) {
        return report_error ("***Failed to set extra 2 sys.path\n");
    }
    QString extrapath_three = QString(EXTRA_MODULE_DIR_THREE);
    if(!pyize->appendToSysPath (extrapath_three.latin1 ())) {
        return report_error ("***Failed to set extra 3 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
    QString bridge = QString("import sip\n" 
                            "import qt\n"
                            "def kcontrol_bridge_" FACTORY "(parent,name):\n"
                             "    if parent!=0:\n"
#if SIP_VERSION >= 0x040200
                             "        wparent = sip.wrapinstance(parent,qt.QWidget)\n"
#else                             
                             "        wparent = sip.wrapinstance(parent,'QWidget')\n"
#endif
                             "    else:\n"
                             "        wparent = None\n"
                             "    inst = " FACTORY "(wparent, name)\n"
                             "    return (inst,sip.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 = PyString_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
        pyKCModuleTuple = pyize->runFunction(kcmFactory, args);
        if(!pyKCModuleTuple) {
            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(pyKCModuleTuple,0));
    
    // convert the KCModule PyObject to a real C++ KCModule *.
    isErr = 0;
    pyKCModule = PyTuple_GET_ITEM(pyKCModuleTuple,1);
    kcmodule = (KCModule *)PyLong_AsVoidPtr(pyKCModule);
    if(!kcmodule) {
        return report_error ("***failed sip conversion to C++ pointer\n");
    }
    pyize->decref(pyKCModuleTuple);
    
    // PyKDE 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
    KGlobal::locale()->insertCatalogue(script);

    // Return the pointer to our new KCModule
    return kcmodule;
}

extern "C" {
    // Factory function that kcontrol will call.
    KCModule* CPP_FACTORY(QWidget *parent, const char *name) {
        return return_instance(parent, name);
    }
}