Allow hooking to object-specific events (partial).
[screen-lua.git] / src / python.c
blob1572450e473a2b3d6b467a250a9bbd21893f159f
1 /* Python scripting support
3 * Copyright (c) 2009 Sadrul Habib Chowdhury (sadrul@users.sf.net)
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3, or (at your option)
8 * any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program (see the file COPYING); if not, write to the
17 * Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
20 ****************************************************************
22 #include <sys/types.h>
24 #include "config.h"
25 #include "screen.h"
26 #include "script.h"
27 #include <sys/stat.h>
28 #include <unistd.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
34 #include "extern.h"
35 #include "logfile.h"
37 #include <Python.h>
38 #include <structmember.h>
40 #define RETURN_NONE do { Py_INCREF(Py_None); return Py_None; } while (0)
42 extern struct win *windows;
43 extern struct display *display, *displays;
44 extern struct layer *flayer;
46 static PyObject * SPy_Get(PyObject *obj, void *closure);
47 static PyObject * SPy_Set(PyObject *obj, PyObject *value, void *closure);
48 static int PyDispatch(void *handler, const char *params, va_list va);
49 static PyObject * register_event_hook(PyObject *self, PyObject *args, PyObject *kw, void *object);
51 typedef struct
53 PyObject *callback;
54 struct listener *listener;
55 } SPyCallback;
57 typedef struct
59 char *name;
60 char *doc;
62 int type;
63 size_t offset1;
64 size_t offset2;
65 PyObject * (*conv)(void *);
66 } SPyClosure;
69 #define compare_callback NULL
70 #define repr_callback NULL
72 #define REGISTER_TYPE(type, Type, closures, methods) \
73 static int \
74 register_##type(PyObject *module) \
75 { \
76 static PyGetSetDef getsets[sizeof(closures)]; \
77 int i, count = sizeof(closures); \
78 for (i = 0; i < count; i++) \
79 { \
80 getsets[i].name = closures[i].name; \
81 getsets[i].doc = closures[i].doc; \
82 getsets[i].closure = &closures[i]; \
83 getsets[i].get = SPy_Get; \
84 getsets[i].set = SPy_Set; \
85 } \
86 PyType##Type.tp_base = &ScreenObjectType; \
87 PyType##Type.tp_getset = getsets; \
88 PyType##Type.tp_methods = methods; \
89 PyType##Type.tp_compare = compare_##type; \
90 PyType##Type.tp_repr = repr_##type; \
91 PyType_Ready(&PyType##Type); \
92 Py_INCREF(&PyType##Type); \
93 PyModule_AddObject(module, #Type, (PyObject *)&PyType##Type); \
94 return 1; \
97 #define DEFINE_TYPE(str, Type) \
98 typedef struct \
99 { \
100 ScreenObject __parent; \
101 str *_obj; \
102 } Py##Type; \
104 static PyTypeObject PyType##Type = \
106 PyObject_HEAD_INIT(NULL) \
107 .ob_size = 0, \
108 .tp_name = "screen." #Type, \
109 .tp_basicsize = sizeof(Py##Type), \
110 .tp_flags = Py_TPFLAGS_DEFAULT, \
111 .tp_doc = #Type " object", \
112 .tp_methods = NULL, \
113 .tp_getset = NULL, \
114 }; \
116 static PyObject * \
117 PyObject_From##Type(str *_obj) \
119 Py##Type *obj = PyType##Type.tp_alloc(&PyType##Type, 0); \
120 obj->_obj = _obj; \
121 return (PyObject *)obj; \
124 static PyObject *
125 PyString_FromStringSafe(const char *str)
127 if (str)
128 return PyString_FromString(str);
129 RETURN_NONE;
132 /** Generic Object {{{ */
133 typedef struct
135 PyObject_HEAD
136 char *name;
137 } ScreenObject;
139 static PyObject *
140 object_hook(PyObject *self, PyObject *args, PyObject *kw)
142 char *object;
143 object = *(char **)((char *)self + sizeof(ScreenObject)); /* ugliness */
144 return register_event_hook(self, args, kw, object);
147 static PyMethodDef omethods[] = {
148 {"hook", (PyCFunction)object_hook, METH_VARARGS | METH_KEYWORDS, "Hook to an event on the object."},
149 {NULL}
152 static PyTypeObject ScreenObjectType =
154 PyObject_HEAD_INIT(NULL)
155 .ob_size = 0,
156 .tp_name = "screen.Object",
157 .tp_basicsize = sizeof(ScreenObject),
158 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
159 .tp_doc = "Generic object",
160 .tp_methods = omethods,
161 .tp_getset = NULL,
164 static int
165 register_object(PyObject *module)
167 PyType_Ready(&ScreenObjectType);
168 Py_INCREF(&ScreenObjectType);
169 PyModule_AddObject(module, "Generic Object", (PyObject *)&ScreenObjectType);
172 /** }}} */
174 /** Window {{{ */
175 DEFINE_TYPE(struct win, Window)
177 #define SPY_CLOSURE(name, doc, type, member, func) \
178 {name, doc, type, offsetof(PyWindow, _obj), offsetof(struct win, member), func}
179 static SPyClosure wclosures[] =
181 SPY_CLOSURE("title", "Window title", T_STRING, w_title, NULL),
182 SPY_CLOSURE("number", "Window number", T_INT, w_number, NULL),
183 SPY_CLOSURE("dir", "Window directory", T_STRING, w_dir, NULL),
184 SPY_CLOSURE("tty", "TTY belonging to the window", T_STRING_INPLACE, w_tty, NULL),
185 SPY_CLOSURE("group", "The group the window belongs to", T_OBJECT_EX, w_group, PyObject_FromWindow),
186 SPY_CLOSURE("pid", "Window pid", T_INT, w_pid, NULL),
187 {NULL}
190 static PyObject *
191 window_select(PyObject *self)
193 PyWindow *win = self;
194 struct win *w = win->_obj;
195 SwitchWindow(w->w_number);
196 RETURN_NONE;
199 static PyMethodDef wmethods[] = {
200 {"select", (PyCFunction)window_select, METH_NOARGS, "Select the window."},
201 {NULL},
204 static int
205 compare_window(PyWindow *one, PyWindow *two)
207 struct win *wone = one->_obj;
208 struct win *wtwo = two->_obj;
210 return wtwo->w_number - wone->w_number;
213 static PyObject *
214 repr_window(PyObject *obj)
216 PyWindow *w = obj;
217 struct win *win = w->_obj;
218 return PyString_FromFormat("window (title: %s, number: %d)", win->w_title, win->w_number);
221 REGISTER_TYPE(window, Window, wclosures, wmethods)
222 #undef SPY_CLOSURE
223 /** }}} */
225 /** Display {{{ */
226 DEFINE_TYPE(struct display, Display)
228 #define SPY_CLOSURE(name, doc, type, member, func) \
229 {name, doc, type, offsetof(PyDisplay, _obj), offsetof(struct display, member), func}
230 static SPyClosure dclosures[] =
232 SPY_CLOSURE("tty", "Display TTY", T_STRING_INPLACE, d_usertty, NULL),
233 SPY_CLOSURE("term", "Display Term", T_STRING_INPLACE, d_termname, NULL),
234 SPY_CLOSURE("fore", "Foreground window of the display", T_OBJECT_EX, d_fore, PyObject_FromWindow),
235 SPY_CLOSURE("width", "Display width", T_INT, d_width, NULL),
236 SPY_CLOSURE("height", "Display height", T_INT, d_height, NULL),
237 {NULL}
240 static PyMethodDef dmethods[] =
242 {NULL}
245 static int
246 compare_display(PyDisplay *one, PyDisplay *two)
248 struct display *done = one->_obj;
249 struct display *dtwo = two->_obj;
250 struct display *iter;
252 if (done->d_userpid == dtwo->d_userpid)
253 return 0;
255 for (iter = displays; iter; iter = iter->d_next)
256 if (iter == done)
257 return -1;
258 else if (iter == dtwo)
259 return 1;
261 return 0;
264 static PyObject *
265 repr_display(PyObject *obj)
267 PyDisplay *d = obj;
268 struct display *disp = d->_obj;
269 return PyString_FromFormat("display (term: %s, tty: %s)", disp->d_termname, disp->d_usertty);
272 REGISTER_TYPE(display, Display, dclosures, dmethods)
273 #undef SPY_CLOSURE
274 /** }}} */
276 /** Callback {{{ */
277 DEFINE_TYPE(SPyCallback, Callback)
278 static SPyClosure cclosures[] = {{NULL}};
280 static void
281 FreeCallback(SPyCallback *scallback)
283 Py_XDECREF(scallback->callback);
284 Free(scallback);
287 static PyObject *
288 callback_unhook(PyObject *obj)
290 PyCallback *cb = obj;
291 SPyCallback *scallback = cb->_obj;
292 if (!scallback)
293 return NULL;
294 unregister_listener(scallback->listener);
295 FreeCallback(scallback);
296 cb->_obj = NULL;
297 RETURN_NONE;
300 static PyMethodDef cmethods[] = {
301 {"unhook", (PyCFunction)callback_unhook, METH_NOARGS, "Unhook this event callback."},
302 {NULL}
304 REGISTER_TYPE(callback, Callback, cclosures, cmethods)
305 /** }}} */
307 static PyObject *
308 SPy_Get(PyObject *obj, void *closure)
310 SPyClosure *sc = closure;
311 char **first = (char *)obj + sc->offset1;
312 char **second = (char *)*first + sc->offset2;
313 PyObject *(*cb)(void *) = sc->conv;
314 void *data = *second;
316 if (!cb)
318 switch (sc->type)
320 case T_STRING:
321 cb = PyString_FromStringSafe;
322 data = *second;
323 break;
324 case T_STRING_INPLACE:
325 cb = PyString_FromStringSafe;
326 data = second;
327 break;
328 case T_INT:
329 cb = PyInt_FromLong;
330 data = *second;
331 break;
334 return cb(data);
337 static PyObject *
338 SPy_Set(PyObject *obj, PyObject *value, void *closure)
340 return NULL;
343 static int
344 PyDispatch(void *handler, const char *params, va_list va)
346 PyCallback *callback = handler;
347 PyObject *args, *ret;
348 int count, retval;
349 const char *p;
350 SPyCallback *scallback = callback->_obj;
352 for (count = 0, p = params; *p; p++, count++)
354 if (count > 0)
355 args = PyTuple_New(count);
356 else
357 args = NULL;
359 for (count = 0, p = params; *p; p++, count++)
361 PyObject *item = NULL;
362 switch (*p)
364 case 's':
365 item = PyString_FromStringSafe(va_arg(va, char *));
366 break;
367 case 'S':
369 char **ls = va_arg(va, char **), **iter;
370 int c = 0;
371 for (iter = ls; iter && *iter; iter++, c++)
373 if (c == 0)
374 break;
375 item = PyTuple_New(c);
376 for (c = 0, iter = ls; iter && *iter; iter++, c++)
377 PyTuple_SetItem(item, c, PyString_FromStringSafe(*iter));
379 break;
380 case 'i':
381 item = PyInt_FromLong(va_arg(va, int));
382 break;
383 case 'd':
384 item = PyObject_FromDisplay(va_arg(va, struct display *));
385 break;
388 if (!item)
390 item = Py_None;
391 Py_INCREF(Py_None);
393 PyTuple_SetItem(args, count, item);
396 ret = PyObject_CallObject(scallback->callback, args);
397 Py_DECREF(args);
398 if (!ret)
399 return 0;
401 retval = (int)PyInt_AsLong(ret);
402 Py_DECREF(ret);
403 return retval;
406 static PyObject *
407 register_event_hook(PyObject *self, PyObject *args, PyObject *kw, void *object)
409 static char *kwlist[] = {"event", "callback", NULL};
411 PyObject *callback;
412 char *name;
414 struct script_event *sev;
415 struct listener *l;
416 SPyCallback *scallback;
418 if (!PyArg_ParseTupleAndKeywords(args, kw, "sO:screen.hook", kwlist, &name, &callback))
419 return NULL; /* Return Py_None instead? */
421 if (!PyCallable_Check(callback))
423 PyErr_SetString(PyExc_TypeError, "The event-callback functions must be callable.");
424 LMsg(0, "The event-callback functions must be callable.");
425 return NULL;
428 sev = object_get_event(object, name);
429 if (!sev)
431 LMsg(0, "No event named '%s'", name);
432 return NULL;
435 l = malloc(sizeof(struct listener));
437 scallback = malloc(sizeof(SPyCallback));
438 scallback->callback = callback;
439 scallback->listener = l;
440 Py_INCREF(scallback->callback);
442 l->handler = PyObject_FromCallback(scallback);
443 l->priv = 0;
444 l->dispatcher = PyDispatch;
445 if (register_listener(sev, l))
447 Py_DECREF((PyObject *)l->handler);
448 FreeCallback(scallback);
449 Free(l);
451 LMsg(0, "Hook could not be registered.");
453 RETURN_NONE;
456 Py_INCREF((PyObject *)l->handler);
457 return l->handler;
459 RETURN_NONE;
462 /** Screen {{{ */
463 static PyObject *
464 screen_display(PyObject *self)
466 if (!display)
468 RETURN_NONE;
470 return PyObject_FromDisplay(display);
473 static PyObject *
474 screen_displays(PyObject *self)
476 struct display *d = displays;
477 int count = 0;
478 for (; d; d = d->d_next)
479 ++count;
480 PyObject *tuple = PyTuple_New(count);
482 for (d = displays, count = 0; d; d = d->d_next, ++count)
483 PyTuple_SetItem(tuple, count, PyObject_FromDisplay(d));
485 return tuple;
488 static PyObject *
489 screen_windows(PyObject *self)
491 struct win *w = windows;
492 int count = 0;
493 for (; w; w = w->w_next)
494 ++count;
495 PyObject *tuple = PyTuple_New(count);
497 for (w = windows, count = 0; w; w = w->w_next, ++count)
498 PyTuple_SetItem(tuple, count, PyObject_FromWindow(w));
500 return tuple;
503 static PyObject *
504 hook_event(PyObject *self, PyObject *args, PyObject *kw)
506 return register_event_hook(self, args, kw, NULL);
509 static void
510 screen_input_cb(char *buf, int len, char *p)
512 PyObject *callback = p;
513 PyObject *str = PyTuple_New(1);
514 PyTuple_SetItem(str, 0, PyString_FromStringSafe(buf));
515 PyObject_CallObject(callback, str);
516 Py_DECREF(str);
517 Py_DECREF(callback);
520 static PyObject *
521 screen_input(PyObject *self, PyObject *args, PyObject *kw)
523 static char *kwlist[] = {"prompt", "callback", "value (optional)", NULL};
524 char *prompt, *pre = NULL;
525 PyObject *callback;
527 if (!PyArg_ParseTupleAndKeywords(args, kw, "sO|s:screen.input", kwlist, &prompt, &callback, &pre))
529 LMsg(0, "Could not parse all the parameters to screen.input call.");
530 return NULL;
533 if (!PyCallable_Check(callback))
535 LMsg(0, "Input callback must be a callable object.");
536 return NULL;
539 Py_INCREF(callback);
540 Input(prompt, 100 /* huh? */,
541 INP_COOKED, screen_input_cb, callback, 0);
543 if (pre && *pre)
545 int len = strlen(pre);
546 LayProcess(&pre, &len);
549 RETURN_NONE;
552 const PyMethodDef py_methods[] = {
553 {"display", (PyCFunction)screen_display, METH_NOARGS, "Get the current display."},
554 {"displays", (PyCFunction)screen_displays, METH_NOARGS, "Get the list of displays."},
555 {"hook", (PyCFunction)hook_event, METH_VARARGS|METH_KEYWORDS, "Hook a callback to an event."},
556 {"input", (PyCFunction)screen_input, METH_VARARGS|METH_KEYWORDS, "Read user input interactively."},
557 {"windows", (PyCFunction)screen_windows, METH_NOARGS, "Get the list of windows."},
558 {NULL, NULL, 0, NULL}
560 /** }}} */
562 static int
563 SPyInit(void)
565 PyObject *m;
567 Py_Initialize();
569 m = Py_InitModule3 ("screen", py_methods, NULL);
570 register_object(m);
571 register_window(m);
572 register_display(m);
573 register_callback(m);
575 return 0;
578 static int
579 SPyFinit(void)
581 Py_Finalize();
582 return 0;
585 static int
586 SPySource(const char *file, int async)
588 FILE *f = fopen(file, "rb");
589 int ret = PyRun_SimpleFile(f, file);
590 fclose(f);
592 if (ret == 0)
593 return 1; /* Success */
595 if (PyErr_Occurred())
597 PyErr_Print();
598 return 0;
601 return 1;
604 struct binding py_binding =
606 "python",
609 SPyInit,
610 SPyFinit,
612 SPySource,