1 /*
2 * gsdlg_lua.c - Lua bindings for gsdlg.c
3 *
4 * Copyright 2007-2008 Jeff Pohlmeyer <yetanothergeek(at)gmail(dot)com>
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 *
22 *
23 *
24 * Some portions of this code were adapted from the Lua standalone
25 * interpreter sources, and may be subject to the terms and conditions
26 * specified under the Lua license. See the file COPYRIGHT.LUA for more
27 * information, or visit http://www.lua.org/license.html .
28 *
29 *
30 */
31
32
33
34 #include <lua.h>
35 #include <lualib.h>
36 #include <lauxlib.h>
37
38
39 #define GSDLG_ALL_IN_ONE
40 #include "gsdlg.h"
41
42 #define LUA_MODULE_NAME "dialog"
43 #define MetaName "_gsdlg_metatable"
44
45
46 #define SetTableValue(name,value,pusher) \
47 lua_pushstring(L, name); \
48 pusher(L, value); \
49 lua_rawset(L,-3);
50
51 #define SetTableStr(name,value) SetTableValue(name,value,lua_pushstring)
52
53
54 #define FAIL_STRING_ARG(argnum) \
55 (fail_arg_type(L,__FUNCTION__,argnum,"string"))
56
57
58 #define FAIL_BOOL_ARG(argnum) \
59 (fail_arg_type(L,__FUNCTION__,argnum,"boolean"))
60
61
62 #define FAIL_TABLE_ARG(argnum) \
63 (fail_arg_type(L,__FUNCTION__,argnum,"table"))
64
65
66 #define FAIL_DBOX_ARG(argnum) \
67 (fail_arg_type(L,__FUNCTION__,argnum,"DialogBox"))
68
69
70 static const gchar*DialogBoxType="DialogBox";
71
72
73
74 typedef struct _DialogBox {
75 const gchar*id;
76 GtkDialog *dlg;
77 } DialogBox;
78
79
80 /* Subtract one from error argnum if we have implicit "self" */
adjust_argnum(lua_State * L,gint argnum)81 static gint adjust_argnum(lua_State *L, gint argnum) {
82 lua_Debug ar;
83 if (lua_getstack(L, 0, &ar)){
84 lua_getinfo(L, "n", &ar);
85 if (g_str_equal(ar.namewhat, "method")) { return argnum-1; }
86 }
87 return argnum;
88 }
89
90
91
92 /* Pushes an error message onto Lua stack if script passes a wrong arg type */
fail_arg_type(lua_State * L,const gchar * func,gint argnum,const gchar * type)93 static gint fail_arg_type(lua_State *L, const gchar *func, gint argnum, const gchar *type)
94 {
95 lua_pushfstring(L, _("Error in module \"%s\" at function %s():\n"
96 " expected type \"%s\" for argument #%d\n"),
97 LUA_MODULE_NAME, func+5, type, adjust_argnum(L, argnum));
98 lua_error(L);
99 return 0;
100 }
101
102
103
104 /*Pushes an error message onto Lua stack if table contains wrong element type*/
gsdl_fail_elem_type(lua_State * L,const gchar * func,gint argnum,gint idx,const gchar * type)105 static gint gsdl_fail_elem_type(
106 lua_State *L, const gchar *func, gint argnum, gint idx, const gchar *type)
107 {
108 lua_pushfstring(L, _("Error in module \"%s\" at function %s():\n"
109 " invalid table in argument #%d:\n"
110 " expected type \"%s\" for element #%d\n"),
111 LUA_MODULE_NAME, func+5, argnum, type, idx);
112 lua_error(L);
113 return 0;
114 }
115
116
117
todialog(lua_State * L,gint argnum)118 static DialogBox* todialog(lua_State *L, gint argnum)
119 {
120 DialogBox*rv=lua_touserdata(L,argnum);
121 return (rv && (DialogBoxType==rv->id))?rv:NULL;
122 }
123
124
125
126 #define DLG_REQUIRE \
127 DialogBox*D=todialog(L,1); \
128 if (!D) { return FAIL_DBOX_ARG(1); }
129
130
131
gsdl_checkbox(lua_State * L)132 static gint gsdl_checkbox(lua_State *L)
133 {
134 DLG_REQUIRE;
135 if ((lua_gettop(L)<4)||!lua_isstring(L,4)) {return FAIL_STRING_ARG(4); }
136 if (!lua_isboolean(L,3)) { return FAIL_BOOL_ARG(3); }
137 if (!lua_isstring(L,2)) { return FAIL_STRING_ARG(2); }
138 gsdlg_checkbox(D->dlg, lua_tostring(L,2),lua_toboolean(L,3),lua_tostring(L,4));
139 return 0;
140 }
141
142
143
gsdl_hr(lua_State * L)144 static gint gsdl_hr(lua_State *L)
145 {
146 DLG_REQUIRE;
147 gsdlg_hr(D->dlg);
148 return 0;
149 }
150
151
152
gsdl_text(lua_State * L)153 static gint gsdl_text(lua_State *L)
154 {
155 DLG_REQUIRE;
156 if ((lua_gettop(L)<4) || !lua_isstring(L,4)) { return FAIL_STRING_ARG(4); }
157 if (!(lua_isstring(L,3)||lua_isnil(L,3))) { return FAIL_STRING_ARG(3); }
158 if (!lua_isstring(L,2)) { return FAIL_STRING_ARG(2); }
159 gsdlg_text(D->dlg, lua_tostring(L,2),lua_tostring(L,3),lua_tostring(L,4));
160 return 0;
161 }
162
163
164
gsdl_password(lua_State * L)165 static gint gsdl_password(lua_State *L)
166 {
167 DLG_REQUIRE;
168 if ((lua_gettop(L)<4) || !lua_isstring(L,4)) { return FAIL_STRING_ARG(4); }
169 if (!(lua_isstring(L,3)||lua_isnil(L,3))) { return FAIL_STRING_ARG(3); }
170 if (!lua_isstring(L,2)) { return FAIL_STRING_ARG(2); }
171 gsdlg_password(D->dlg, lua_tostring(L,2),lua_tostring(L,3),lua_tostring(L,4));
172 return 0;
173 }
174
175
176
gsdl_file(lua_State * L)177 static gint gsdl_file(lua_State *L)
178 {
179 DLG_REQUIRE;
180 if ((lua_gettop(L)<4) || !lua_isstring(L,4)) { return FAIL_STRING_ARG(4); }
181 if (!(lua_isstring(L,3)||lua_isnil(L,3))) { return FAIL_STRING_ARG(3); }
182 if (!lua_isstring(L,2)) { return FAIL_STRING_ARG(2); }
183 gsdlg_file(D->dlg, lua_tostring(L,2),lua_tostring(L,3),lua_tostring(L,4));
184 return 0;
185 }
186
187
188
gsdl_color(lua_State * L)189 static gint gsdl_color(lua_State *L)
190 {
191 DLG_REQUIRE;
192 if ((lua_gettop(L)<4) || !lua_isstring(L,4)) { return FAIL_STRING_ARG(4); }
193 if (!(lua_isstring(L,3)||lua_isnil(L,3))) { return FAIL_STRING_ARG(3); }
194 if (!lua_isstring(L,2)) { return FAIL_STRING_ARG(2); }
195 gsdlg_color(D->dlg, lua_tostring(L,2),lua_tostring(L,3),lua_tostring(L,4));
196 return 0;
197 }
198
199
200
gsdl_font(lua_State * L)201 static gint gsdl_font(lua_State *L)
202 {
203 DLG_REQUIRE;
204 if ((lua_gettop(L)<4) || !lua_isstring(L,4)) { return FAIL_STRING_ARG(4); }
205 if (!(lua_isstring(L,3)||lua_isnil(L,3))) { return FAIL_STRING_ARG(3); }
206 if (!lua_isstring(L,2)) { return FAIL_STRING_ARG(2); }
207 gsdlg_font(D->dlg, lua_tostring(L,2),lua_tostring(L,3),lua_tostring(L,4));
208 return 0;
209 }
210
211
212 #define str_or_nil(argnum) (lua_isstring(L,argnum)||lua_isnil(L,argnum))
213
gsdl_textarea(lua_State * L)214 static gint gsdl_textarea(lua_State *L)
215 {
216 GsDlgStr key=NULL;
217 GsDlgStr value=NULL;
218 GsDlgStr label=NULL;
219 gint argc=lua_gettop(L);
220 DLG_REQUIRE;
221 if (argc>=4) {
222 if (!str_or_nil(4)) { return FAIL_STRING_ARG(4); }
223 label=lua_tostring(L,4);
224 }
225 if (argc>=3) {
226 if (!str_or_nil(3)) { return FAIL_STRING_ARG(3); }
227 value=lua_tostring(L,3);
228 }
229 if ((argc<2)||!lua_isstring(L,2)) {FAIL_STRING_ARG(2);}
230 key=lua_tostring(L,2);
231 gsdlg_textarea(D->dlg, key,value,label);
232 return 0;
233 }
234
235
236
gsdl_group(lua_State * L)237 static gint gsdl_group(lua_State *L)
238 {
239 DLG_REQUIRE;
240 if ((lua_gettop(L)<4) || !lua_isstring(L,4)) { return FAIL_STRING_ARG(4); }
241 if (!lua_isstring(L,3)) { return FAIL_STRING_ARG(3); }
242 if (!lua_isstring(L,2)) { return FAIL_STRING_ARG(2); }
243 gsdlg_group(D->dlg, lua_tostring(L,2),lua_tostring(L,3),lua_tostring(L,4));
244 return 0;
245 }
246
247
248
gsdl_select(lua_State * L)249 static gint gsdl_select(lua_State *L)
250 {
251 DLG_REQUIRE;
252 if ((lua_gettop(L)<4) || !lua_isstring(L,4)) { return FAIL_STRING_ARG(4); }
253 if (!lua_isstring(L,3)) { return FAIL_STRING_ARG(3); }
254 if (!lua_isstring(L,2)) { return FAIL_STRING_ARG(2); }
255 gsdlg_select(D->dlg, lua_tostring(L,2),lua_tostring(L,3),lua_tostring(L,4));
256 return 0;
257 }
258
259
260
gsdl_radio(lua_State * L)261 static gint gsdl_radio(lua_State *L)
262 {
263 DLG_REQUIRE;
264 if ((lua_gettop(L)<4) || !lua_isstring(L,4)) { return FAIL_STRING_ARG(4); }
265 if (!lua_isstring(L,3)) { return FAIL_STRING_ARG(3); }
266 if (!lua_isstring(L,2)) { return FAIL_STRING_ARG(2); }
267 gsdlg_radio(D->dlg, lua_tostring(L,2),lua_tostring(L,3),lua_tostring(L,4));
268 return 0;
269 }
270
271
272
273
274
275
276
277
gsdl_option(lua_State * L)278 static gint gsdl_option(lua_State *L)
279 {
280 DLG_REQUIRE;
281 if ((lua_gettop(L)<4) || !lua_isstring(L,4)) { return FAIL_STRING_ARG(4); }
282 if (!lua_isstring(L,3)) { return FAIL_STRING_ARG(3); }
283 if (!lua_isstring(L,2)) { return FAIL_STRING_ARG(2); }
284 gsdlg_option(D->dlg,
285 lua_tostring(L,2),
286 lua_tostring(L,3),
287 lua_tostring(L,4));
288 return 0;
289 }
290
291
292
gsdl_label(lua_State * L)293 static gint gsdl_label(lua_State *L)
294 {
295 DLG_REQUIRE;
296 if ((lua_gettop(L)<2)||(!lua_isstring(L,2))) { return FAIL_STRING_ARG(2); }
297 gsdlg_label(D->dlg,lua_tostring(L,2));
298 return 0;
299 }
300
301
302
gsdl_heading(lua_State * L)303 static gint gsdl_heading(lua_State *L)
304 {
305 DLG_REQUIRE;
306 if ((lua_gettop(L)<2)||(!lua_isstring(L,2))) { return FAIL_STRING_ARG(2); }
307 gsdlg_heading(D->dlg,lua_tostring(L,2));
308 return 0;
309 }
310
311
312
gsdl_new(lua_State * L)313 static gint gsdl_new(lua_State *L) {
314 gint argc=lua_gettop(L);
315 GsDlgStr title=NULL;
316 GsDlgStr *btns;
317 gint i,n;
318 DialogBox*D;
319 if (argc>=1) {
320 if (!lua_isstring(L,1)) { return FAIL_STRING_ARG(1); }
321 title=lua_tostring(L,1);
322 }
323 if (argc>=2) {
324 if (!lua_istable(L,2)) { return FAIL_TABLE_ARG(2); }
325 }
326 n=lua_objlen(L,2);
327 for (i=1;i<=n; i++) {
328 lua_rawgeti(L,2,i);
329 if (!lua_isstring(L, -1)) {
330 return gsdl_fail_elem_type(L, __FUNCTION__, 2, i, "string");
331 }
332 lua_pop(L, 1);
333 }
334 btns=g_malloc0(sizeof(gchar*)*(n+1));
335 for (i=1;i<=n; i++) {
336 lua_rawgeti(L,2,i);
337 btns[i-1]=lua_tostring(L, -1);
338 lua_pop(L, 1);
339 }
340 D=(DialogBox*)lua_newuserdata(L,sizeof(DialogBox));
341 luaL_getmetatable(L, MetaName);
342 lua_setmetatable(L, -2);
343 D->id=DialogBoxType;
344 D->dlg=gsdlg_new(title,btns);
345 g_free(btns);
346 return 1;
347 }
348
349
350
gsdl_hash_cb(gpointer key,gpointer value,gpointer L)351 static void gsdl_hash_cb(gpointer key, gpointer value, gpointer L)
352 {
353 SetTableStr((gchar*)key, (gchar*)value);
354 }
355
356
357 #define push_num(L,n) lua_pushnumber(L,(lua_Number)n)
358
gsdl_run(lua_State * L)359 static gint gsdl_run(lua_State *L)
360 {
361 gint rv=-1;
362 GHashTable *h;
363 DLG_REQUIRE;
364 h=gsdlg_run(D->dlg, &rv, L);
365 push_num(L,rv+1);
366 if (h) {
367 lua_newtable(L);
368 g_hash_table_foreach(h,gsdl_hash_cb,L);
369 g_hash_table_destroy(h);
370 return 2;
371 }
372 return 1;
373 }
374
375
376
gsdl_done(lua_State * L)377 static gint gsdl_done(lua_State *L)
378 {
379 DialogBox*D;
380 if (lua_isnil(L, 1)) { return 0; }
381 D=(DialogBox*)lua_touserdata(L,1);
382 if (D->id!=DialogBoxType) { return 1; }
383 gtk_widget_destroy(GTK_WIDGET(D->dlg));
384 return 1;
385 }
386
387
388
389
390 static const struct luaL_reg gsdl_funcs[] = {
391 {"new", gsdl_new},
392 {"run", gsdl_run},
393 {"label", gsdl_label},
394 {"text", gsdl_text},
395 {"select", gsdl_select},
396 {"option", gsdl_option},
397 {"group", gsdl_group},
398 {"radio", gsdl_radio},
399 {"password", gsdl_password},
400 {"heading", gsdl_heading},
401 {"checkbox", gsdl_checkbox},
402 {"hr", gsdl_hr},
403 {"textarea", gsdl_textarea},
404 {"file", gsdl_file},
405 {"color", gsdl_color},
406 {"font", gsdl_font},
407 {0,0}
408 };
409
410
411
412 #ifndef DIALOG_LIB
413 static
414 #endif
luaopen_dialog(lua_State * L)415 gint luaopen_dialog(lua_State *L)
416 {
417 gtk_init(NULL,NULL);
418 luaL_newmetatable(L, MetaName);
419 lua_pushstring(L, "__index");
420 lua_pushvalue(L, -2);
421 lua_settable(L, -3);
422
423 luaL_getmetatable(L, MetaName);
424 lua_pushstring(L,"__gc");
425 lua_pushcfunction(L,gsdl_done);
426 lua_rawset(L,-3);
427
428 luaL_openlib(L, NULL, &gsdl_funcs[1], 0);
429 luaL_openlib(L, LUA_MODULE_NAME, gsdl_funcs, 0);
430 return 0;
431 }
432
433
434 #ifndef DIALOG_LIB
glspi_init_gsdlg_module(lua_State * L,GsDlgRunHook hook,GtkWindow * toplevel)435 void glspi_init_gsdlg_module(lua_State *L, GsDlgRunHook hook, GtkWindow *toplevel)
436 {
437 gsdlg_set_run_hook(hook);
438 gsdlg_toplevel=toplevel;
439 luaopen_dialog(L);
440 }
441 #endif
442
443