summaryrefslogtreecommitdiff
path: root/lib/luavgl/src/timer.c
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-11-12 19:14:09 +1100
committerjacqueline <me@jacqueline.id.au>2023-11-12 19:14:09 +1100
commit8a0a167adbf3d9b6f8b6f16aaf20ca39ad5549de (patch)
tree02b6cf23f591915747ec2994381854a79979c4a0 /lib/luavgl/src/timer.c
parent8471046a95ab9e00f7d42b56dbbc9ce3e5b424b9 (diff)
downloadtangara-fw-8a0a167adbf3d9b6f8b6f16aaf20ca39ad5549de.tar.gz
Convert the main menu screen to lua lol
Diffstat (limited to 'lib/luavgl/src/timer.c')
-rw-r--r--lib/luavgl/src/timer.c222
1 files changed, 222 insertions, 0 deletions
diff --git a/lib/luavgl/src/timer.c b/lib/luavgl/src/timer.c
new file mode 100644
index 00000000..4ee334ca
--- /dev/null
+++ b/lib/luavgl/src/timer.c
@@ -0,0 +1,222 @@
+#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 */
+}