Start implementation of setters.
[screen-lua.git] / src / python.c
blobbfe6f710e55c1836c8e3ced668d96abe1c85ca44
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 int 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 int (*setter)(void *, PyObject *);
67 } SPyClosure;
70 #define compare_callback NULL
71 #define repr_callback NULL
73 #define REGISTER_TYPE(type, Type, closures, methods) \
74 static int \
75 register_##type(PyObject *module) \
76 { \
77 static PyGetSetDef getsets[sizeof(closures)]; \
78 int i, count = sizeof(closures); \
79 for (i = 0; i < count; i++) \
80 { \
81 getsets[i].name = closures[i].name; \
82 getsets[i].doc = closures[i].doc; \
83 getsets[i].closure = &closures[i]; \
84 getsets[i].get = SPy_Get; \
85 getsets[i].set = SPy_Set; \
86 } \
87 PyType##Type.tp_base = &ScreenObjectType; \
88 PyType##Type.tp_getset = getsets; \
89 PyType##Type.tp_methods = methods; \
90 PyType##Type.tp_compare = compare_##type; \
91 PyType##Type.tp_repr = repr_##type; \
92 PyType_Ready(&PyType##Type); \
93 Py_INCREF(&PyType##Type); \
94 PyModule_AddObject(module, #Type, (PyObject *)&PyType##Type); \
95 return 1; \
98 #define DEFINE_TYPE(str, Type) \
99 typedef struct \
101 ScreenObject __parent; \
102 str *_obj; \
103 } Py##Type; \
105 static PyTypeObject PyType##Type = \
107 PyObject_HEAD_INIT(NULL) \
108 .ob_size = 0, \
109 .tp_name = "screen." #Type, \
110 .tp_basicsize = sizeof(Py##Type), \
111 .tp_flags = Py_TPFLAGS_DEFAULT, \
112 .tp_doc = #Type " object", \
113 .tp_methods = NULL, \
114 .tp_getset = NULL, \
115 }; \
117 static PyObject * \
118 PyObject_From##Type(str *_obj) \
120 Py##Type *obj = PyType##Type.tp_alloc(&PyType##Type, 0); \
121 obj->_obj = _obj; \
122 return (PyObject *)obj; \
125 static PyObject *
126 PyString_FromStringSafe(const char *str)
128 if (str)
129 return PyString_FromString(str);
130 RETURN_NONE;
133 /** Generic Object {{{ */
134 typedef struct
136 PyObject_HEAD
137 char *name;
138 } ScreenObject;
140 static PyObject *
141 object_hook(PyObject *self, PyObject *args, PyObject *kw)
143 char *object;
144 object = *(char **)((char *)self + sizeof(ScreenObject)); /* ugliness */
145 return register_event_hook(self, args, kw, object);
148 static PyMethodDef omethods[] = {
149 {"hook", (PyCFunction)object_hook, METH_VARARGS | METH_KEYWORDS, "Hook to an event on the object."},
150 {NULL}
153 static PyTypeObject ScreenObjectType =
155 PyObject_HEAD_INIT(NULL)
156 .ob_size = 0,
157 .tp_name = "screen.Object",
158 .tp_basicsize = sizeof(ScreenObject),
159 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
160 .tp_doc = "Generic object",
161 .tp_methods = omethods,
162 .tp_getset = NULL,
165 static int
166 register_object(PyObject *module)
168 PyType_Ready(&ScreenObjectType);
169 Py_INCREF(&ScreenObjectType);
170 PyModule_AddObject(module, "Generic Object", (PyObject *)&ScreenObjectType);
173 /** }}} */
175 /** Window {{{ */
176 DEFINE_TYPE(struct win, Window)
178 static int
179 window_set_title(struct win *win, PyObject *value)
181 char *string = PyString_AsString(value);
182 if (!string || !*string)
183 return -1;
184 ChangeAKA(win, string, strlen(string));
185 return 0;
188 #define SPY_CLOSURE(name, doc, type, member, func, setter) \
189 {name, doc, type, offsetof(PyWindow, _obj), offsetof(struct win, member), func, setter}
190 static SPyClosure wclosures[] =
192 SPY_CLOSURE("title", "Window title", T_STRING, w_title, NULL, window_set_title),
193 SPY_CLOSURE("number", "Window number", T_INT, w_number, NULL, NULL),
194 SPY_CLOSURE("dir", "Window directory", T_STRING, w_dir, NULL, NULL),
195 SPY_CLOSURE("tty", "TTY belonging to the window", T_STRING_INPLACE, w_tty, NULL, NULL),
196 SPY_CLOSURE("group", "The group the window belongs to", T_OBJECT_EX, w_group, PyObject_FromWindow, NULL),
197 SPY_CLOSURE("pid", "Window pid", T_INT, w_pid, NULL, NULL),
198 {NULL}
201 static PyObject *
202 window_select(PyObject *self)
204 PyWindow *win = self;
205 struct win *w = win->_obj;
206 SwitchWindow(w->w_number);
207 RETURN_NONE;
210 static PyMethodDef wmethods[] = {
211 {"select", (PyCFunction)window_select, METH_NOARGS, "Select the window."},
212 {NULL},
215 static int
216 compare_window(PyWindow *one, PyWindow *two)
218 struct win *wone = one->_obj;
219 struct win *wtwo = two->_obj;
221 return wtwo->w_number - wone->w_number;
224 static PyObject *
225 repr_window(PyObject *obj)
227 PyWindow *w = obj;
228 struct win *win = w->_obj;
229 return PyString_FromFormat("window (title: %s, number: %d)", win->w_title, win->w_number);
232 REGISTER_TYPE(window, Window, wclosures, wmethods)
233 #undef SPY_CLOSURE
234 /** }}} */
236 /** Display {{{ */
237 DEFINE_TYPE(struct display, Display)
239 #define SPY_CLOSURE(name, doc, type, member, func) \
240 {name, doc, type, offsetof(PyDisplay, _obj), offsetof(struct display, member), func}
241 static SPyClosure dclosures[] =
243 SPY_CLOSURE("tty", "Display TTY", T_STRING_INPLACE, d_usertty, NULL),
244 SPY_CLOSURE("term", "Display Term", T_STRING_INPLACE, d_termname, NULL),
245 SPY_CLOSURE("fore", "Foreground window of the display", T_OBJECT_EX, d_fore, PyObject_FromWindow),
246 SPY_CLOSURE("width", "Display width", T_INT, d_width, NULL),
247 SPY_CLOSURE("height", "Display height", T_INT, d_height, NULL),
248 {NULL}
251 static PyMethodDef dmethods[] =
253 {NULL}
256 static int
257 compare_display(PyDisplay *one, PyDisplay *two)
259 struct display *done = one->_obj;
260 struct display *dtwo = two->_obj;
261 struct display *iter;
263 if (done->d_userpid == dtwo->d_userpid)
264 return 0;
266 for (iter = displays; iter; iter = iter->d_next)
267 if (iter == done)
268 return -1;
269 else if (iter == dtwo)
270 return 1;
272 return 0;
275 static PyObject *
276 repr_display(PyObject *obj)
278 PyDisplay *d = obj;
279 struct display *disp = d->_obj;
280 return PyString_FromFormat("display (term: %s, tty: %s)", disp->d_termname, disp->d_usertty);
283 REGISTER_TYPE(display, Display, dclosures, dmethods)
284 #undef SPY_CLOSURE
285 /** }}} */
287 /** Callback {{{ */
288 DEFINE_TYPE(SPyCallback, Callback)
289 static SPyClosure cclosures[] = {{NULL}};
291 static void
292 FreeCallback(SPyCallback *scallback)
294 Py_XDECREF(scallback->callback);
295 Free(scallback);
298 static PyObject *
299 callback_unhook(PyObject *obj)
301 PyCallback *cb = obj;
302 SPyCallback *scallback = cb->_obj;
303 if (!scallback)
304 return NULL;
305 unregister_listener(scallback->listener);
306 FreeCallback(scallback);
307 cb->_obj = NULL;
308 RETURN_NONE;
311 static PyMethodDef cmethods[] = {
312 {"unhook", (PyCFunction)callback_unhook, METH_NOARGS, "Unhook this event callback."},
313 {NULL}
315 REGISTER_TYPE(callback, Callback, cclosures, cmethods)
316 /** }}} */
318 static PyObject *
319 SPy_Get(PyObject *obj, void *closure)
321 SPyClosure *sc = closure;
322 char **first = (char *)obj + sc->offset1;
323 char **second = (char *)*first + sc->offset2;
324 PyObject *(*cb)(void *) = sc->conv;
325 void *data = *second;
327 if (!cb)
329 switch (sc->type)
331 case T_STRING:
332 cb = PyString_FromStringSafe;
333 data = *second;
334 break;
335 case T_STRING_INPLACE:
336 cb = PyString_FromStringSafe;
337 data = second;
338 break;
339 case T_INT:
340 cb = PyInt_FromLong;
341 data = *second;
342 break;
345 return cb(data);
348 static int
349 SPy_Set(PyObject *obj, PyObject *value, void *closure)
351 SPyClosure *sc = closure;
352 char **first = (char *)obj + sc->offset1;
353 if (value == NULL)
355 PyErr_SetString(PyExc_TypeError, "Cannot remove an attribute value.");
356 return -1;
358 if (sc->setter == NULL)
360 char str[256];
361 snprintf(str, sizeof(str) - 1, "Cannot change '%s'.", sc->name);
362 PyErr_SetString(PyExc_TypeError, str);
363 return -1;
366 return sc->setter(*(void **)first, value);
369 static int
370 PyDispatch(void *handler, const char *params, va_list va)
372 PyCallback *callback = handler;
373 PyObject *args, *ret;
374 int count, retval;
375 const char *p;
376 SPyCallback *scallback = callback->_obj;
378 for (count = 0, p = params; *p; p++, count++)
380 if (count > 0)
381 args = PyTuple_New(count);
382 else
383 args = NULL;
385 for (count = 0, p = params; *p; p++, count++)
387 PyObject *item = NULL;
388 switch (*p)
390 case 's':
391 item = PyString_FromStringSafe(va_arg(va, char *));
392 break;
393 case 'S':
395 char **ls = va_arg(va, char **), **iter;
396 int c = 0;
397 for (iter = ls; iter && *iter; iter++, c++)
399 if (c == 0)
400 break;
401 item = PyTuple_New(c);
402 for (c = 0, iter = ls; iter && *iter; iter++, c++)
403 PyTuple_SetItem(item, c, PyString_FromStringSafe(*iter));
405 break;
406 case 'i':
407 item = PyInt_FromLong(va_arg(va, int));
408 break;
409 case 'd':
410 item = PyObject_FromDisplay(va_arg(va, struct display *));
411 break;
414 if (!item)
416 item = Py_None;
417 Py_INCREF(Py_None);
419 PyTuple_SetItem(args, count, item);
422 ret = PyObject_CallObject(scallback->callback, args);
423 Py_DECREF(args);
424 if (!ret)
425 return 0;
427 retval = (int)PyInt_AsLong(ret);
428 Py_DECREF(ret);
429 return retval;
432 static PyObject *
433 register_event_hook(PyObject *self, PyObject *args, PyObject *kw, void *object)
435 static char *kwlist[] = {"event", "callback", NULL};
437 PyObject *callback;
438 char *name;
440 struct script_event *sev;
441 struct listener *l;
442 SPyCallback *scallback;
444 if (!PyArg_ParseTupleAndKeywords(args, kw, "sO:screen.hook", kwlist, &name, &callback))
445 return NULL; /* Return Py_None instead? */
447 if (!PyCallable_Check(callback))
449 PyErr_SetString(PyExc_TypeError, "The event-callback functions must be callable.");
450 LMsg(0, "The event-callback functions must be callable.");
451 return NULL;
454 sev = object_get_event(object, name);
455 if (!sev)
457 LMsg(0, "No event named '%s'", name);
458 return NULL;
461 l = malloc(sizeof(struct listener));
463 scallback = malloc(sizeof(SPyCallback));
464 scallback->callback = callback;
465 scallback->listener = l;
466 Py_INCREF(scallback->callback);
468 l->handler = PyObject_FromCallback(scallback);
469 l->priv = 0;
470 l->dispatcher = PyDispatch;
471 if (register_listener(sev, l))
473 Py_DECREF((PyObject *)l->handler);
474 FreeCallback(scallback);
475 Free(l);
477 LMsg(0, "Hook could not be registered.");
479 RETURN_NONE;
482 Py_INCREF((PyObject *)l->handler);
483 return l->handler;
485 RETURN_NONE;
488 /** Screen {{{ */
489 static PyObject *
490 screen_display(PyObject *self)
492 if (!display)
494 RETURN_NONE;
496 return PyObject_FromDisplay(display);
499 static PyObject *
500 screen_displays(PyObject *self)
502 struct display *d = displays;
503 int count = 0;
504 for (; d; d = d->d_next)
505 ++count;
506 PyObject *tuple = PyTuple_New(count);
508 for (d = displays, count = 0; d; d = d->d_next, ++count)
509 PyTuple_SetItem(tuple, count, PyObject_FromDisplay(d));
511 return tuple;
514 static PyObject *
515 screen_windows(PyObject *self)
517 struct win *w = windows;
518 int count = 0;
519 for (; w; w = w->w_next)
520 ++count;
521 PyObject *tuple = PyTuple_New(count);
523 for (w = windows, count = 0; w; w = w->w_next, ++count)
524 PyTuple_SetItem(tuple, count, PyObject_FromWindow(w));
526 return tuple;
529 static PyObject *
530 hook_event(PyObject *self, PyObject *args, PyObject *kw)
532 return register_event_hook(self, args, kw, NULL);
535 static void
536 screen_input_cb(char *buf, int len, char *p)
538 PyObject *callback = p;
539 PyObject *str = PyTuple_New(1);
540 PyTuple_SetItem(str, 0, PyString_FromStringSafe(buf));
541 PyObject_CallObject(callback, str);
542 Py_DECREF(str);
543 Py_DECREF(callback);
546 static PyObject *
547 screen_input(PyObject *self, PyObject *args, PyObject *kw)
549 static char *kwlist[] = {"prompt", "callback", "value (optional)", NULL};
550 char *prompt, *pre = NULL;
551 PyObject *callback;
553 if (!PyArg_ParseTupleAndKeywords(args, kw, "sO|s:screen.input", kwlist, &prompt, &callback, &pre))
555 LMsg(0, "Could not parse all the parameters to screen.input call.");
556 return NULL;
559 if (!PyCallable_Check(callback))
561 LMsg(0, "Input callback must be a callable object.");
562 return NULL;
565 Py_INCREF(callback);
566 Input(prompt, 100 /* huh? */,
567 INP_COOKED, screen_input_cb, callback, 0);
569 if (pre && *pre)
571 int len = strlen(pre);
572 LayProcess(&pre, &len);
575 RETURN_NONE;
578 const PyMethodDef py_methods[] = {
579 {"display", (PyCFunction)screen_display, METH_NOARGS, "Get the current display."},
580 {"displays", (PyCFunction)screen_displays, METH_NOARGS, "Get the list of displays."},
581 {"hook", (PyCFunction)hook_event, METH_VARARGS|METH_KEYWORDS, "Hook a callback to an event."},
582 {"input", (PyCFunction)screen_input, METH_VARARGS|METH_KEYWORDS, "Read user input interactively."},
583 {"windows", (PyCFunction)screen_windows, METH_NOARGS, "Get the list of windows."},
584 {NULL, NULL, 0, NULL}
586 /** }}} */
588 static PyObject *module;
589 static int
590 SPyInit(void)
592 PyObject *m;
594 Py_Initialize();
596 m = Py_InitModule3 ("screen", py_methods, NULL);
597 register_object(m);
598 register_window(m);
599 register_display(m);
600 register_callback(m);
601 module = m;
603 return 0;
606 static int
607 SPyFinit(void)
609 Py_Finalize();
610 return 0;
613 static int
614 SPySource(const char *file, int async)
616 FILE *f = fopen(file, "rb");
617 int ret = PyRun_SimpleFile(f, file);
618 fclose(f);
620 if (ret == 0)
621 return 1; /* Success */
623 if (PyErr_Occurred())
625 PyErr_Print();
626 return 0;
629 return 1;
632 static int
633 SPyCall(char *func, char **argv)
635 PyObject *dict = PyModule_GetDict(module);
636 PyObject *f = PyDict_GetItemString(dict, func);
637 PyObject *ret;
638 if (!f)
640 return 0;
642 ret = PyEval_CallFunction(f, "s", argv[0]);
643 Py_XDECREF(ret);
644 return 1;
647 struct binding py_binding =
649 "python",
652 SPyInit,
653 SPyFinit,
654 SPyCall,
655 SPySource,