]> icculus.org git repositories - dana/openbox.git/blob - openbox/hooks.c
stop using python internally. add an event dispatcher
[dana/openbox.git] / openbox / hooks.c
1 #include "hooks.h"
2 #include <glib.h>
3
4 /*
5  *
6  * Define the 'Hook' class type
7  *
8  */
9 #define IS_HOOK(v)  ((v)->ob_type == &HookType)
10
11 staticforward PyTypeObject HookType;
12
13 typedef struct HookObject {
14     PyObject_HEAD
15     GSList *funcs;
16 } HookObject;
17
18 static int hook_init(HookObject *self, PyObject *args, PyObject *kwds)
19 {
20     char *keywords[] = { 0 };
21     if (!PyArg_ParseTupleAndKeywords(args, kwds, ":__init__", keywords))
22         return -1;
23     self->funcs = NULL;
24     return 0;
25 }
26
27 static void hook_dealloc(HookObject *self)
28 {
29     GSList *it;
30
31     for (it = self->funcs; it != NULL; it = it->next)
32         Py_DECREF((PyObject*) it->data);
33      
34     PyObject_Del((PyObject*) self);
35 }
36
37 static PyObject *hook_fire(HookObject *self, PyObject *args)
38 {
39     GSList *it;
40
41     if (!IS_HOOK(self)) {
42         PyErr_SetString(PyExc_TypeError,
43                         "descriptor 'fire' requires a 'Hook' object");
44         return NULL;
45     }
46
47     for (it = self->funcs; it != NULL; it = it->next) {
48         PyObject *ret = PyObject_CallObject(it->data, args);
49         if (ret == NULL)
50             return NULL;
51         Py_DECREF(ret);
52     }
53
54     Py_INCREF(Py_None);
55     return Py_None;
56 }
57
58 static PyObject *hook_append(HookObject *self, PyObject *args)
59 {
60     PyObject *func;
61      
62     if (!IS_HOOK(self)) {
63         PyErr_SetString(PyExc_TypeError,
64                         "descriptor 'append' requires a 'Hook' object");
65         return NULL;
66     }
67     if (!PyArg_ParseTuple(args, "O:append", &func))
68         return NULL;
69     if (!PyCallable_Check(func)) {
70         PyErr_SetString(PyExc_TypeError,
71                         "descriptor 'append' requires a callable argument");
72         return NULL;
73     }
74     self->funcs = g_slist_append(self->funcs, func);
75     Py_INCREF(func);
76
77     Py_INCREF(Py_None);
78     return Py_None;
79 }
80
81 static PyObject *hook_remove(HookObject *self, PyObject *args)
82 {
83     PyObject *func;
84     GSList *it;
85      
86     if (!IS_HOOK(self)) {
87         PyErr_SetString(PyExc_TypeError,
88                         "descriptor 'remove' requires a 'Hook' object");
89         return NULL;
90     }
91     if (!PyArg_ParseTuple(args, "O:remove", &func))
92         return NULL;
93     if (!PyCallable_Check(func)) {
94         PyErr_SetString(PyExc_TypeError,
95                         "descriptor 'remove' requires a callable argument");
96         return NULL;
97     }
98
99     it = g_slist_find(self->funcs, func);
100     if (it != NULL) {
101         self->funcs = g_slist_delete_link(self->funcs, it);
102         Py_DECREF(func);
103
104         Py_INCREF(Py_None);
105         return Py_None;
106     }
107     PyErr_SetString(PyExc_TypeError,
108                     "given callable object was not found in Hook");
109     return NULL;
110 }
111
112 static PyObject *hook_call(HookObject *self, PyObject *args)
113 {
114     PyObject *ret;
115     GSList *it, *next;
116     gboolean stop = FALSE;
117
118     if (!IS_HOOK(self)) {
119         PyErr_SetString(PyExc_TypeError,
120                         "descriptor '__call__' requires a 'Hook' object");
121         return NULL;
122     }
123
124     for (it = self->funcs; !stop && it != NULL;) {
125         next = it->next; /* incase the hook removes itself */
126
127         ret = PyObject_CallObject(it->data, args);
128         if (ret == NULL)
129             return NULL;
130         if (ret != Py_None)
131             stop = TRUE;
132         Py_DECREF(ret);
133
134         it = next;
135     }
136
137     Py_INCREF(Py_None);
138     return Py_None;
139 }
140
141 static PyTypeObject HookType = {
142     PyObject_HEAD_INIT(NULL)
143     0,
144     "Hook",
145     sizeof(HookObject),
146     0,
147     (destructor) hook_dealloc, /*tp_dealloc*/
148     0,                         /*tp_print*/
149     0,                         /*tp_getattr*/
150     0,                         /*tp_setattr*/
151     0,                         /*tp_compare*/
152     0,                         /*tp_repr*/
153     0,                         /*tp_as_number*/
154     0,                         /*tp_as_sequence*/
155     0,                         /*tp_as_mapping*/
156     0,                         /*tp_hash */
157 };
158
159 static PyMethodDef HookMethods[] = {
160     {"append", (PyCFunction)hook_append, METH_VARARGS,
161      "hook.add(func) -- Add a function to the hook." },
162     {"remove", (PyCFunction)hook_remove, METH_VARARGS,
163      "hook.remove(func) -- Remove a function from the hook." },
164     { NULL, NULL, 0, NULL }
165 };
166
167
168 /*
169  *
170  * Module initialization/finalization
171  *
172  */
173
174 static PyObject *hooks, *hooksdict;
175
176 static PyMethodDef HooksMethods[] = {
177     { NULL, NULL, 0, NULL }
178 };
179
180 struct HookObject *hooks_create(char *name)
181 {
182     HookObject *hook;
183     int ret;
184
185     hook = PyObject_New(HookObject, &HookType);
186     hook->funcs = NULL;
187
188     /* add it to the hooks module */
189     ret = PyDict_SetItemString(hooksdict, name, (PyObject*) hook);
190     g_assert(ret != -1);
191
192     return hook;
193 }
194
195 void hooks_startup()
196 {
197     HookType.ob_type = &PyType_Type;
198     HookType.tp_methods = HookMethods;
199     HookType.tp_alloc = PyType_GenericAlloc;
200     HookType.tp_new = PyType_GenericNew;
201     HookType.tp_init = (initproc) hook_init;
202     HookType.tp_call = (ternaryfunc) hook_call;
203     PyType_Ready(&HookType);
204
205     Py_InitModule("hooks", HooksMethods);
206
207     /* get the hooks module/dict */
208     hooks = PyImport_ImportModule("hooks"); /* new */
209     g_assert(hooks != NULL);
210     hooksdict = PyModule_GetDict(hooks); /* borrowed */
211     g_assert(hooksdict != NULL);
212
213     /* add the Hook type to the hooks module */
214     PyDict_SetItemString(hooksdict, "Hook", (PyObject*) &HookType);
215
216     hook_startup = hooks_create("startup");
217     hook_shutdown = hooks_create("shutdown");
218     hook_visibledesktop = hooks_create("visibledesktop");
219     hook_numdesktops = hooks_create("numdesktops");
220     hook_desktopnames = hooks_create("desktopnames");
221     hook_showdesktop = hooks_create("showdesktop");
222     hook_screenconfiguration = hooks_create("screenconfiguration");
223     hook_screenarea = hooks_create("screenarea");
224     hook_managed = hooks_create("managed");
225     hook_closed = hooks_create("closed");
226     hook_bell = hooks_create("bell");
227     hook_urgent = hooks_create("urgent");
228     hook_pointerenter = hooks_create("pointerenter");
229     hook_pointerleave = hooks_create("pointerleave");
230     hook_focused = hooks_create("focused");
231     hook_requestactivate = hooks_create("requestactivate");
232     hook_title = hooks_create("title");
233     hook_desktop = hooks_create("desktop");
234     hook_iconic = hooks_create("iconic");
235     hook_shaded = hooks_create("shaded");
236     hook_maximized = hooks_create("maximized");
237     hook_fullscreen = hooks_create("fullscreen");
238     hook_visible = hooks_create("visible");
239     hook_configuration = hooks_create("configuration");
240 }
241
242 void hooks_shutdown()
243 {
244     Py_DECREF(hook_startup);
245     Py_DECREF(hook_shutdown);
246     Py_DECREF(hook_visibledesktop);
247     Py_DECREF(hook_numdesktops);
248     Py_DECREF(hook_desktopnames);
249     Py_DECREF(hook_showdesktop);
250     Py_DECREF(hook_screenconfiguration);
251     Py_DECREF(hook_screenarea);
252     Py_DECREF(hook_managed);
253     Py_DECREF(hook_closed);
254     Py_DECREF(hook_bell);
255     Py_DECREF(hook_urgent);
256     Py_DECREF(hook_pointerenter);
257     Py_DECREF(hook_pointerleave);
258     Py_DECREF(hook_focused);
259     Py_DECREF(hook_requestactivate);
260     Py_DECREF(hook_title);
261     Py_DECREF(hook_desktop);
262     Py_DECREF(hook_iconic);
263     Py_DECREF(hook_shaded);
264     Py_DECREF(hook_maximized);
265     Py_DECREF(hook_fullscreen);
266     Py_DECREF(hook_visible);
267     Py_DECREF(hook_configuration);
268
269     Py_DECREF(hooks);
270 }
271
272 void hooks_fire(struct HookObject *hook, PyObject *args)
273 {
274     PyObject *ret = hook_call(hook, args);
275     if (ret == NULL)
276         PyErr_Print();
277     Py_XDECREF(ret);
278 }
279
280 void hooks_fire_client(struct HookObject *hook, struct Client *client)
281 {
282     PyObject *args;
283
284     if (client != NULL) {
285         PyObject *c = clientwrap_new(client);
286         g_assert(c != NULL);
287         args = Py_BuildValue("(O)", c);
288         Py_DECREF(c);
289     } else {
290         args = Py_BuildValue("(O)", Py_None);
291     }
292
293     g_assert(args != NULL);
294     hooks_fire(hook, args);
295     Py_DECREF(args);
296 }