You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
222 lines
4.8 KiB
222 lines
4.8 KiB
#include "luavgl.h"
|
|
#include "private.h"
|
|
|
|
typedef struct luavgl_timer_s {
|
|
lua_State *L;
|
|
int ref; /* ref to callback */
|
|
} luavgl_timer_t;
|
|
|
|
static lv_timer_t *luavgl_check_timer(lua_State *L, int index)
|
|
{
|
|
lv_timer_t *v = *(lv_timer_t **)luaL_checkudata(L, index, "lv_timer");
|
|
return v;
|
|
}
|
|
|
|
static void luavgl_timer_cb(lv_timer_t *t)
|
|
{
|
|
luavgl_timer_t *data = t->user_data;
|
|
lua_State *L = data->L;
|
|
int ref = data->ref;
|
|
if (ref == LUA_NOREF) {
|
|
return;
|
|
}
|
|
|
|
int top = lua_gettop(L);
|
|
/* stack: 1. function, 2. timer userdata */
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
|
lua_pushlightuserdata(L, t);
|
|
lua_rawget(L, LUA_REGISTRYINDEX); /* this should not fail*/
|
|
|
|
luavgl_pcall_int(L, 1, 0);
|
|
lua_settop(L, top);
|
|
}
|
|
|
|
static void luavgl_timer_set_cb(void *_t, lua_State *L)
|
|
{
|
|
lv_timer_t *t = _t;
|
|
int ref = luavgl_check_continuation(L, -1);
|
|
luavgl_timer_t *data = t->user_data;
|
|
|
|
if (data->ref != LUA_NOREF) {
|
|
luaL_unref(L, LUA_REGISTRYINDEX, data->ref);
|
|
}
|
|
data->ref = ref;
|
|
}
|
|
|
|
static void luavgl_timer_set_paused(lv_timer_t *t, int paused)
|
|
{
|
|
/* pause or resume. */
|
|
paused ? lv_timer_pause(t) : lv_timer_resume(t);
|
|
}
|
|
|
|
/* clang-format off */
|
|
static const luavgl_value_setter_t timer_property_table[] = {
|
|
{ "paused", 0, { .setter = (setter_int_t)luavgl_timer_set_paused } },
|
|
{ "period", 0, { .setter = (setter_int_t)lv_timer_set_period } },
|
|
{ "repeat_count", 0, { .setter = (setter_int_t)lv_timer_set_repeat_count } },
|
|
{ "cb", SETTER_TYPE_STACK, { .setter_stack = luavgl_timer_set_cb } },
|
|
};
|
|
|
|
/* clang-format on */
|
|
|
|
static int timer_set_para_cb(lua_State *L, void *data)
|
|
{
|
|
int ret = luavgl_set_property(L, data, timer_property_table);
|
|
|
|
if (ret != 0) {
|
|
debug("failed\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* setup timer using parameter in table idx */
|
|
int luavgl_timer_setup(lua_State *L, int idx, lv_timer_t *t)
|
|
{
|
|
luavgl_iterate(L, idx, timer_set_para_cb, t);
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* t = luavgl:timer({timer parameters})
|
|
* t:pause()
|
|
* t:resume()
|
|
* t:ready() -- make it ready right now
|
|
*
|
|
*/
|
|
static int luavgl_timer_create(lua_State *L)
|
|
{
|
|
luavgl_timer_t *data = malloc(sizeof(luavgl_timer_t));
|
|
if (data == NULL) {
|
|
return luaL_error(L, "No memory.");
|
|
}
|
|
data->ref = LUA_NOREF;
|
|
data->L = L;
|
|
|
|
lv_timer_t *t = lv_timer_create(luavgl_timer_cb, 0, data);
|
|
|
|
*(void **)lua_newuserdata(L, sizeof(void *)) = t;
|
|
luaL_getmetatable(L, "lv_timer");
|
|
lua_setmetatable(L, -2);
|
|
|
|
lua_pushlightuserdata(L, t);
|
|
lua_pushvalue(L, -2);
|
|
lua_rawset(L, LUA_REGISTRYINDEX);
|
|
|
|
/* parameter table is on stack[1] */
|
|
luavgl_timer_setup(L, 1, t);
|
|
lua_remove(L, 1); /* remove it to keep stack balance */
|
|
|
|
if (t->period == 0) {
|
|
/* if period is not set, then it's paused. */
|
|
lv_timer_pause(t);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int luavgl_timer_set(lua_State *L)
|
|
{
|
|
lv_timer_t *t = luavgl_check_timer(L, 1);
|
|
if (t == NULL) {
|
|
return luaL_argerror(L, 1, "timer is null.");
|
|
}
|
|
|
|
luavgl_timer_setup(L, 2, t);
|
|
return 0;
|
|
}
|
|
|
|
static int luavgl_timer_ready(lua_State *L)
|
|
{
|
|
lv_timer_t *t = luavgl_check_timer(L, 1);
|
|
if (t == NULL) {
|
|
return luaL_argerror(L, 1, "timer is null.");
|
|
}
|
|
|
|
lv_timer_ready(t);
|
|
return 0;
|
|
}
|
|
|
|
static int luavgl_timer_resume(lua_State *L)
|
|
{
|
|
lv_timer_t *t = luavgl_check_timer(L, 1);
|
|
if (t == NULL) {
|
|
return luaL_argerror(L, 1, "timer is null.");
|
|
}
|
|
|
|
lv_timer_resume(t);
|
|
return 0;
|
|
}
|
|
|
|
static int luavgl_timer_pause(lua_State *L)
|
|
{
|
|
lv_timer_t *t = luavgl_check_timer(L, 1);
|
|
if (t == NULL) {
|
|
return luaL_argerror(L, 1, "timer is null.");
|
|
}
|
|
|
|
lv_timer_pause(t);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* remove timer from obj, */
|
|
static int luavgl_timer_delete(lua_State *L)
|
|
{
|
|
lv_timer_t *t = luavgl_check_timer(L, 1);
|
|
if (t == NULL) {
|
|
return luaL_argerror(L, 1, "timer is null.");
|
|
}
|
|
|
|
luavgl_timer_t *data = t->user_data;
|
|
if (data->ref) {
|
|
luaL_unref(L, LUA_REGISTRYINDEX, data->ref);
|
|
data->ref = LUA_NOREF;
|
|
}
|
|
|
|
lua_pushlightuserdata(L, t);
|
|
lua_pushnil(L);
|
|
lua_rawset(L, LUA_REGISTRYINDEX);
|
|
|
|
/* we can only release memory in gc, since we need t->use_data */
|
|
lv_timer_pause(t);
|
|
|
|
debug("delete timer:%p\n", t);
|
|
return 0;
|
|
}
|
|
|
|
static int luavgl_timer_gc(lua_State *L)
|
|
{
|
|
/* stop timer if not stopped. */
|
|
luavgl_timer_delete(L);
|
|
|
|
lv_timer_t *t = luavgl_check_timer(L, 1);
|
|
free(t->user_data);
|
|
lv_timer_del(t);
|
|
|
|
debug("gc timer:%p\n", t);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg luavgl_timer_methods[] = {
|
|
{"set", luavgl_timer_set },
|
|
{"pause", luavgl_timer_pause },
|
|
{"resume", luavgl_timer_resume},
|
|
{"delete", luavgl_timer_delete},
|
|
{"ready", luavgl_timer_ready },
|
|
|
|
{NULL, NULL }
|
|
};
|
|
|
|
static void luavgl_timer_init(lua_State *L)
|
|
{
|
|
luaL_newmetatable(L, "lv_timer");
|
|
|
|
lua_pushcfunction(L, luavgl_timer_gc);
|
|
lua_setfield(L, -2, "__gc");
|
|
|
|
luaL_newlib(L, luavgl_timer_methods); /* methods belong to this type */
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
lua_pop(L, 1); /* pop __index table */
|
|
}
|
|
|