Comapre and Represent displays.
[screen-lua.git] / src / python.c
blob29a4a27087db42b43b85aa310c8b9c27acac5786
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);
50 typedef struct
52 PyObject *callback;
53 struct listener *listener;
54 } SPyCallback;
56 typedef struct
58 char *name;
59 char *doc;
61 int type;
62 size_t offset1;
63 size_t offset2;
64 PyObject * (*conv)(void *);
65 } SPyClosure;
68 #define compare_callback NULL
69 #define repr_callback NULL
71 #define REGISTER_TYPE(type, Type, closures, methods) \
72 static int \
73 register_##type(PyObject *module) \
74 { \
75 static PyGetSetDef getsets[sizeof(closures)]; \
76 int i, count = sizeof(closures); \
77 for (i = 0; i < count; i++) \
78 { \
79 getsets[i].name = closures[i].name; \
80 getsets[i].doc = closures[i].doc; \
81 getsets[i].closure = &closures[i]; \
82 getsets[i].get = SPy_Get; \
83 getsets[i].set = SPy_Set; \
84 } \
85 PyType##Type.tp_getset = getsets; \
86 PyType##Type.tp_methods = methods; \
87 PyType##Type.tp_compare = compare_##type; \
88 PyType##Type.tp_repr = repr_##type; \
89 PyType_Ready(&PyType##Type); \
90 Py_INCREF(&PyType##Type); \
91 PyModule_AddObject(module, #Type, (PyObject *)&PyType##Type); \
92 return 1; \
95 #define DEFINE_TYPE(str, Type) \
96 typedef struct \
97 { \
98 PyObject_HEAD \
99 str *_obj; \
100 } Py##Type; \
102 static PyTypeObject PyType##Type = \
104 PyObject_HEAD_INIT(NULL) \
105 .ob_size = 0, \
106 .tp_name = "screen." #Type, \
107 .tp_basicsize = sizeof(Py##Type), \
108 .tp_flags = Py_TPFLAGS_DEFAULT, \
109 .tp_doc = #Type " object", \
110 .tp_methods = NULL, \
111 .tp_getset = NULL, \
112 }; \
114 static PyObject * \
115 PyObject_From##Type(str *_obj) \
117 Py##Type *obj = PyType##Type.tp_alloc(&PyType##Type, 0); \
118 obj->_obj = _obj; \
119 return (PyObject *)obj; \
122 static PyObject *
123 PyString_FromStringSafe(const char *str)
125 if (str)
126 return PyString_FromString(str);
127 RETURN_NONE;
130 /** Window {{{ */
131 DEFINE_TYPE(struct win, Window)
133 #define SPY_CLOSURE(name, doc, type, member, func) \
134 {name, doc, type, offsetof(PyWindow, _obj), offsetof(struct win, member), func}
135 static SPyClosure wclosures[] =
137 SPY_CLOSURE("title", "Window title", T_STRING, w_title, NULL),
138 SPY_CLOSURE("number", "Window number", T_INT, w_number, NULL),
139 SPY_CLOSURE("dir", "Window directory", T_STRING, w_dir, NULL),
140 SPY_CLOSURE("tty", "TTY belonging to the window", T_STRING_INPLACE, w_tty, NULL),
141 SPY_CLOSURE("group", "The group the window belongs to", T_OBJECT_EX, w_group, PyObject_FromWindow),
142 SPY_CLOSURE("pid", "Window pid", T_INT, w_pid, NULL),
143 {NULL}
146 static PyObject *
147 window_select(PyObject *self)
149 PyWindow *win = self;
150 struct win *w = win->_obj;
151 SwitchWindow(w->w_number);
152 RETURN_NONE;
155 static PyMethodDef wmethods[] = {
156 {"select", (PyCFunction)window_select, METH_NOARGS, "Select the window."},
157 {NULL},
160 static int
161 compare_window(PyWindow *one, PyWindow *two)
163 struct win *wone = one->_obj;
164 struct win *wtwo = two->_obj;
166 return wtwo->w_number - wone->w_number;
169 static PyObject *
170 repr_window(PyObject *obj)
172 PyWindow *w = obj;
173 struct win *win = w->_obj;
174 return PyString_FromFormat("window (title: %s, number: %d)", win->w_title, win->w_number);
177 REGISTER_TYPE(window, Window, wclosures, wmethods)
178 #undef SPY_CLOSURE
179 /** }}} */
181 /** Display {{{ */
182 DEFINE_TYPE(struct display, Display)
184 #define SPY_CLOSURE(name, doc, type, member, func) \
185 {name, doc, type, offsetof(PyDisplay, _obj), offsetof(struct display, member), func}
186 static SPyClosure dclosures[] =
188 SPY_CLOSURE("tty", "Display TTY", T_STRING_INPLACE, d_usertty, NULL),
189 SPY_CLOSURE("term", "Display Term", T_STRING_INPLACE, d_termname, NULL),
190 SPY_CLOSURE("fore", "Foreground window of the display", T_OBJECT_EX, d_fore, PyObject_FromWindow),
191 SPY_CLOSURE("width", "Display width", T_INT, d_width, NULL),
192 SPY_CLOSURE("height", "Display height", T_INT, d_height, NULL),
193 {NULL}
196 static PyMethodDef dmethods[] =
198 {NULL}
201 static int
202 compare_display(PyDisplay *one, PyDisplay *two)
204 struct display *done = one->_obj;
205 struct display *dtwo = two->_obj;
206 struct display *iter;
208 if (done->d_userpid == dtwo->d_userpid)
209 return 0;
211 for (iter = displays; iter; iter = iter->d_next)
212 if (iter == done)
213 return -1;
214 else if (iter == dtwo)
215 return 1;
217 return 0;
220 static PyObject *
221 repr_display(PyObject *obj)
223 PyDisplay *d = obj;
224 struct display *disp = d->_obj;
225 return PyString_FromFormat("display (term: %s, tty: %s)", disp->d_termname, disp->d_usertty);
228 REGISTER_TYPE(display, Display, dclosures, dmethods)
229 #undef SPY_CLOSURE
230 /** }}} */
232 /** Callback {{{ */
233 DEFINE_TYPE(SPyCallback, Callback)
234 static SPyClosure cclosures[] = {{NULL}};
236 static void
237 FreeCallback(SPyCallback *scallback)
239 Py_XDECREF(scallback->callback);
240 Free(scallback);
243 static PyObject *
244 callback_unhook(PyObject *obj)
246 PyCallback *cb = obj;
247 SPyCallback *scallback = cb->_obj;
248 if (!scallback)
249 return NULL;
250 unregister_listener(scallback->listener);
251 FreeCallback(scallback);
252 cb->_obj = NULL;
253 RETURN_NONE;
256 static PyMethodDef cmethods[] = {
257 {"unhook", (PyCFunction)callback_unhook, METH_NOARGS, "Unhook this event callback."},
258 {NULL}
260 REGISTER_TYPE(callback, Callback, cclosures, cmethods)
261 /** }}} */
263 static PyObject *
264 SPy_Get(PyObject *obj, void *closure)
266 SPyClosure *sc = closure;
267 char **first = (char *)obj + sc->offset1;
268 char **second = (char *)*first + sc->offset2;
269 PyObject *(*cb)(void *) = sc->conv;
270 void *data = *second;
272 if (!cb)
274 switch (sc->type)
276 case T_STRING:
277 cb = PyString_FromStringSafe;
278 data = *second;
279 break;
280 case T_STRING_INPLACE:
281 cb = PyString_FromStringSafe;
282 data = second;
283 break;
284 case T_INT:
285 cb = PyInt_FromLong;
286 data = *second;
287 break;
290 return cb(data);
293 static PyObject *
294 SPy_Set(PyObject *obj, PyObject *value, void *closure)
296 return NULL;
299 static int
300 PyDispatch(void *handler, const char *params, va_list va)
302 PyCallback *callback = handler;
303 PyObject *args, *ret;
304 int count, retval;
305 const char *p;
306 SPyCallback *scallback = callback->_obj;
308 for (count = 0, p = params; *p; p++, count++)
310 if (count > 0)
311 args = PyTuple_New(count);
312 else
313 args = NULL;
315 for (count = 0, p = params; *p; p++, count++)
317 PyObject *item = NULL;
318 switch (*p)
320 case 's':
321 item = PyString_FromStringSafe(va_arg(va, char *));
322 break;
323 case 'S':
325 char **ls = va_arg(va, char **), **iter;
326 int c = 0;
327 for (iter = ls; iter && *iter; iter++, c++)
329 if (c == 0)
330 break;
331 item = PyTuple_New(c);
332 for (c = 0, iter = ls; iter && *iter; iter++, c++)
333 PyTuple_SetItem(item, c, PyString_FromStringSafe(*iter));
335 break;
336 case 'i':
337 item = PyInt_FromLong(va_arg(va, int));
338 break;
339 case 'd':
340 item = PyObject_FromDisplay(va_arg(va, struct display *));
341 break;
344 if (!item)
346 item = Py_None;
347 Py_INCREF(Py_None);
349 PyTuple_SetItem(args, count, item);
352 ret = PyObject_CallObject(scallback->callback, args);
353 Py_DECREF(args);
354 if (!ret)
355 return 0;
357 retval = (int)PyInt_AsLong(ret);
358 Py_DECREF(ret);
359 return retval;
362 /** Screen {{{ */
363 static PyObject *
364 screen_display(PyObject *self)
366 if (!display)
368 RETURN_NONE;
370 return PyObject_FromDisplay(display);
373 static PyObject *
374 screen_displays(PyObject *self)
376 struct display *d = displays;
377 int count = 0;
378 for (; d; d = d->d_next)
379 ++count;
380 PyObject *tuple = PyTuple_New(count);
382 for (d = displays, count = 0; d; d = d->d_next, ++count)
383 PyTuple_SetItem(tuple, count, PyObject_FromDisplay(d));
385 return tuple;
388 static PyObject *
389 screen_windows(PyObject *self)
391 struct win *w = windows;
392 int count = 0;
393 for (; w; w = w->w_next)
394 ++count;
395 PyObject *tuple = PyTuple_New(count);
397 for (w = windows, count = 0; w; w = w->w_next, ++count)
398 PyTuple_SetItem(tuple, count, PyObject_FromWindow(w));
400 return tuple;
403 static PyObject *
404 hook_event(PyObject *self, PyObject *args, PyObject *kw)
406 static char *kwlist[] = {"event", "callback", NULL};
407 PyObject *callback;
408 char *name;
410 struct script_event *sev;
411 struct listener *l;
412 SPyCallback *scallback;
414 if (!PyArg_ParseTupleAndKeywords(args, kw, "sO:screen.hook", kwlist, &name, &callback))
415 return NULL; /* Return Py_None instead? */
417 if (!PyCallable_Check(callback))
419 PyErr_SetString(PyExc_TypeError, "The event-callback functions must be callable.");
420 LMsg(0, "The event-callback functions must be callable.");
421 return NULL;
424 sev = object_get_event(NULL, name);
425 if (!sev)
427 LMsg(0, "No event named '%s'", name);
428 return NULL;
431 l = malloc(sizeof(struct listener));
433 scallback = malloc(sizeof(SPyCallback));
434 scallback->callback = callback;
435 scallback->listener = l;
436 Py_INCREF(scallback->callback);
438 l->handler = PyObject_FromCallback(scallback);
439 l->priv = 0;
440 l->dispatcher = PyDispatch;
441 if (register_listener(sev, l))
443 Py_DECREF((PyObject *)l->handler);
444 FreeCallback(scallback);
445 Free(l);
447 LMsg(0, "Hook could not be registered.");
449 RETURN_NONE;
452 Py_INCREF((PyObject *)l->handler);
453 return l->handler;
456 static void
457 screen_input_cb(char *buf, int len, char *p)
459 PyObject *callback = p;
460 PyObject *str = PyTuple_New(1);
461 PyTuple_SetItem(str, 0, PyString_FromStringSafe(buf));
462 PyObject_CallObject(callback, str);
463 Py_DECREF(str);
464 Py_DECREF(callback);
467 static PyObject *
468 screen_input(PyObject *self, PyObject *args, PyObject *kw)
470 static char *kwlist[] = {"prompt", "callback", "value (optional)", NULL};
471 char *prompt, *pre = NULL;
472 PyObject *callback;
474 if (!PyArg_ParseTupleAndKeywords(args, kw, "sO|s:screen.input", kwlist, &prompt, &callback, &pre))
476 LMsg(0, "Could not parse all the parameters to screen.input call.");
477 return NULL;
480 if (!PyCallable_Check(callback))
482 LMsg(0, "Input callback must be a callable object.");
483 return NULL;
486 Py_INCREF(callback);
487 Input(prompt, 100 /* huh? */,
488 INP_COOKED, screen_input_cb, callback, 0);
490 if (pre && *pre)
492 int len = strlen(pre);
493 LayProcess(&pre, &len);
496 RETURN_NONE;
499 const PyMethodDef py_methods[] = {
500 {"display", (PyCFunction)screen_display, METH_NOARGS, "Get the current display."},
501 {"displays", (PyCFunction)screen_displays, METH_NOARGS, "Get the list of displays."},
502 {"hook", (PyCFunction)hook_event, METH_VARARGS|METH_KEYWORDS, "Hook a callback to an event."},
503 {"input", (PyCFunction)screen_input, METH_VARARGS|METH_KEYWORDS, "Read user input interactively."},
504 {"windows", (PyCFunction)screen_windows, METH_NOARGS, "Get the list of windows."},
505 {NULL, NULL, 0, NULL}
507 /** }}} */
509 static int
510 SPyInit(void)
512 PyObject *m;
514 Py_Initialize();
516 m = Py_InitModule3 ("screen", py_methods, NULL);
517 register_window(m);
518 register_display(m);
519 register_callback(m);
521 return 0;
524 static int
525 SPyFinit(void)
527 Py_Finalize();
528 return 0;
531 static int
532 SPySource(const char *file, int async)
534 FILE *f = fopen(file, "rb");
535 int ret = PyRun_SimpleFile(f, file);
536 fclose(f);
538 if (ret == 0)
539 return 1; /* Success */
541 if (PyErr_Occurred())
543 PyErr_Print();
544 return 0;
547 return 1;
550 struct binding py_binding =
552 "python",
555 SPyInit,
556 SPyFinit,
558 SPySource,