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