]> icculus.org git repositories - mikachu/openbox.git/blob - c/hooks.c
kill the const
[mikachu/openbox.git] / c / hooks.c
1 #include "hooks.h"
2 #include <Python.h>
3 #include <glib.h>
4
5 /* the 'hooks' module and its dictionary */
6 static PyObject *hooks = NULL, *hooksdict = NULL;
7
8 /*
9  *
10  * Define the type 'Hook'
11  *
12  */
13 #define IS_HOOK(v)  ((v)->ob_type == &HookType)
14
15 staticforward PyTypeObject HookType;
16
17 typedef struct {
18     PyObject_HEAD
19     GSList *funcs;
20 } HookObject;
21
22 static PyObject *create_Hook(PyObject *self, PyObject *args)
23 {
24     HookObject *hook;
25     char *name;
26     int ret;
27
28     (void) self;
29
30     if (!PyArg_ParseTuple(args, "s:Hook", &name))
31         return NULL;
32
33     hook = PyObject_New(HookObject, &HookType);
34     hook->funcs = NULL;
35
36     /* add it to the hooks module */
37     ret = PyDict_SetItemString(hooksdict, name, (PyObject*) hook);
38     Py_DECREF(hook);
39
40     if (ret == -1) {
41         char *s = g_strdup_printf(
42             "Failed to add the hook '%s' to the 'hooks' module", name);
43         PyErr_SetString(PyExc_RuntimeError, s);
44         g_free(s);
45         return NULL;
46     }
47      
48     Py_INCREF(Py_None);
49     return Py_None;
50 }
51
52 static void hook_dealloc(HookObject *self)
53 {
54     GSList *it;
55
56     for (it = self->funcs; it != NULL; it = it->next)
57         Py_DECREF((PyObject*) it->data);
58      
59     PyObject_Del((PyObject*) self);
60 }
61
62 static PyObject *hook_fire(HookObject *self, PyObject *args)
63 {
64     GSList *it;
65
66     if (!IS_HOOK(self)) {
67         PyErr_SetString(PyExc_TypeError,
68                         "descriptor 'fire' requires a 'Hook' object");
69         return NULL;
70     }
71
72     for (it = self->funcs; it != NULL; it = it->next) {
73         PyObject *ret = PyObject_CallObject(it->data, args);
74         if (ret == NULL)
75             return NULL;
76         Py_DECREF(ret);
77     }
78
79     Py_INCREF(Py_None);
80     return Py_None;
81 }
82
83 static PyObject *hook_add(HookObject *self, PyObject *args)
84 {
85     PyObject *func;
86      
87     if (!IS_HOOK(self)) {
88         PyErr_SetString(PyExc_TypeError,
89                         "descriptor 'add' requires a 'Hook' object");
90         return NULL;
91     }
92     if (!PyArg_ParseTuple(args, "O:add", &func))
93         return NULL;
94     if (!PyCallable_Check(func)) {
95         PyErr_SetString(PyExc_TypeError,
96                         "descriptor 'add' requires a callable argument");
97         return NULL;
98     }
99     self->funcs = g_slist_append(self->funcs, func);
100     Py_INCREF(func);
101
102     Py_INCREF(Py_None);
103     return Py_None;
104 }
105
106 static PyObject *hook_remove(HookObject *self, PyObject *args)
107 {
108     PyObject *func;
109     GSList *it;
110      
111     if (!IS_HOOK(self)) {
112         PyErr_SetString(PyExc_TypeError,
113                         "descriptor 'remove' requires a 'Hook' object");
114         return NULL;
115     }
116     if (!PyArg_ParseTuple(args, "O:remove", &func))
117         return NULL;
118     if (!PyCallable_Check(func)) {
119         PyErr_SetString(PyExc_TypeError,
120                         "descriptor 'remove' requires a callable argument");
121         return NULL;
122     }
123     it = g_slist_find(self->funcs, func);
124     if (it != NULL) {
125         self->funcs = g_slist_delete_link(self->funcs, it);
126         Py_DECREF(func);
127
128         Py_INCREF(Py_None);
129         return Py_None;
130     }
131     PyErr_SetString(PyExc_TypeError,
132                     "given callable object was not found in Hook");
133     return NULL;
134 }
135
136 static PyObject *hook_count(HookObject *self, PyObject *args)
137 {
138     if (!IS_HOOK(self)) {
139         PyErr_SetString(PyExc_TypeError,
140                         "descriptor 'fire' requires a 'Hook' object");
141         return NULL;
142     }
143     if (!PyArg_ParseTuple(args, ":count"))
144         return NULL;
145
146     return PyInt_FromLong(g_slist_length(self->funcs));
147 }
148
149 static PyTypeObject HookType = {
150     PyObject_HEAD_INIT(NULL)
151     0,
152     "Hook",
153     sizeof(HookObject),
154     0,
155     (destructor) hook_dealloc, /*tp_dealloc*/
156     0,                         /*tp_print*/
157     0,                         /*tp_getattr*/
158     0,                         /*tp_setattr*/
159     0,                         /*tp_compare*/
160     0,                         /*tp_repr*/
161     0,                         /*tp_as_number*/
162     0,                         /*tp_as_sequence*/
163     0,                         /*tp_as_mapping*/
164     0,                         /*tp_hash */
165 };
166
167 static PyMethodDef HookMethods[] = {
168     {"fire", (PyCFunction)hook_fire, METH_VARARGS,
169      "hook.fire() -- Fire the added hook functions for the Hook."},
170     {"add", (PyCFunction)hook_add, METH_VARARGS,
171      "hook.add(func) -- Add a function to the hook." },
172     {"remove", (PyCFunction)hook_remove, METH_VARARGS,
173      "hook.remove(func) -- Remove a function from the hook." },
174     {"count", (PyCFunction)hook_count, METH_VARARGS,
175      "hook.count() -- Return the number of functions in the hook." },
176      
177     { NULL, NULL, 0, NULL }
178 };
179
180
181 /*
182  *
183  * Module initialization/finalization
184  *
185  */
186
187 /* the "events" hook */
188 static HookObject *events_hook = NULL, *keyboard_hook = NULL,
189     *pointer_hook = NULL;
190
191 static PyMethodDef HooksMethods[] = {
192     {"create", create_Hook, METH_VARARGS,
193      "hooks.create('name') -- Add a hook called 'name' to the hooks module."},
194      
195     { NULL, NULL, 0, NULL }
196 };
197
198 void hooks_startup()
199 {
200     int ret;
201
202     HookType.ob_type = &PyType_Type;
203     HookType.tp_methods = HookMethods;
204     PyType_Ready(&HookType);
205
206     Py_InitModule("hooks", HooksMethods);
207
208     /* get the hooks module/dict */
209     hooks = PyImport_ImportModule("hooks"); /* new */
210     g_assert(hooks != NULL);
211     hooksdict = PyModule_GetDict(hooks); /* borrowed */
212     g_assert(hooksdict != NULL);
213
214     /* create the "events" hook */
215     events_hook = PyObject_New(HookObject, &HookType);
216     events_hook->funcs = NULL;
217
218     /* add it to the hooks module */
219     ret = PyDict_SetItemString(hooksdict, "events", (PyObject*) events_hook);
220     g_assert(ret == 0);
221
222     /* create the "keyboard" hook */
223     keyboard_hook = PyObject_New(HookObject, &HookType);
224     keyboard_hook->funcs = NULL;
225
226     /* add it to the hooks module */
227     ret = PyDict_SetItemString(hooksdict, "keyboard",
228                                (PyObject*) keyboard_hook);
229     g_assert(ret == 0);
230
231     /* create the "pointer" hook */
232     pointer_hook = PyObject_New(HookObject, &HookType);
233     pointer_hook->funcs = NULL;
234
235     /* add it to the hooks module */
236     ret = PyDict_SetItemString(hooksdict, "pointer", (PyObject*) pointer_hook);
237     g_assert(ret == 0);
238 }
239
240 void hooks_shutdown()
241 {
242     Py_DECREF(pointer_hook);
243     Py_DECREF(keyboard_hook);
244     Py_DECREF(events_hook);
245     Py_DECREF(hooks);
246 }
247
248 void hooks_fire(EventData *data)
249 {
250     PyObject *ret, *args;
251
252     g_assert(events_hook != NULL);
253
254     args = Py_BuildValue("(O)", data);
255     ret = hook_fire(events_hook, args);
256     Py_DECREF(args);
257     if (ret == NULL)
258         PyErr_Print();
259 }
260
261 void hooks_fire_keyboard(EventData *data)
262 {
263     PyObject *ret, *args;
264
265     g_assert(events_hook != NULL);
266
267     args = Py_BuildValue("(O)", data);
268     ret = hook_fire(keyboard_hook, args);
269     Py_DECREF(args);
270     if (ret == NULL)
271         PyErr_Print();
272 }
273
274 void hooks_fire_pointer(EventData *data)
275 {
276     PyObject *ret, *args;
277
278     g_assert(events_hook != NULL);
279
280     args = Py_BuildValue("(O)", data);
281     ret = hook_fire(pointer_hook, args);
282     Py_DECREF(args);
283     if (ret == NULL)
284         PyErr_Print();
285 }