Lua: return nil when function failed instead of returning nothing
[kugel-rb.git] / apps / plugins / lua / rocklib.c
blob73c3851bc1ea3451e6861dfd1c565a23bd32dc87
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2008 Dan Everton (safetydan)
11 * Copyright (C) 2009 Maurus Cuelenaere
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
23 #define lrocklib_c
24 #define LUA_LIB
26 #include "lua.h"
28 #include "lauxlib.h"
29 #include "rocklib.h"
30 #include "lib/helper.h"
33 * http://www.lua.org/manual/5.1/manual.html#lua_CFunction
35 * In order to communicate properly with Lua, a C function must use the following protocol,
36 * which defines the way parameters and results are passed: a C function receives its arguments
37 * from Lua in its stack in direct order (the first argument is pushed first). To return values to Lua,
38 * a C function just pushes them onto the stack, in direct order (the first result is pushed first),
39 * and returns the number of results. Any other value in the stack below the results will be properly
40 * discarded by Lua. Like a Lua function, a C function called by Lua can also return many results.
45 * -----------------------------
47 * Rockbox Lua image wrapper
49 * -----------------------------
52 #define ROCKLUA_IMAGE "rb.image"
53 struct rocklua_image
55 int width;
56 int height;
57 fb_data *data;
58 fb_data dummy[1][1];
61 static void rli_wrap(lua_State *L, fb_data *src, int width, int height)
63 struct rocklua_image *a = (struct rocklua_image *)lua_newuserdata(L, sizeof(struct rocklua_image));
65 luaL_getmetatable(L, ROCKLUA_IMAGE);
66 lua_setmetatable(L, -2);
68 a->width = width;
69 a->height = height;
70 a->data = src;
73 static fb_data* rli_alloc(lua_State *L, int width, int height)
75 size_t nbytes = sizeof(struct rocklua_image) + ((width*height) - 1) * sizeof(fb_data);
76 struct rocklua_image *a = (struct rocklua_image *)lua_newuserdata(L, nbytes);
78 luaL_getmetatable(L, ROCKLUA_IMAGE);
79 lua_setmetatable(L, -2);
81 a->width = width;
82 a->height = height;
83 a->data = &a->dummy[0][0];
85 return a->data;
88 static int rli_new(lua_State *L)
90 int width = luaL_checkint(L, 1);
91 int height = luaL_checkint(L, 2);
93 rli_alloc(L, width, height);
95 return 1;
98 static struct rocklua_image* rli_checktype(lua_State *L, int arg)
100 void *ud = luaL_checkudata(L, arg, ROCKLUA_IMAGE);
101 luaL_argcheck(L, ud != NULL, arg, "'" ROCKLUA_IMAGE "' expected");
102 return (struct rocklua_image*) ud;
105 static int rli_width(lua_State *L)
107 struct rocklua_image *a = rli_checktype(L, 1);
108 lua_pushnumber(L, a->width);
109 return 1;
112 static int rli_height(lua_State *L)
114 struct rocklua_image *a = rli_checktype(L, 1);
115 lua_pushnumber(L, a->height);
116 return 1;
119 static fb_data* rli_element(lua_State *L)
121 struct rocklua_image *a = rli_checktype(L, 1);
122 int x = luaL_checkint(L, 2);
123 int y = luaL_checkint(L, 3);
125 luaL_argcheck(L, 1 <= x && x <= a->width, 2,
126 "index out of range");
127 luaL_argcheck(L, 1 <= y && y <= a->height, 3,
128 "index out of range");
130 /* return element address */
131 return &a->data[a->width * (y - 1) + (x - 1)];
134 static int rli_set(lua_State *L)
136 fb_data newvalue = (fb_data) luaL_checknumber(L, 4);
137 *rli_element(L) = newvalue;
138 return 0;
141 static int rli_get(lua_State *L)
143 lua_pushnumber(L, *rli_element(L));
144 return 1;
147 static int rli_tostring(lua_State *L)
149 struct rocklua_image *a = rli_checktype(L, 1);
150 lua_pushfstring(L, ROCKLUA_IMAGE ": %dx%d", a->width, a->height);
151 return 1;
154 static const struct luaL_reg rli_lib [] =
156 {"__tostring", rli_tostring},
157 {"set", rli_set},
158 {"get", rli_get},
159 {"width", rli_width},
160 {"height", rli_height},
161 {NULL, NULL}
164 static inline void rli_init(lua_State *L)
166 luaL_newmetatable(L, ROCKLUA_IMAGE);
168 lua_pushstring(L, "__index");
169 lua_pushvalue(L, -2); /* pushes the metatable */
170 lua_settable(L, -3); /* metatable.__index = metatable */
172 luaL_register(L, NULL, rli_lib);
176 * -----------------------------
178 * Rockbox wrappers start here!
180 * -----------------------------
183 #define RB_WRAP(M) static int rock_##M(lua_State *L)
184 #define SIMPLE_VOID_WRAPPER(func) RB_WRAP(func) { (void)L; func(); return 0; }
186 /* Helper function for opt_viewport */
187 static void check_tablevalue(lua_State *L, const char* key, int tablepos, void* res, bool unsigned_val)
189 lua_getfield(L, tablepos, key); /* Find table[key] */
191 if(!lua_isnoneornil(L, -1))
193 if(unsigned_val)
194 *(unsigned*)res = luaL_checkint(L, -1);
195 else
196 *(int*)res = luaL_checkint(L, -1);
199 lua_pop(L, 1); /* Pop the value off the stack */
202 static struct viewport* opt_viewport(lua_State *L, int narg, struct viewport* alt)
204 if(lua_isnoneornil(L, narg))
205 return alt;
207 int tablepos = lua_gettop(L);
208 struct viewport *vp;
210 lua_getfield(L, tablepos, "vp"); /* get table['vp'] */
211 if(lua_isnoneornil(L, -1))
213 lua_pop(L, 1); /* Pop nil off stack */
215 vp = (struct viewport*) lua_newuserdata(L, sizeof(struct viewport)); /* Allocate memory and push it as udata on the stack */
216 memset(vp, 0, sizeof(struct viewport)); /* Init viewport values to 0 */
217 lua_setfield(L, tablepos, "vp"); /* table['vp'] = vp (pops value off the stack) */
219 else
221 vp = (struct viewport*) lua_touserdata(L, -1); /* Reuse viewport struct */
222 lua_pop(L, 1); /* We don't need the value on stack */
225 luaL_checktype(L, narg, LUA_TTABLE);
227 check_tablevalue(L, "x", tablepos, &vp->x, false);
228 check_tablevalue(L, "y", tablepos, &vp->y, false);
229 check_tablevalue(L, "width", tablepos, &vp->width, false);
230 check_tablevalue(L, "height", tablepos, &vp->height, false);
231 #ifdef HAVE_LCD_BITMAP
232 check_tablevalue(L, "font", tablepos, &vp->font, false);
233 check_tablevalue(L, "drawmode", tablepos, &vp->drawmode, false);
234 #endif
235 #if LCD_DEPTH > 1
236 check_tablevalue(L, "fg_pattern", tablepos, &vp->fg_pattern, true);
237 check_tablevalue(L, "bg_pattern", tablepos, &vp->bg_pattern, true);
238 #ifdef HAVE_LCD_COLOR
239 check_tablevalue(L, "lss_pattern", tablepos, &vp->lss_pattern, true);
240 check_tablevalue(L, "lse_pattern", tablepos, &vp->lse_pattern, true);
241 check_tablevalue(L, "lst_pattern", tablepos, &vp->lst_pattern, true);
242 #endif
243 #endif
245 return vp;
248 RB_WRAP(set_viewport)
250 struct viewport *vp = opt_viewport(L, 1, NULL);
251 int screen = luaL_optint(L, 2, SCREEN_MAIN);
252 rb->screens[screen]->set_viewport(vp);
253 return 0;
256 RB_WRAP(clear_viewport)
258 int screen = luaL_optint(L, 1, SCREEN_MAIN);
259 rb->screens[screen]->clear_viewport();
260 return 0;
263 #ifdef HAVE_LCD_BITMAP
264 RB_WRAP(lcd_framebuffer)
266 rli_wrap(L, rb->lcd_framebuffer, LCD_WIDTH, LCD_HEIGHT);
267 return 1;
270 RB_WRAP(lcd_mono_bitmap_part)
272 struct rocklua_image *src = rli_checktype(L, 1);
273 int src_x = luaL_checkint(L, 2);
274 int src_y = luaL_checkint(L, 3);
275 int stride = luaL_checkint(L, 4);
276 int x = luaL_checkint(L, 5);
277 int y = luaL_checkint(L, 6);
278 int width = luaL_checkint(L, 7);
279 int height = luaL_checkint(L, 8);
280 int screen = luaL_optint(L, 9, SCREEN_MAIN);
282 rb->screens[screen]->mono_bitmap_part((const unsigned char *)src->data, src_x, src_y, stride, x, y, width, height);
283 return 0;
286 RB_WRAP(lcd_mono_bitmap)
288 struct rocklua_image *src = rli_checktype(L, 1);
289 int x = luaL_checkint(L, 2);
290 int y = luaL_checkint(L, 3);
291 int width = luaL_checkint(L, 4);
292 int height = luaL_checkint(L, 5);
293 int screen = luaL_optint(L, 6, SCREEN_MAIN);
295 rb->screens[screen]->mono_bitmap((const unsigned char *)src->data, x, y, width, height);
296 return 0;
299 #if LCD_DEPTH > 1
300 RB_WRAP(lcd_bitmap_part)
302 struct rocklua_image *src = rli_checktype(L, 1);
303 int src_x = luaL_checkint(L, 2);
304 int src_y = luaL_checkint(L, 3);
305 int stride = luaL_checkint(L, 4);
306 int x = luaL_checkint(L, 5);
307 int y = luaL_checkint(L, 6);
308 int width = luaL_checkint(L, 7);
309 int height = luaL_checkint(L, 8);
310 int screen = luaL_optint(L, 9, SCREEN_MAIN);
312 rb->screens[screen]->bitmap_part(src->data, src_x, src_y, stride, x, y, width, height);
313 return 0;
316 RB_WRAP(lcd_bitmap)
318 struct rocklua_image *src = rli_checktype(L, 1);
319 int x = luaL_checkint(L, 2);
320 int y = luaL_checkint(L, 3);
321 int width = luaL_checkint(L, 4);
322 int height = luaL_checkint(L, 5);
323 int screen = luaL_optint(L, 6, SCREEN_MAIN);
325 rb->screens[screen]->bitmap(src->data, x, y, width, height);
326 return 0;
329 RB_WRAP(lcd_get_backdrop)
331 fb_data* backdrop = rb->lcd_get_backdrop();
332 if(backdrop == NULL)
333 lua_pushnil(L);
334 else
335 rli_wrap(L, backdrop, LCD_WIDTH, LCD_HEIGHT);
337 return 1;
339 #endif /* LCD_DEPTH > 1 */
341 #if LCD_DEPTH == 16
342 RB_WRAP(lcd_bitmap_transparent_part)
344 struct rocklua_image *src = rli_checktype(L, 1);
345 int src_x = luaL_checkint(L, 2);
346 int src_y = luaL_checkint(L, 3);
347 int stride = luaL_checkint(L, 4);
348 int x = luaL_checkint(L, 5);
349 int y = luaL_checkint(L, 6);
350 int width = luaL_checkint(L, 7);
351 int height = luaL_checkint(L, 8);
352 int screen = luaL_optint(L, 9, SCREEN_MAIN);
354 rb->screens[screen]->transparent_bitmap_part(src->data, src_x, src_y, stride, x, y, width, height);
355 return 0;
358 RB_WRAP(lcd_bitmap_transparent)
360 struct rocklua_image *src = rli_checktype(L, 1);
361 int x = luaL_checkint(L, 2);
362 int y = luaL_checkint(L, 3);
363 int width = luaL_checkint(L, 4);
364 int height = luaL_checkint(L, 5);
365 int screen = luaL_optint(L, 6, SCREEN_MAIN);
367 rb->screens[screen]->transparent_bitmap(src->data, x, y, width, height);
368 return 0;
370 #endif /* LCD_DEPTH == 16 */
372 #endif /* defined(LCD_BITMAP) */
374 RB_WRAP(current_tick)
376 lua_pushinteger(L, *rb->current_tick);
377 return 1;
380 #ifdef HAVE_TOUCHSCREEN
381 RB_WRAP(action_get_touchscreen_press)
383 short x, y;
384 int result = rb->action_get_touchscreen_press(&x, &y);
386 lua_pushinteger(L, result);
387 lua_pushinteger(L, x);
388 lua_pushinteger(L, y);
389 return 3;
391 #endif
393 RB_WRAP(kbd_input)
395 luaL_Buffer b;
396 luaL_buffinit(L, &b);
398 const char *input = luaL_optstring(L, 1, NULL);
399 char *buffer = luaL_prepbuffer(&b);
401 if(input != NULL)
402 rb->strlcpy(buffer, input, LUAL_BUFFERSIZE);
403 else
404 buffer[0] = '\0';
406 if(!rb->kbd_input(buffer, LUAL_BUFFERSIZE))
408 luaL_addsize(&b, strlen(buffer));
409 luaL_pushresult(&b);
411 else
412 lua_pushnil(L);
414 return 1;
417 #ifdef HAVE_TOUCHSCREEN
418 RB_WRAP(touchscreen_set_mode)
420 enum touchscreen_mode mode = luaL_checkint(L, 1);
421 rb->touchscreen_set_mode(mode);
422 return 0;
424 #endif
426 RB_WRAP(font_getstringsize)
428 const unsigned char* str = luaL_checkstring(L, 1);
429 int fontnumber = luaL_checkint(L, 2);
430 int w, h;
432 int result = rb->font_getstringsize(str, &w, &h, fontnumber);
433 lua_pushinteger(L, result);
434 lua_pushinteger(L, w);
435 lua_pushinteger(L, h);
437 return 3;
440 #ifdef HAVE_LCD_COLOR
441 RB_WRAP(lcd_rgbpack)
443 int r = luaL_checkint(L, 1);
444 int g = luaL_checkint(L, 2);
445 int b = luaL_checkint(L, 3);
446 int result = LCD_RGBPACK(r, g, b);
447 lua_pushinteger(L, result);
448 return 1;
451 RB_WRAP(lcd_rgbunpack)
453 int rgb = luaL_checkint(L, 1);
454 lua_pushinteger(L, RGB_UNPACK_RED(rgb));
455 lua_pushinteger(L, RGB_UNPACK_GREEN(rgb));
456 lua_pushinteger(L, RGB_UNPACK_BLUE(rgb));
457 return 3;
459 #endif
461 RB_WRAP(read_bmp_file)
463 struct bitmap bm;
464 const char* filename = luaL_checkstring(L, 1);
465 bool dither = luaL_optboolean(L, 2, true);
466 bool transparent = luaL_optboolean(L, 3, false);
467 int format = FORMAT_NATIVE;
469 if(dither)
470 format |= FORMAT_DITHER;
472 if(transparent)
473 format |= FORMAT_TRANSPARENT;
475 int result = rb->read_bmp_file(filename, &bm, 0, format | FORMAT_RETURN_SIZE, NULL);
477 if(result > 0)
479 bm.data = (unsigned char*) rli_alloc(L, bm.width, bm.height);
480 if(rb->read_bmp_file(filename, &bm, result, format, NULL) < 0)
482 /* Error occured, drop newly allocated image from stack */
483 lua_pop(L, 1);
484 lua_pushnil(L);
487 else
488 lua_pushnil(L);
490 return 1;
493 RB_WRAP(current_path)
495 const char *current_path = get_current_path(L, 1);
496 if(current_path != NULL)
497 lua_pushstring(L, current_path);
498 else
499 lua_pushnil(L);
501 return 1;
504 static void fill_text_message(lua_State *L, struct text_message * message,
505 int pos)
507 int i;
508 luaL_checktype(L, pos, LUA_TTABLE);
509 int n = luaL_getn(L, pos);
510 const char **lines = (const char**) dlmalloc(n * sizeof(const char*));
511 if(lines == NULL)
512 luaL_error(L, "Can't allocate %d bytes!", n * sizeof(const char*));
513 for(i=1; i<=n; i++)
515 lua_rawgeti(L, pos, i);
516 lines[i-1] = luaL_checkstring(L, -1);
517 lua_pop(L, 1);
519 message->message_lines = lines;
520 message->nb_lines = n;
523 RB_WRAP(gui_syncyesno_run)
525 struct text_message main_message, yes_message, no_message;
526 struct text_message *yes = NULL, *no = NULL;
528 fill_text_message(L, &main_message, 1);
529 if(!lua_isnoneornil(L, 2))
530 fill_text_message(L, (yes = &yes_message), 2);
531 if(!lua_isnoneornil(L, 3))
532 fill_text_message(L, (no = &no_message), 3);
534 enum yesno_res result = rb->gui_syncyesno_run(&main_message, yes, no);
536 dlfree(main_message.message_lines);
537 if(yes)
538 dlfree(yes_message.message_lines);
539 if(no)
540 dlfree(no_message.message_lines);
542 lua_pushinteger(L, result);
543 return 1;
546 RB_WRAP(do_menu)
548 struct menu_callback_with_desc menu_desc = {NULL, NULL, Icon_NOICON};
549 struct menu_item_ex menu = {MT_RETURN_ID | MENU_HAS_DESC, {.strings = NULL},
550 {.callback_and_desc = &menu_desc}};
551 int i, n, start_selected;
552 const char **items, *title;
554 title = luaL_checkstring(L, 1);
555 luaL_checktype(L, 2, LUA_TTABLE);
556 start_selected = luaL_optint(L, 3, 0);
558 n = luaL_getn(L, 2);
559 items = (const char**) dlmalloc(n * sizeof(const char*));
560 if(items == NULL)
561 luaL_error(L, "Can't allocate %d bytes!", n * sizeof(const char*));
562 for(i=1; i<=n; i++)
564 lua_rawgeti(L, 2, i); /* Push item on the stack */
565 items[i-1] = luaL_checkstring(L, -1);
566 lua_pop(L, 1); /* Pop it */
569 menu.strings = items;
570 menu.flags |= MENU_ITEM_COUNT(n);
571 menu_desc.desc = (unsigned char*) title;
573 int result = rb->do_menu(&menu, &start_selected, NULL, false);
575 dlfree(items);
577 lua_pushinteger(L, result);
578 return 1;
581 SIMPLE_VOID_WRAPPER(backlight_force_on);
582 SIMPLE_VOID_WRAPPER(backlight_use_settings);
583 #ifdef HAVE_REMOTE_LCD
584 SIMPLE_VOID_WRAPPER(remote_backlight_force_on);
585 SIMPLE_VOID_WRAPPER(remote_backlight_use_settings);
586 #endif
587 #ifdef HAVE_BUTTON_LIGHT
588 SIMPLE_VOID_WRAPPER(buttonlight_force_on);
589 SIMPLE_VOID_WRAPPER(buttonlight_use_settings);
590 #endif
591 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
592 RB_WRAP(backlight_brightness_set)
594 int brightness = luaL_checkint(L, 1);
595 backlight_brightness_set(brightness);
597 return 0;
599 SIMPLE_VOID_WRAPPER(backlight_brightness_use_setting);
600 #endif
602 #define R(NAME) {#NAME, rock_##NAME}
603 static const luaL_Reg rocklib[] =
605 /* Graphics */
606 #ifdef HAVE_LCD_BITMAP
607 R(lcd_framebuffer),
608 R(lcd_mono_bitmap_part),
609 R(lcd_mono_bitmap),
610 #if LCD_DEPTH > 1
611 R(lcd_get_backdrop),
612 R(lcd_bitmap_part),
613 R(lcd_bitmap),
614 #endif
615 #if LCD_DEPTH == 16
616 R(lcd_bitmap_transparent_part),
617 R(lcd_bitmap_transparent),
618 #endif
619 #endif
620 #ifdef HAVE_LCD_COLOR
621 R(lcd_rgbpack),
622 R(lcd_rgbunpack),
623 #endif
625 /* Kernel */
626 R(current_tick),
628 /* Buttons */
629 #ifdef HAVE_TOUCHSCREEN
630 R(action_get_touchscreen_press),
631 R(touchscreen_set_mode),
632 #endif
633 R(kbd_input),
635 R(font_getstringsize),
636 R(read_bmp_file),
637 R(set_viewport),
638 R(clear_viewport),
639 R(current_path),
640 R(gui_syncyesno_run),
641 R(do_menu),
643 /* Backlight helper */
644 R(backlight_force_on),
645 R(backlight_use_settings),
646 #ifdef HAVE_REMOTE_LCD
647 R(remote_backlight_force_on),
648 R(remote_backlight_use_settings),
649 #endif
650 #ifdef HAVE_BUTTON_LIGHT
651 R(buttonlight_force_on),
652 R(buttonlight_use_settings),
653 #endif
654 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
655 R(backlight_brightness_set),
656 R(backlight_brightness_use_setting),
657 #endif
659 {"new_image", rli_new},
661 {NULL, NULL}
663 #undef R
664 extern const luaL_Reg rocklib_aux[];
667 #define RB_CONSTANT(x) lua_pushinteger(L, x); lua_setfield(L, -2, #x);
669 ** Open Rockbox library
671 LUALIB_API int luaopen_rock(lua_State *L)
673 luaL_register(L, LUA_ROCKLIBNAME, rocklib);
674 luaL_register(L, LUA_ROCKLIBNAME, rocklib_aux);
676 RB_CONSTANT(HZ);
678 RB_CONSTANT(LCD_WIDTH);
679 RB_CONSTANT(LCD_HEIGHT);
680 RB_CONSTANT(LCD_DEPTH);
682 RB_CONSTANT(FONT_SYSFIXED);
683 RB_CONSTANT(FONT_UI);
685 #ifdef HAVE_TOUCHSCREEN
686 RB_CONSTANT(TOUCHSCREEN_POINT);
687 RB_CONSTANT(TOUCHSCREEN_BUTTON);
688 #endif
690 RB_CONSTANT(SCREEN_MAIN);
691 #ifdef HAVE_REMOTE_LCD
692 RB_CONSTANT(SCREEN_REMOTE);
693 #endif
695 rli_init(L);
697 return 1;