1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
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"
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);
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);
83 a
->data
= &a
->dummy
[0][0];
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
);
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
);
112 static int rli_height(lua_State
*L
)
114 struct rocklua_image
*a
= rli_checktype(L
, 1);
115 lua_pushnumber(L
, a
->height
);
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
;
141 static int rli_get(lua_State
*L
)
143 lua_pushnumber(L
, *rli_element(L
));
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
);
154 static const struct luaL_reg rli_lib
[] =
156 {"__tostring", rli_tostring
},
159 {"width", rli_width
},
160 {"height", rli_height
},
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))
194 *(unsigned*)res
= luaL_checkint(L
, -1);
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
))
207 int tablepos
= lua_gettop(L
);
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) */
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);
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);
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
);
256 RB_WRAP(clear_viewport
)
258 int screen
= luaL_optint(L
, 1, SCREEN_MAIN
);
259 rb
->screens
[screen
]->clear_viewport();
263 #ifdef HAVE_LCD_BITMAP
264 RB_WRAP(lcd_framebuffer
)
266 rli_wrap(L
, rb
->lcd_framebuffer
, LCD_WIDTH
, LCD_HEIGHT
);
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
);
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
);
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
);
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
);
329 RB_WRAP(lcd_get_backdrop
)
331 fb_data
* backdrop
= rb
->lcd_get_backdrop();
335 rli_wrap(L
, backdrop
, LCD_WIDTH
, LCD_HEIGHT
);
339 #endif /* LCD_DEPTH > 1 */
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
);
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
);
370 #endif /* LCD_DEPTH == 16 */
372 #endif /* defined(LCD_BITMAP) */
374 RB_WRAP(current_tick
)
376 lua_pushinteger(L
, *rb
->current_tick
);
380 #ifdef HAVE_TOUCHSCREEN
381 RB_WRAP(action_get_touchscreen_press
)
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
);
396 luaL_buffinit(L
, &b
);
398 const char *input
= luaL_optstring(L
, 1, NULL
);
399 char *buffer
= luaL_prepbuffer(&b
);
402 rb
->strlcpy(buffer
, input
, LUAL_BUFFERSIZE
);
406 if(!rb
->kbd_input(buffer
, LUAL_BUFFERSIZE
))
408 luaL_addsize(&b
, strlen(buffer
));
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
);
426 RB_WRAP(font_getstringsize
)
428 const unsigned char* str
= luaL_checkstring(L
, 1);
429 int fontnumber
= luaL_checkint(L
, 2);
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
);
440 #ifdef HAVE_LCD_COLOR
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
);
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
));
461 RB_WRAP(read_bmp_file
)
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
;
470 format
|= FORMAT_DITHER
;
473 format
|= FORMAT_TRANSPARENT
;
475 int result
= rb
->read_bmp_file(filename
, &bm
, 0, format
| FORMAT_RETURN_SIZE
, NULL
);
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 */
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
);
504 static void fill_text_message(lua_State
*L
, struct text_message
* message
,
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*));
512 luaL_error(L
, "Can't allocate %d bytes!", n
* sizeof(const char*));
515 lua_rawgeti(L
, pos
, i
);
516 lines
[i
-1] = luaL_checkstring(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
);
538 dlfree(yes_message
.message_lines
);
540 dlfree(no_message
.message_lines
);
542 lua_pushinteger(L
, result
);
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);
559 items
= (const char**) dlmalloc(n
* sizeof(const char*));
561 luaL_error(L
, "Can't allocate %d bytes!", n
* sizeof(const char*));
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);
577 lua_pushinteger(L
, result
);
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
);
587 #ifdef HAVE_BUTTON_LIGHT
588 SIMPLE_VOID_WRAPPER(buttonlight_force_on
);
589 SIMPLE_VOID_WRAPPER(buttonlight_use_settings
);
591 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
592 RB_WRAP(backlight_brightness_set
)
594 int brightness
= luaL_checkint(L
, 1);
595 backlight_brightness_set(brightness
);
599 SIMPLE_VOID_WRAPPER(backlight_brightness_use_setting
);
602 #define R(NAME) {#NAME, rock_##NAME}
603 static const luaL_Reg rocklib
[] =
606 #ifdef HAVE_LCD_BITMAP
608 R(lcd_mono_bitmap_part
),
616 R(lcd_bitmap_transparent_part
),
617 R(lcd_bitmap_transparent
),
620 #ifdef HAVE_LCD_COLOR
629 #ifdef HAVE_TOUCHSCREEN
630 R(action_get_touchscreen_press
),
631 R(touchscreen_set_mode
),
635 R(font_getstringsize
),
640 R(gui_syncyesno_run
),
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
),
650 #ifdef HAVE_BUTTON_LIGHT
651 R(buttonlight_force_on
),
652 R(buttonlight_use_settings
),
654 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
655 R(backlight_brightness_set
),
656 R(backlight_brightness_use_setting
),
659 {"new_image", rli_new
},
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
);
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
);
690 RB_CONSTANT(SCREEN_MAIN
);
691 #ifdef HAVE_REMOTE_LCD
692 RB_CONSTANT(SCREEN_REMOTE
);