Bug 846: Separate JS_GetParent & JS_GetPrivate calls from initializations.
[elinks.git] / src / scripting / smjs / keybinding.c
blob10818ea0793770f6ca8adbfbe7ba1d9626d70bbe
1 /* "elinks.keymaps" */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include "elinks.h"
9 #include "config/kbdbind.h"
10 #include "ecmascript/spidermonkey/util.h"
11 #include "main/event.h"
12 #include "scripting/smjs/core.h"
13 #include "scripting/smjs/elinks_object.h"
14 #include "util/memory.h"
16 /* @keymap_class.getProperty */
17 static JSBool
18 keymap_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
20 unsigned char *action_str;
21 const unsigned char *keystroke_str;
22 int *data;
23 enum keymap_id keymap_id = *data;
25 data = JS_GetPrivate(ctx, obj); /* from @keymap_class */
27 keystroke_str = JS_GetStringBytes(JS_ValueToString(ctx, id));
28 if (!keystroke_str) goto ret_null;
30 action_str = get_action_name_from_keystroke(keymap_id, keystroke_str);
31 if (!action_str) goto ret_null;
33 *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(ctx, action_str));
35 return JS_TRUE;
37 ret_null:
38 *vp = JSVAL_NULL;
40 return JS_TRUE;
43 static enum evhook_status
44 smjs_keybinding_action_callback(va_list ap, void *data)
46 jsval rval;
47 struct session *ses = va_arg(ap, struct session *);
48 JSObject *jsobj = data;
49 JSFunction *func = JS_ValueToFunction(smjs_ctx, OBJECT_TO_JSVAL(jsobj));
51 evhook_use_params(ses);
53 assert(func);
55 smjs_ses = ses;
57 JS_CallFunction(smjs_ctx, NULL, func, 0, NULL, &rval);
59 smjs_ses = NULL;
61 return EVENT_HOOK_STATUS_LAST;
64 /* @keymap_class.setProperty */
65 static JSBool
66 keymap_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
68 int *data;
69 enum keymap_id keymap_id = *data;
70 unsigned char *keymap_str;
71 const unsigned char *keystroke_str;
73 data = JS_GetPrivate(ctx, obj); /* from @keymap_class */
75 /* Ugly fact: we need to get the string from the id to give to bind_do,
76 * which will of course then convert the string back to an id... */
77 keymap_str = get_keymap_name(keymap_id);
78 if (!keymap_str) return JS_FALSE;
80 keystroke_str = JS_GetStringBytes(JS_ValueToString(ctx, id));
81 if (!keystroke_str) return JS_FALSE;
83 if (JSVAL_IS_STRING(*vp)) {
84 unsigned char *action_str;
86 action_str = JS_GetStringBytes(JS_ValueToString(ctx, *vp));
87 if (!action_str) return JS_FALSE;
89 if (bind_do(keymap_str, keystroke_str, action_str, 0))
90 return JS_FALSE;
92 return JS_TRUE;
94 } else if (JSVAL_IS_OBJECT(*vp)) {
95 unsigned char *err = NULL;
96 int event_id;
97 struct string event_name = NULL_STRING;
98 JSObject *jsobj = JSVAL_TO_OBJECT(*vp);
100 if (JS_FALSE == JS_ObjectIsFunction(ctx, jsobj))
101 return JS_FALSE;
103 if (!init_string(&event_name)) return JS_FALSE;
105 add_format_to_string(&event_name, "smjs-run-func %p", jsobj);
107 event_id = bind_key_to_event_name(keymap_str,
108 keystroke_str,
109 event_name.source, &err);
111 done_string(&event_name);
113 if (err) {
114 alert_smjs_error(err);
116 return JS_FALSE;
119 event_id = register_event_hook(event_id,
120 smjs_keybinding_action_callback,
121 0, (void *) jsobj);
123 if (event_id == EVENT_NONE) {
124 alert_smjs_error("error registering event hook"
125 " for keybinding");
127 return JS_FALSE;
130 return JS_TRUE;
133 return JS_FALSE;
136 /* @keymap_class.finalize */
137 static void
138 keymap_finalize(JSContext *ctx, JSObject *obj)
140 void *data;
142 data = JS_GetPrivate(ctx, obj); /* from @keymap_class */
144 mem_free(data);
147 static const JSClass keymap_class = {
148 "keymap",
149 JSCLASS_HAS_PRIVATE, /* int * */
150 JS_PropertyStub, JS_PropertyStub,
151 keymap_get_property, keymap_set_property,
152 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, keymap_finalize,
155 static JSObject *
156 smjs_get_keymap_object(enum keymap_id keymap_id)
158 int *data;
159 JSObject *keymap_object;
161 assert(smjs_ctx);
163 keymap_object = JS_NewObject(smjs_ctx, (JSClass *) &keymap_class,
164 NULL, NULL);
166 if (!keymap_object) return NULL;
168 data = intdup(keymap_id);
169 if (!data) return NULL;
171 if (JS_TRUE == JS_SetPrivate(smjs_ctx, keymap_object, data)) /* to @keymap_class */
172 return keymap_object;
174 mem_free(data);
176 return NULL;
179 static const JSClass keymaps_hash_class = {
180 "keymaps_hash",
181 JSCLASS_HAS_PRIVATE,
182 JS_PropertyStub, JS_PropertyStub,
183 JS_PropertyStub, JS_PropertyStub,
184 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
187 static JSObject *
188 smjs_get_keymap_hash_object(void)
190 jsval val;
191 enum keymap_id keymap_id;
192 JSObject *keymaps_hash;
194 keymaps_hash = JS_NewObject(smjs_ctx, (JSClass *) &keymaps_hash_class,
195 NULL, NULL);
196 if (!keymaps_hash) return NULL;
198 for (keymap_id = 0; keymap_id < KEYMAP_MAX; ++keymap_id) {
199 unsigned char *keymap_str = get_keymap_name(keymap_id);
200 JSObject *map = smjs_get_keymap_object(keymap_id);
202 assert(keymap_str);
204 if (!map) return NULL;
206 val = OBJECT_TO_JSVAL(map);
208 JS_SetProperty(smjs_ctx, keymaps_hash, keymap_str, &val);
211 return keymaps_hash;
214 void
215 smjs_init_keybinding_interface(void)
217 jsval val;
218 struct JSObject *keymaps_hash;
220 if (!smjs_ctx || !smjs_elinks_object)
221 return;
223 keymaps_hash = smjs_get_keymap_hash_object();
224 if (!keymaps_hash) return;
226 val = OBJECT_TO_JSVAL(keymaps_hash);
228 JS_SetProperty(smjs_ctx, smjs_elinks_object, "keymaps", &val);