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)
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>
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
);
54 struct listener
*listener
;
65 PyObject
* (*conv
)(void *);
66 int (*setter
)(void *, PyObject
*);
70 #define compare_callback NULL
71 #define repr_callback NULL
73 #define REGISTER_TYPE(type, Type, closures, methods) \
75 register_##type(PyObject *module) \
77 static PyGetSetDef getsets[sizeof(closures)]; \
78 int i, count = sizeof(closures); \
79 for (i = 0; i < count; i++) \
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; \
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); \
98 #define DEFINE_TYPE(str, Type) \
101 ScreenObject __parent; \
105 static PyTypeObject PyType##Type = \
107 PyObject_HEAD_INIT(NULL) \
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, \
118 PyObject_From##Type(str *_obj) \
120 Py##Type *obj = PyType##Type.tp_alloc(&PyType##Type, 0); \
122 return (PyObject *)obj; \
126 PyString_FromStringSafe(const char *str
)
129 return PyString_FromString(str
);
133 /** Generic Object {{{ */
141 object_hook(PyObject
*self
, PyObject
*args
, PyObject
*kw
)
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."},
153 static PyTypeObject ScreenObjectType
=
155 PyObject_HEAD_INIT(NULL
)
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
,
166 register_object(PyObject
*module
)
168 PyType_Ready(&ScreenObjectType
);
169 Py_INCREF(&ScreenObjectType
);
170 PyModule_AddObject(module
, "Generic Object", (PyObject
*)&ScreenObjectType
);
176 DEFINE_TYPE(struct win
, Window
)
179 window_set_title(struct win
*win
, PyObject
*value
)
181 char *string
= PyString_AsString(value
);
182 if (!string
|| !*string
)
184 ChangeAKA(win
, string
, strlen(string
));
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
),
202 window_select(PyObject
*self
)
204 PyWindow
*win
= self
;
205 struct win
*w
= win
->_obj
;
206 SwitchWindow(w
->w_number
);
210 static PyMethodDef wmethods
[] = {
211 {"select", (PyCFunction
)window_select
, METH_NOARGS
, "Select the window."},
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
;
225 repr_window(PyObject
*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
)
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
),
251 static PyMethodDef dmethods
[] =
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
)
266 for (iter
= displays
; iter
; iter
= iter
->d_next
)
269 else if (iter
== dtwo
)
276 repr_display(PyObject
*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
)
288 DEFINE_TYPE(SPyCallback
, Callback
)
289 static SPyClosure cclosures
[] = {{NULL
}};
292 FreeCallback(SPyCallback
*scallback
)
294 Py_XDECREF(scallback
->callback
);
299 callback_unhook(PyObject
*obj
)
301 PyCallback
*cb
= obj
;
302 SPyCallback
*scallback
= cb
->_obj
;
305 unregister_listener(scallback
->listener
);
306 FreeCallback(scallback
);
311 static PyMethodDef cmethods
[] = {
312 {"unhook", (PyCFunction
)callback_unhook
, METH_NOARGS
, "Unhook this event callback."},
315 REGISTER_TYPE(callback
, Callback
, cclosures
, cmethods
)
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
;
332 cb
= PyString_FromStringSafe
;
335 case T_STRING_INPLACE
:
336 cb
= PyString_FromStringSafe
;
349 SPy_Set(PyObject
*obj
, PyObject
*value
, void *closure
)
351 SPyClosure
*sc
= closure
;
352 char **first
= (char *)obj
+ sc
->offset1
;
355 PyErr_SetString(PyExc_TypeError
, "Cannot remove an attribute value.");
358 if (sc
->setter
== NULL
)
361 snprintf(str
, sizeof(str
) - 1, "Cannot change '%s'.", sc
->name
);
362 PyErr_SetString(PyExc_TypeError
, str
);
366 return sc
->setter(*(void **)first
, value
);
370 PyDispatch(void *handler
, const char *params
, va_list va
)
372 PyCallback
*callback
= handler
;
373 PyObject
*args
, *ret
;
376 SPyCallback
*scallback
= callback
->_obj
;
378 for (count
= 0, p
= params
; *p
; p
++, count
++)
381 args
= PyTuple_New(count
);
385 for (count
= 0, p
= params
; *p
; p
++, count
++)
387 PyObject
*item
= NULL
;
391 item
= PyString_FromStringSafe(va_arg(va
, char *));
395 char **ls
= va_arg(va
, char **), **iter
;
397 for (iter
= ls
; iter
&& *iter
; iter
++, c
++)
401 item
= PyTuple_New(c
);
402 for (c
= 0, iter
= ls
; iter
&& *iter
; iter
++, c
++)
403 PyTuple_SetItem(item
, c
, PyString_FromStringSafe(*iter
));
407 item
= PyInt_FromLong(va_arg(va
, int));
410 item
= PyObject_FromDisplay(va_arg(va
, struct display
*));
419 PyTuple_SetItem(args
, count
, item
);
422 ret
= PyObject_CallObject(scallback
->callback
, args
);
427 retval
= (int)PyInt_AsLong(ret
);
433 register_event_hook(PyObject
*self
, PyObject
*args
, PyObject
*kw
, void *object
)
435 static char *kwlist
[] = {"event", "callback", NULL
};
440 struct script_event
*sev
;
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.");
454 sev
= object_get_event(object
, name
);
457 LMsg(0, "No event named '%s'", name
);
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
);
470 l
->dispatcher
= PyDispatch
;
471 if (register_listener(sev
, l
))
473 Py_DECREF((PyObject
*)l
->handler
);
474 FreeCallback(scallback
);
477 LMsg(0, "Hook could not be registered.");
482 Py_INCREF((PyObject
*)l
->handler
);
490 screen_display(PyObject
*self
)
496 return PyObject_FromDisplay(display
);
500 screen_displays(PyObject
*self
)
502 struct display
*d
= displays
;
504 for (; d
; d
= d
->d_next
)
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
));
515 screen_windows(PyObject
*self
)
517 struct win
*w
= windows
;
519 for (; w
; w
= w
->w_next
)
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
));
530 hook_event(PyObject
*self
, PyObject
*args
, PyObject
*kw
)
532 return register_event_hook(self
, args
, kw
, NULL
);
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
);
547 screen_input(PyObject
*self
, PyObject
*args
, PyObject
*kw
)
549 static char *kwlist
[] = {"prompt", "callback", "value (optional)", NULL
};
550 char *prompt
, *pre
= NULL
;
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.");
559 if (!PyCallable_Check(callback
))
561 LMsg(0, "Input callback must be a callable object.");
566 Input(prompt
, 100 /* huh? */,
567 INP_COOKED
, screen_input_cb
, callback
, 0);
571 int len
= strlen(pre
);
572 LayProcess(&pre
, &len
);
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
}
588 static PyObject
*module
;
596 m
= Py_InitModule3 ("screen", py_methods
, NULL
);
600 register_callback(m
);
614 SPySource(const char *file
, int async
)
616 FILE *f
= fopen(file
, "rb");
617 int ret
= PyRun_SimpleFile(f
, file
);
621 return 1; /* Success */
623 if (PyErr_Occurred())
633 SPyCall(char *func
, char **argv
)
635 PyObject
*dict
= PyModule_GetDict(module
);
636 PyObject
*f
= PyDict_GetItemString(dict
, func
);
642 ret
= PyEval_CallFunction(f
, "s", argv
[0]);
647 struct binding py_binding
=