Function to compare windows.
[screen-lua.git] / src / python.c
blob358abc96665652a7667cf72a68a6233bd6ae7515
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_display NULL
69 #define compare_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_Ready(&PyType##Type); \
89 Py_INCREF(&PyType##Type); \
90 PyModule_AddObject(module, #Type, (PyObject *)&PyType##Type); \
91 return 1; \
94 #define DEFINE_TYPE(str, Type) \
95 typedef struct \
96 { \
97 PyObject_HEAD \
98 str *_obj; \
99 } Py##Type; \
101 static PyTypeObject PyType##Type = \
103 PyObject_HEAD_INIT(NULL) \
104 .ob_size = 0, \
105 .tp_name = "screen." #Type, \
106 .tp_basicsize = sizeof(Py##Type), \
107 .tp_flags = Py_TPFLAGS_DEFAULT, \
108 .tp_doc = #Type " object", \
109 .tp_methods = NULL, \
110 .tp_getset = NULL, \
111 }; \
113 static PyObject * \
114 PyObject_From##Type(str *_obj) \
116 Py##Type *obj = PyType##Type.tp_alloc(&PyType##Type, 0); \
117 obj->_obj = _obj; \
118 return (PyObject *)obj; \
121 static PyObject *
122 PyString_FromStringSafe(const char *str)
124 if (str)
125 return PyString_FromString(str);
126 RETURN_NONE;
129 /** Window {{{ */
130 DEFINE_TYPE(struct win, Window)
132 #define SPY_CLOSURE(name, doc, type, member, func) \
133 {name, doc, type, offsetof(PyWindow, _obj), offsetof(struct win, member), func}
134 static SPyClosure wclosures[] =
136 SPY_CLOSURE("title", "Window title", T_STRING, w_title, NULL),
137 SPY_CLOSURE("number", "Window number", T_INT, w_number, NULL),
138 SPY_CLOSURE("dir", "Window directory", T_STRING, w_dir, NULL),
139 SPY_CLOSURE("tty", "TTY belonging to the window", T_STRING_INPLACE, w_tty, NULL),
140 SPY_CLOSURE("group", "The group the window belongs to", T_OBJECT_EX, w_group, PyObject_FromWindow),
141 SPY_CLOSURE("pid", "Window pid", T_INT, w_pid, NULL),
142 {NULL}
145 static PyObject *
146 window_select(PyObject *self)
148 PyWindow *win = self;
149 struct win *w = win->_obj;
150 SwitchWindow(w->w_number);
151 RETURN_NONE;
154 static PyMethodDef wmethods[] = {
155 {"select", (PyCFunction)window_select, METH_NOARGS, "Select the window."},
156 {NULL},
159 static int
160 compare_window(PyWindow *one, PyWindow *two)
162 struct win *wone = one->_obj;
163 struct win *wtwo = two->_obj;
165 return wtwo->w_number - wone->w_number;
168 REGISTER_TYPE(window, Window, wclosures, wmethods)
169 #undef SPY_CLOSURE
170 /** }}} */
172 /** Display {{{ */
173 DEFINE_TYPE(struct display, Display)
175 #define SPY_CLOSURE(name, doc, type, member, func) \
176 {name, doc, type, offsetof(PyDisplay, _obj), offsetof(struct display, member), func}
177 static SPyClosure dclosures[] =
179 SPY_CLOSURE("tty", "Display TTY", T_STRING_INPLACE, d_usertty, NULL),
180 SPY_CLOSURE("term", "Display Term", T_STRING_INPLACE, d_termname, NULL),
181 SPY_CLOSURE("fore", "Foreground window of the display", T_OBJECT_EX, d_fore, PyObject_FromWindow),
182 SPY_CLOSURE("width", "Display width", T_INT, d_width, NULL),
183 SPY_CLOSURE("height", "Display height", T_INT, d_height, NULL),
184 {NULL}
186 REGISTER_TYPE(display, Display, dclosures, NULL)
187 #undef SPY_CLOSURE
188 /** }}} */
190 /** Callback {{{ */
191 DEFINE_TYPE(SPyCallback, Callback)
192 static SPyClosure cclosures[] = {{NULL}};
194 static void
195 FreeCallback(SPyCallback *scallback)
197 Py_XDECREF(scallback->callback);
198 Free(scallback);
201 static PyObject *
202 callback_unhook(PyObject *obj)
204 PyCallback *cb = obj;
205 SPyCallback *scallback = cb->_obj;
206 if (!scallback)
207 return NULL;
208 unregister_listener(scallback->listener);
209 FreeCallback(scallback);
210 cb->_obj = NULL;
211 RETURN_NONE;
214 static PyMethodDef cmethods[] = {
215 {"unhook", (PyCFunction)callback_unhook, METH_NOARGS, "Unhook this event callback."},
216 {NULL}
218 REGISTER_TYPE(callback, Callback, cclosures, cmethods)
219 /** }}} */
221 static PyObject *
222 SPy_Get(PyObject *obj, void *closure)
224 SPyClosure *sc = closure;
225 char **first = (char *)obj + sc->offset1;
226 char **second = (char *)*first + sc->offset2;
227 PyObject *(*cb)(void *) = sc->conv;
228 void *data = *second;
230 if (!cb)
232 switch (sc->type)
234 case T_STRING:
235 cb = PyString_FromStringSafe;
236 data = *second;
237 break;
238 case T_STRING_INPLACE:
239 cb = PyString_FromStringSafe;
240 data = second;
241 break;
242 case T_INT:
243 cb = PyInt_FromLong;
244 data = *second;
245 break;
248 return cb(data);
251 static PyObject *
252 SPy_Set(PyObject *obj, PyObject *value, void *closure)
254 return NULL;
257 static int
258 PyDispatch(void *handler, const char *params, va_list va)
260 PyCallback *callback = handler;
261 PyObject *args, *ret;
262 int count, retval;
263 const char *p;
264 SPyCallback *scallback = callback->_obj;
266 for (count = 0, p = params; *p; p++, count++)
268 if (count > 0)
269 args = PyTuple_New(count);
270 else
271 args = NULL;
273 for (count = 0, p = params; *p; p++, count++)
275 PyObject *item = NULL;
276 switch (*p)
278 case 's':
279 item = PyString_FromStringSafe(va_arg(va, char *));
280 break;
281 case 'S':
283 char **ls = va_arg(va, char **), **iter;
284 int c = 0;
285 for (iter = ls; iter && *iter; iter++, c++)
287 if (c == 0)
288 break;
289 item = PyTuple_New(c);
290 for (c = 0, iter = ls; iter && *iter; iter++, c++)
291 PyTuple_SetItem(item, c, PyString_FromStringSafe(*iter));
293 break;
294 case 'i':
295 item = PyInt_FromLong(va_arg(va, int));
296 break;
297 case 'd':
298 item = PyObject_FromDisplay(va_arg(va, struct display *));
299 break;
302 if (!item)
304 item = Py_None;
305 Py_INCREF(Py_None);
307 PyTuple_SetItem(args, count, item);
310 ret = PyObject_CallObject(scallback->callback, args);
311 Py_DECREF(args);
312 if (!ret)
313 return 0;
315 retval = (int)PyInt_AsLong(ret);
316 Py_DECREF(ret);
317 return retval;
320 /** Screen {{{ */
321 static PyObject *
322 screen_display(PyObject *self)
324 if (!display)
326 RETURN_NONE;
328 return PyObject_FromDisplay(display);
331 static PyObject *
332 screen_displays(PyObject *self)
334 struct display *d = displays;
335 int count = 0;
336 for (; d; d = d->d_next)
337 ++count;
338 PyObject *tuple = PyTuple_New(count);
340 for (d = displays, count = 0; d; d = d->d_next, ++count)
341 PyTuple_SetItem(tuple, count, PyObject_FromDisplay(d));
343 return tuple;
346 static PyObject *
347 screen_windows(PyObject *self)
349 struct win *w = windows;
350 int count = 0;
351 for (; w; w = w->w_next)
352 ++count;
353 PyObject *tuple = PyTuple_New(count);
355 for (w = windows, count = 0; w; w = w->w_next, ++count)
356 PyTuple_SetItem(tuple, count, PyObject_FromWindow(w));
358 return tuple;
361 static PyObject *
362 hook_event(PyObject *self, PyObject *args, PyObject *kw)
364 static char *kwlist[] = {"event", "callback", NULL};
365 PyObject *callback;
366 char *name;
368 struct script_event *sev;
369 struct listener *l;
370 SPyCallback *scallback;
372 if (!PyArg_ParseTupleAndKeywords(args, kw, "sO:screen.hook", kwlist, &name, &callback))
373 return NULL; /* Return Py_None instead? */
375 if (!PyCallable_Check(callback))
377 PyErr_SetString(PyExc_TypeError, "The event-callback functions must be callable.");
378 LMsg(0, "The event-callback functions must be callable.");
379 return NULL;
382 sev = object_get_event(NULL, name);
383 if (!sev)
385 LMsg(0, "No event named '%s'", name);
386 return NULL;
389 l = malloc(sizeof(struct listener));
391 scallback = malloc(sizeof(SPyCallback));
392 scallback->callback = callback;
393 scallback->listener = l;
394 Py_INCREF(scallback->callback);
396 l->handler = PyObject_FromCallback(scallback);
397 l->priv = 0;
398 l->dispatcher = PyDispatch;
399 if (register_listener(sev, l))
401 Py_DECREF((PyObject *)l->handler);
402 FreeCallback(scallback);
403 Free(l);
405 LMsg(0, "Hook could not be registered.");
407 RETURN_NONE;
410 Py_INCREF((PyObject *)l->handler);
411 return l->handler;
414 static void
415 screen_input_cb(char *buf, int len, char *p)
417 PyObject *callback = p;
418 PyObject *str = PyTuple_New(1);
419 PyTuple_SetItem(str, 0, PyString_FromStringSafe(buf));
420 PyObject_CallObject(callback, str);
421 Py_DECREF(str);
422 Py_DECREF(callback);
425 static PyObject *
426 screen_input(PyObject *self, PyObject *args, PyObject *kw)
428 static char *kwlist[] = {"prompt", "callback", "value (optional)", NULL};
429 char *prompt, *pre = NULL;
430 PyObject *callback;
432 if (!PyArg_ParseTupleAndKeywords(args, kw, "sO|s:screen.input", kwlist, &prompt, &callback, &pre))
434 LMsg(0, "Could not parse all the parameters to screen.input call.");
435 return NULL;
438 if (!PyCallable_Check(callback))
440 LMsg(0, "Input callback must be a callable object.");
441 return NULL;
444 Py_INCREF(callback);
445 Input(prompt, 100 /* huh? */,
446 INP_COOKED, screen_input_cb, callback, 0);
448 if (pre && *pre)
450 int len = strlen(pre);
451 LayProcess(&pre, &len);
454 RETURN_NONE;
457 const PyMethodDef py_methods[] = {
458 {"display", (PyCFunction)screen_display, METH_NOARGS, "Get the current display."},
459 {"displays", (PyCFunction)screen_displays, METH_NOARGS, "Get the list of displays."},
460 {"hook", (PyCFunction)hook_event, METH_VARARGS|METH_KEYWORDS, "Hook a callback to an event."},
461 {"input", (PyCFunction)screen_input, METH_VARARGS|METH_KEYWORDS, "Read user input interactively."},
462 {"windows", (PyCFunction)screen_windows, METH_NOARGS, "Get the list of windows."},
463 {NULL, NULL, 0, NULL}
465 /** }}} */
467 static int
468 SPyInit(void)
470 PyObject *m;
472 Py_Initialize();
474 m = Py_InitModule3 ("screen", py_methods, NULL);
475 register_window(m);
476 register_display(m);
477 register_callback(m);
479 return 0;
482 static int
483 SPyFinit(void)
485 Py_Finalize();
486 return 0;
489 static int
490 SPySource(const char *file, int async)
492 FILE *f = fopen(file, "rb");
493 int ret = PyRun_SimpleFile(f, file);
494 fclose(f);
496 if (ret == 0)
497 return 1; /* Success */
499 if (PyErr_Occurred())
501 PyErr_Print();
502 return 0;
505 return 1;
508 struct binding py_binding =
510 "python",
513 SPyInit,
514 SPyFinit,
516 SPySource,