src/python.cc (raw)
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 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- #include "python.hh" #include "openbox.hh" #include <vector> #include <algorithm> namespace ob { typedef std::vector<PyObject*> FunctionList; static FunctionList callbacks[OBActions::NUM_ACTIONS]; static FunctionList bindfuncs; bool python_register(int action, PyObject *callback) { if (action < 0 || action >= OBActions::NUM_ACTIONS) { PyErr_SetString(PyExc_AssertionError, "Invalid action type."); return false; } if (!PyCallable_Check(callback)) { PyErr_SetString(PyExc_AssertionError, "Invalid callback function."); return false; } FunctionList::iterator it = std::find(callbacks[action].begin(), callbacks[action].end(), callback); if (it == callbacks[action].end()) { // not already in there Py_XINCREF(callback); // Add a reference to new callback callbacks[action].push_back(callback); } return true; } bool python_preregister(int action, PyObject *callback) { if (action < 0 || action >= OBActions::NUM_ACTIONS) { PyErr_SetString(PyExc_AssertionError, "Invalid action type."); return false; } if (!PyCallable_Check(callback)) { PyErr_SetString(PyExc_AssertionError, "Invalid callback function."); return false; } FunctionList::iterator it = std::find(callbacks[action].begin(), callbacks[action].end(), callback); if (it == callbacks[action].end()) { // not already in there Py_XINCREF(callback); // Add a reference to new callback callbacks[action].insert(callbacks[action].begin(), callback); } return true; } bool python_unregister(int action, PyObject *callback) { if (action < 0 || action >= OBActions::NUM_ACTIONS) { PyErr_SetString(PyExc_AssertionError, "Invalid action type."); return false; } if (!PyCallable_Check(callback)) { PyErr_SetString(PyExc_AssertionError, "Invalid callback function."); return false; } FunctionList::iterator it = std::find(callbacks[action].begin(), callbacks[action].end(), callback); if (it != callbacks[action].end()) { // its been registered before Py_XDECREF(*it); // Dispose of previous callback callbacks[action].erase(it); } return true; } bool python_unregister_all(int action) { if (action < 0 || action >= OBActions::NUM_ACTIONS) { PyErr_SetString(PyExc_AssertionError, "Invalid action type."); return false; } while (!callbacks[action].empty()) { Py_XDECREF(callbacks[action].back()); callbacks[action].pop_back(); } return true; } void python_callback(OBActions::ActionType action, Window window, OBWidget::WidgetType type, unsigned int state, long d1, long d2, long d3, long d4) { PyObject *arglist; PyObject *result; assert(action >= 0 && action < OBActions::NUM_ACTIONS); if (d4 != LONG_MIN) arglist = Py_BuildValue("iliillll", action, window, type, state, d1, d2, d3, d4); else if (d3 != LONG_MIN) arglist = Py_BuildValue("iliilll", action, window, type, state, d1, d2, d3); else if (d2 != LONG_MIN) arglist = Py_BuildValue("iliill", action, window, type, state, d1, d2); else if (d1 != LONG_MIN) arglist = Py_BuildValue("iliil", action, window, type, state, d1); else arglist = Py_BuildValue("ilii", action, window, type, state); FunctionList::iterator it, end = callbacks[action].end(); for (it = callbacks[action].begin(); it != end; ++it) { // call the callback result = PyEval_CallObject(*it, arglist); if (result) { Py_DECREF(result); } else { // an exception occured in the script, display it PyErr_Print(); } } Py_DECREF(arglist); } bool python_bind(PyObject *keylist, PyObject *callback) { if (!PyList_Check(keylist)) { PyErr_SetString(PyExc_AssertionError, "Invalid keylist. Not a list."); return false; } if (!PyCallable_Check(callback)) { PyErr_SetString(PyExc_AssertionError, "Invalid callback function."); return false; } OBBindings::StringVect vectkeylist; for (int i = 0, end = PyList_Size(keylist); i < end; ++i) { PyObject *str = PyList_GetItem(keylist, i); if (!PyString_Check(str)) { PyErr_SetString(PyExc_AssertionError, "Invalid keylist. It must contain only strings."); return false; } vectkeylist.push_back(PyString_AsString(str)); } // the id is what the binding class can call back with so it doesnt have to // worry about the python function pointer int id = bindfuncs.size(); if (Openbox::instance->bindings()->add(vectkeylist, id)) { Py_XINCREF(callback); // Add a reference to new callback bindfuncs.push_back(callback); return true; } else { PyErr_SetString(PyExc_AssertionError,"Unable to create binding. Invalid."); return false; } } bool python_unbind(PyObject *keylist) { if (!PyList_Check(keylist)) { PyErr_SetString(PyExc_AssertionError, "Invalid keylist. Not a list."); return false; } OBBindings::StringVect vectkeylist; for (int i = 0, end = PyList_Size(keylist); i < end; ++i) { PyObject *str = PyList_GetItem(keylist, i); if (!PyString_Check(str)) { PyErr_SetString(PyExc_AssertionError, "Invalid keylist. It must contain only strings."); return false; } vectkeylist.push_back(PyString_AsString(str)); } int id; if ((id = Openbox::instance->bindings()->remove(vectkeylist)) >= 0) { assert(bindfuncs[id]); // shouldn't be able to remove it twice Py_XDECREF(bindfuncs[id]); // Dispose of previous callback // important note: we don't erase the item from the list cuz that would // ruin all the id's that are in use. simply nullify it. bindfuncs[id] = 0; return true; } return false; } bool python_unbind_all() { Openbox::instance->bindings()->remove_all(); return true; } } |