ELinks 0.12pre1
[elinks/elinks-j605.git] / src / scripting / python / keybinding.c
blob983c1847b764930e0c7ccc63180de51f431c65bd
1 /* Keystroke bindings for Python. */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <Python.h>
9 #include <stdarg.h>
10 #include <string.h>
12 #include "elinks.h"
14 #include "config/kbdbind.h"
15 #include "intl/gettext/libintl.h"
16 #include "main/event.h"
17 #include "scripting/python/core.h"
18 #include "session/session.h"
19 #include "util/error.h"
20 #include "util/string.h"
22 static PyObject *keybindings = NULL;
24 /* C wrapper that invokes Python callbacks for bind_key_to_event_name(). */
26 static enum evhook_status
27 invoke_keybinding_callback(va_list ap, void *data)
29 PyObject *callback = data;
30 struct session *saved_python_ses = python_ses;
31 PyObject *result;
33 python_ses = va_arg(ap, struct session *);
35 result = PyObject_CallFunction(callback, NULL);
36 if (result)
37 Py_DECREF(result);
38 else
39 alert_python_error();
41 python_ses = saved_python_ses;
43 return EVENT_HOOK_STATUS_NEXT;
46 /* Check that a keymap name is valid. */
48 static int
49 keymap_is_valid(const unsigned char *keymap)
51 enum keymap_id keymap_id;
53 for (keymap_id = 0; keymap_id < KEYMAP_MAX; ++keymap_id)
54 if (!strcmp(keymap, get_keymap_name(keymap_id)))
55 break;
56 return (keymap_id != KEYMAP_MAX);
59 /* Python interface for binding keystrokes to callable objects. */
61 static char python_bind_key_doc[] =
62 PYTHON_DOCSTRING("bind_key(keystroke, callback[, keymap]) -> None\n\
63 \n\
64 Bind a keystroke to a callable object.\n\
65 \n\
66 Arguments:\n\
67 \n\
68 keystroke -- A string containing a keystroke. The syntax for\n\
69 keystrokes is described in the elinkskeys(5) man page.\n\
70 callback -- A callable object to be called when the keystroke is\n\
71 typed. It will be called without any arguments.\n\
72 \n\
73 Optional arguments:\n\
74 \n\
75 keymap -- A string containing the name of a keymap. Valid keymap\n\
76 names can be found in the elinkskeys(5) man page. By\n\
77 default the \"main\" keymap is used.\n");
79 static PyObject *
80 python_bind_key(PyObject *self, PyObject *args, PyObject *kwargs)
82 const unsigned char *keystroke;
83 PyObject *callback;
84 unsigned char *keymap = "main";
85 PyObject *key_tuple;
86 PyObject *old_callback;
87 struct string event_name;
88 int event_id;
89 unsigned char *error_msg;
90 static char *kwlist[] = {"keystroke", "callback", "keymap", NULL};
92 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|s:bind_key", kwlist,
93 &keystroke, &callback, &keymap))
94 return NULL;
96 assert(keystroke && callback && keymap);
97 if_assert_failed {
98 PyErr_SetString(python_elinks_err, N_("Internal error"));
99 return NULL;
102 if (!keymap_is_valid(keymap)) {
103 PyErr_Format(python_elinks_err, "%s \"%s\"",
104 N_("Unrecognised keymap"), keymap);
105 return NULL;
109 * The callback object needs to be kept alive for as long as the
110 * keystroke is bound, so we stash a reference to it in a dictionary.
111 * We don't need to use the dictionary to find callbacks; its sole
112 * purpose is to prevent these objects from being garbage-collected
113 * by the Python interpreter.
115 * If binding the key fails for any reason after this point then
116 * we'll need to restore the dictionary to its previous state, which
117 * is temporarily preserved in @old_callback.
119 key_tuple = Py_BuildValue("ss", keymap, keystroke);
120 if (!key_tuple)
121 return NULL;
122 old_callback = PyDict_GetItem(keybindings, key_tuple);
123 Py_XINCREF(old_callback);
124 if (PyDict_SetItem(keybindings, key_tuple, callback) != 0) {
125 Py_DECREF(key_tuple);
126 Py_XDECREF(old_callback);
127 return NULL;
130 if (!init_string(&event_name)) {
131 PyErr_NoMemory();
132 goto rollback;
134 if (!add_format_to_string(&event_name, "python-func %p", callback)) {
135 PyErr_SetFromErrno(python_elinks_err);
136 done_string(&event_name);
137 goto rollback;
139 event_id = bind_key_to_event_name(keymap, keystroke, event_name.source,
140 &error_msg);
141 done_string(&event_name);
142 if (error_msg) {
143 PyErr_SetString(python_elinks_err, error_msg);
144 goto rollback;
147 event_id = register_event_hook(event_id, invoke_keybinding_callback, 0,
148 callback);
149 if (event_id == EVENT_NONE) {
150 PyErr_SetString(python_elinks_err,
151 N_("Error registering event hook"));
152 goto rollback;
155 Py_DECREF(key_tuple);
156 Py_XDECREF(old_callback);
158 Py_INCREF(Py_None);
159 return Py_None;
161 rollback:
163 * If an error occurred, try to restore the keybindings dictionary
164 * to its previous state.
166 if (old_callback) {
167 (void) PyDict_SetItem(keybindings, key_tuple, old_callback);
168 Py_DECREF(old_callback);
169 } else {
170 (void) PyDict_DelItem(keybindings, key_tuple);
173 Py_DECREF(key_tuple);
174 return NULL;
177 static PyMethodDef keybinding_methods[] = {
178 {"bind_key", (PyCFunction) python_bind_key,
179 METH_VARARGS | METH_KEYWORDS,
180 python_bind_key_doc},
182 {NULL, NULL, 0, NULL}
186 python_init_keybinding_interface(PyObject *dict, PyObject *name)
188 keybindings = PyDict_New();
189 if (!keybindings) return -1;
191 return add_python_methods(dict, name, keybinding_methods);
194 void
195 python_done_keybinding_interface(void)
197 PyObject *temp;
199 /* This is equivalent to Py_CLEAR(), but it works with older
200 * versions of Python predating that macro: */
201 temp = keybindings;
202 keybindings = NULL;
203 Py_XDECREF(temp);