efl/legacy/edje/src/lib/edje_lua2.c

727 lines
17 KiB
C
Raw Normal View History

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <string.h>
#ifdef HAVE_ALLOCA_H
# include <alloca.h>
#elif defined __GNUC__
# define alloca __builtin_alloca
#elif defined _AIX
# define alloca __alloca
#elif defined _MSC_VER
# include <malloc.h>
# define alloca _alloca
#else
# include <stddef.h>
# ifdef __cplusplus
extern "C"
# endif
void *alloca(size_t);
#endif
#include "edje_private.h"
//--------------------------------------------------------------------------//
#ifdef LUA2
#define MAX_LUA_MEM (4 * (1024 * 1024))
//--------------------------------------------------------------------------//
2010-07-06 17:58:34 -07:00
typedef struct _Edje_Lua_Alloc Edje_Lua_Alloc;
typedef struct _Edje_Lua_Obj Edje_Lua_Obj;
typedef struct _Edje_Lua_Timer Edje_Lua_Timer;
typedef struct _Edje_Lua_Animator Edje_Lua_Animator;
typedef struct _Edje_Lua_Transition Edje_Lua_Transition;
//--------------------------------------------------------------------------//
struct _Edje_Lua_Alloc
{
size_t max, cur;
};
struct _Edje_Lua_Obj
{
EINA_INLIST;
Edje *ed;
void (*free_func) (void *obj);
};
struct _Edje_Lua_Timer
{
Edje_Lua_Obj obj;
Ecore_Timer *timer;
int fn_ref;
};
2010-07-06 17:19:39 -07:00
struct _Edje_Lua_Animator
{
Edje_Lua_Obj obj;
2010-07-06 17:19:39 -07:00
Ecore_Animator *animator;
int fn_ref;
};
2010-07-06 17:58:34 -07:00
struct _Edje_Lua_Transition
{
Edje_Lua_Obj obj;
Ecore_Animator *animator;
double transition, start;
int fn_ref;
};
//--------------------------------------------------------------------------//
static int _elua_obj_gc(lua_State *L);
static int _elua_obj_del(lua_State *L);
static int _elua_echo(lua_State *L);
static int _elua_timer(lua_State *L);
2010-07-06 17:19:39 -07:00
static int _elua_animator(lua_State *L);
2010-07-06 17:58:34 -07:00
static int _elua_transition(lua_State *L);
2010-07-06 19:40:46 -07:00
static int _elua_seconds(lua_State *L);
static int _elua_looptime(lua_State *L);
static int _elua_date(lua_State *L);
//--------------------------------------------------------------------------//
static lua_State *lstate = NULL;
static jmp_buf panic_jmp;
static const struct luaL_reg _elua_edje_api [] =
{
2010-07-06 19:40:46 -07:00
// add an echo too to make it more shelly
{"echo", _elua_echo}, // test func - echo (i know we have print. test)
2010-07-06 19:40:46 -07:00
// generic object methods
{"del", _elua_obj_del}, // generic del any object created for edje
2010-07-06 19:40:46 -07:00
// time based "callback" systems
{"timer", _elua_timer}, // add timer
2010-07-06 17:19:39 -07:00
{"animator", _elua_animator}, // add animator
2010-07-06 17:58:34 -07:00
{"transition", _elua_transition}, // add transition
2010-07-06 19:40:46 -07:00
// system information (time, date blah blah)
{"seconds", _elua_seconds}, // get seconds
{"looptime", _elua_looptime}, // get loop time
{"date", _elua_date}, // get date in a table
// emit
// message
// now evas stuff (create objects, manipulate, delete etc.)
2010-07-06 19:40:46 -07:00
// now more convenient layer on top for objects
// funcs to provide:
// // shutdown
// // message
// // resize
// // get dragable pos
// // set dragable pos
// // get part text
// // set part text
// // get swallow part
// // set swallow part
{NULL, NULL} // end
};
static const struct luaL_reg _elua_edje_meta [] =
{
{"__gc", _elua_obj_gc}, // garbage collector func for edje objects
{NULL, NULL} // end
};
static const luaL_Reg _elua_libs[] =
{
{"", luaopen_base},
// {LUA_LOADLIBNAME, luaopen_package}, // disable this lib - don't want
{LUA_TABLIBNAME, luaopen_table},
// {LUA_IOLIBNAME, luaopen_io}, // disable this lib - don't want
{LUA_OSLIBNAME, luaopen_os},
{LUA_STRLIBNAME, luaopen_string},
{LUA_MATHLIBNAME, luaopen_math},
// {LUA_DBLIBNAME, luaopen_debug}, // disable this lib - don't want
{NULL, NULL} // end
};
static const char *_elua_key = "key";
//--------------------------------------------------------------------------//
static void *
_elua_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
{
Edje_Lua_Alloc *ela = ud;
void *ptr2;
ela->cur += nsize - osize;
if (ela->cur > ela->max)
{
ERR("Edje Lua memory limit of %zu bytes reached (%zu allocated)",
ela->max, ela->cur);
return NULL;
}
if (nsize == 0)
{
free(ptr);
return NULL;
}
ptr2 = realloc(ptr, nsize);
if (ptr2) return ptr2;
ERR("Edje Lua cannot re-allocate %i bytes", nsize);
return ptr2;
}
static int
_elua_custom_panic(lua_State *L)
{
ERR("Lua Panic!!!!");
return 1;
}
//-------------
void
_edje_lua2_error_full(const char *file, const char *fnc, int line,
lua_State *L, int err_code)
{
char *err_type;
switch (err_code)
{
case LUA_ERRRUN:
err_type = "runtime";
break;
case LUA_ERRSYNTAX:
err_type = "syntax";
break;
case LUA_ERRMEM:
err_type = "memory allocation";
break;
case LUA_ERRERR:
err_type = "error handler";
break;
default:
err_type = "unknown";
break;
}
eina_log_print
(_edje_default_log_dom, EINA_LOG_LEVEL_ERR, file, fnc, line,
"Lua %s error: %s", err_type, lua_tostring(L, -1));
}
static void
_elua_init(void)
{
static Edje_Lua_Alloc ela = { MAX_LUA_MEM, 0 };
const luaL_Reg *l;
2010-07-06 02:35:34 -07:00
lua_State *L;
if (lstate) return;
2010-07-06 02:35:34 -07:00
lstate = L = lua_newstate(_elua_alloc, &ela);
lua_atpanic(L, _elua_custom_panic);
// FIXME: figure out optimal gc settings later
2010-07-06 02:35:34 -07:00
// lua_gc(L, LUA_GCSETPAUSE, 200);
// lua_gc(L, LUA_GCSETSTEPMUL, 200);
for (l = _elua_libs; l->func; l++)
{
2010-07-06 02:35:34 -07:00
lua_pushcfunction(L, l->func);
lua_pushstring(L, l->name);
lua_call(L, 1, 0);
}
2010-07-06 02:35:34 -07:00
luaL_register(L, "edje", _elua_edje_api);
luaL_newmetatable(L, "edje");
luaL_register(L, 0, _elua_edje_meta);
2010-07-06 02:35:34 -07:00
lua_pushliteral(L, "__index");
lua_pushvalue(L, -3);
lua_rawset(L, -3);
lua_pop(L, 2);
}
//-------------
static void
_elua_table_ptr_set(lua_State *L, const void *key, const void *val)
{
2010-07-06 02:35:34 -07:00
lua_pushlightuserdata(L, (void *)key);
lua_pushlightuserdata(L, (void *)val);
lua_settable(L, LUA_REGISTRYINDEX);
}
static const void *
_elua_table_ptr_get(lua_State *L, const void *key)
{
const void *ptr;
2010-07-06 02:35:34 -07:00
lua_pushlightuserdata(L, (void *)key);
lua_gettable(L, LUA_REGISTRYINDEX);
ptr = lua_topointer(L, -1);
lua_pop(L, 1);
return ptr;
}
static void
_elua_table_ptr_del(lua_State *L, const void *key)
{
2010-07-06 02:35:34 -07:00
lua_pushlightuserdata(L, (void *)key);
lua_pushnil(L);
lua_settable(L, LUA_REGISTRYINDEX);
}
static void
_elua_gc(lua_State *L)
{
2010-07-06 02:35:34 -07:00
lua_gc(L, LUA_GCCOLLECT, 0);
}
//-------------
static Edje_Lua_Obj *
_elua_obj_new(lua_State *L, Edje *ed, int size)
{
Edje_Lua_Obj *obj;
2010-07-06 02:35:34 -07:00
obj = (Edje_Lua_Obj *)lua_newuserdata(L, size);
memset(obj, 0, size);
ed->lua_objs = eina_inlist_append(ed->lua_objs, EINA_INLIST_GET(obj));
2010-07-06 02:35:34 -07:00
luaL_getmetatable(L, "edje");
lua_setmetatable(L, -2);
obj->ed = ed;
return obj;
}
static void
_elua_obj_free(lua_State *L, Edje_Lua_Obj *obj)
{
if (!obj->free_func) return;
obj->free_func(obj);
obj->ed->lua_objs = eina_inlist_remove(obj->ed->lua_objs, EINA_INLIST_GET(obj));
obj->free_func = NULL;
obj->ed = NULL;
}
//-------------
static int
_elua_obj_gc(lua_State *L)
{
Edje_Lua_Obj *obj = (Edje_Lua_Obj *)lua_touserdata(L, 1);
if (!obj) return 0;
_elua_obj_free(L, obj);
return 0;
}
static int
_elua_obj_del(lua_State *L)
{
return _elua_obj_gc(L);
}
2010-07-06 17:19:39 -07:00
//----------------------------------------------------------------------------
//-------------------------------------------
//---------------------------
//-------------------
//---------------
//-------------
static int
_elua_echo(lua_State *L)
{
const char *string = luaL_checkstring(L, 1); //0
printf("%s\n", string);
return 1;
}
//-------------
2010-07-06 02:35:34 -07:00
static Eina_Bool
_elua_timer_cb(void *data)
{
Edje_Lua_Timer *elt = data;
2010-07-06 02:35:34 -07:00
lua_State *L;
int ret = 0;
int err;
if (!elt->obj.ed) return 0;
2010-07-06 02:35:34 -07:00
L = elt->obj.ed->L;
if (!L) return 0;
2010-07-06 17:19:39 -07:00
lua_rawgeti(L, LUA_REGISTRYINDEX, elt->fn_ref);
if (setjmp(panic_jmp) == 1)
{
ERR("Timer callback panic");
_edje_lua2_error(L, err);
_elua_obj_free(L, (Edje_Lua_Obj *)elt);
_elua_gc(L);
return 0;
}
2010-07-06 17:19:39 -07:00
if ((err = lua_pcall(L, 0, 1, 0)))
{
2010-07-06 17:19:39 -07:00
_edje_lua2_error(L, err);
2010-07-06 02:35:34 -07:00
_elua_obj_free(L, (Edje_Lua_Obj *)elt);
_elua_gc(L);
return 0;
}
2010-07-06 17:19:39 -07:00
ret = lua_toboolean(L, -1);
// ret = luaL_checktype(L, -1, LUA_TBOOLEAN);
// ret = luaL_checkint(L, -1);
2010-07-06 02:35:34 -07:00
lua_pop(L, 1);
2010-07-06 17:19:39 -07:00
if (ret == 0) _elua_obj_free(L, (Edje_Lua_Obj *)elt);
2010-07-06 02:35:34 -07:00
_elua_gc(L);
return ret;
}
static void
_elua_timer_free(void *obj)
{
2010-07-06 17:19:39 -07:00
Edje_Lua_Timer *elt = obj;
2010-07-06 02:35:34 -07:00
lua_State *L;
if (!elt->obj.ed) return;
L = elt->obj.ed->L;
luaL_unref(L, LUA_REGISTRYINDEX, elt->fn_ref); //0
elt->fn_ref = 0;
ecore_timer_del(elt->timer);
elt->timer = NULL;
}
static int
_elua_timer(lua_State *L)
{
Edje *ed = (Edje *)_elua_table_ptr_get(L, _elua_key);
Edje_Lua_Timer *elt;
double val;
2010-07-06 02:35:34 -07:00
val = luaL_checknumber(L, 1);
luaL_checkany(L, 2);
2010-07-06 17:19:39 -07:00
elt = (Edje_Lua_Timer *)_elua_obj_new(L, ed, sizeof(Edje_Lua_Timer));
elt->obj.free_func = _elua_timer_free;
elt->timer = ecore_timer_add(val, _elua_timer_cb, elt);
2010-07-06 17:19:39 -07:00
lua_pushvalue(L, 2);
elt->fn_ref = luaL_ref(L, LUA_REGISTRYINDEX);
2010-07-06 02:35:34 -07:00
_elua_gc(L);
return 1;
}
//-------------
2010-07-06 17:19:39 -07:00
static Eina_Bool
_elua_animator_cb(void *data)
{
Edje_Lua_Animator *ela = data;
lua_State *L;
int ret = 0;
int err;
if (!ela->obj.ed) return 0;
L = ela->obj.ed->L;
if (!L) return 0;
lua_rawgeti(L, LUA_REGISTRYINDEX, ela->fn_ref);
if (setjmp(panic_jmp) == 1)
{
ERR("Animator callback panic");
_edje_lua2_error(L, err);
_elua_obj_free(L, (Edje_Lua_Obj *)ela);
_elua_gc(L);
return 0;
}
2010-07-06 17:19:39 -07:00
if ((err = lua_pcall(L, 0, 1, 0)))
{
_edje_lua2_error(L, err);
_elua_obj_free(L, (Edje_Lua_Obj *)ela);
_elua_gc(L);
return 0;
}
ret = lua_toboolean(L, -1);
lua_pop(L, 1);
if (ret == 0) _elua_obj_free(L, (Edje_Lua_Obj *)ela);
_elua_gc(L);
return ret;
}
static void
_elua_animator_free(void *obj)
{
Edje_Lua_Animator *ela = obj;
lua_State *L;
if (!ela->obj.ed) return;
L = ela->obj.ed->L;
luaL_unref(L, LUA_REGISTRYINDEX, ela->fn_ref); //0
ela->fn_ref = 0;
ecore_animator_del(ela->animator);
ela->animator = NULL;
}
static int
2010-07-06 17:19:39 -07:00
_elua_animator(lua_State *L)
{
Edje *ed = (Edje *)_elua_table_ptr_get(L, _elua_key);
2010-07-06 17:19:39 -07:00
Edje_Lua_Animator *ela;
luaL_checkany(L, 1);
ela = (Edje_Lua_Animator *)_elua_obj_new(L, ed, sizeof(Edje_Lua_Animator));
ela->obj.free_func = _elua_animator_free;
ela->animator = ecore_animator_add(_elua_animator_cb, ela);
lua_pushvalue(L, 1);
ela->fn_ref = luaL_ref(L, LUA_REGISTRYINDEX);
_elua_gc(L);
return 1;
}
2010-07-06 17:58:34 -07:00
//-------------
static Eina_Bool
_elua_transition_cb(void *data)
{
Edje_Lua_Transition *elt = data;
lua_State *L;
int ret = 0;
int err;
double t;
if (!elt->obj.ed) return 0;
L = elt->obj.ed->L;
if (!L) return 0;
t = (ecore_loop_time_get() - elt->start) / elt->transition;
if (t > 1.0) t = 1.0;
lua_rawgeti(L, LUA_REGISTRYINDEX, elt->fn_ref);
lua_pushnumber(L, t);
if (setjmp(panic_jmp) == 1)
{
ERR("Transition callback panic");
_edje_lua2_error(L, err);
_elua_obj_free(L, (Edje_Lua_Obj *)elt);
_elua_gc(L);
return 0;
}
2010-07-06 17:58:34 -07:00
if ((err = lua_pcall(L, 1, 1, 0)))
{
_edje_lua2_error(L, err);
_elua_obj_free(L, (Edje_Lua_Obj *)elt);
_elua_gc(L);
return 0;
}
ret = lua_toboolean(L, -1);
lua_pop(L, 1);
if (t >= 1.0) ret = 0;
if (ret == 0) _elua_obj_free(L, (Edje_Lua_Obj *)elt);
_elua_gc(L);
return ret;
}
static void
_elua_transition_free(void *obj)
{
Edje_Lua_Transition *elt = obj;
lua_State *L;
if (!elt->obj.ed) return;
L = elt->obj.ed->L;
luaL_unref(L, LUA_REGISTRYINDEX, elt->fn_ref); //0
elt->fn_ref = 0;
ecore_animator_del(elt->animator);
elt->animator = NULL;
}
static int
_elua_transition(lua_State *L)
{
Edje *ed = (Edje *)_elua_table_ptr_get(L, _elua_key);
Edje_Lua_Transition *elt;
double val;
val = luaL_checknumber(L, 1);
luaL_checkany(L, 2);
elt = (Edje_Lua_Transition *)_elua_obj_new(L, ed, sizeof(Edje_Lua_Transition));
elt->obj.free_func = _elua_transition_free;
elt->animator = ecore_animator_add(_elua_transition_cb, elt);
if (val < 0.0000001) val = 0.0000001;
elt->transition = val;
elt->start = ecore_loop_time_get();
lua_pushvalue(L, 2);
elt->fn_ref = luaL_ref(L, LUA_REGISTRYINDEX);
_elua_gc(L);
return 1;
}
2010-07-06 19:40:46 -07:00
//-------------
static int
_elua_seconds(lua_State *L)
{
double t = ecore_time_get();
lua_pushnumber(L, t);
return 1;
}
//-------------
static int
_elua_looptime(lua_State *L)
{
double t = ecore_loop_time_get();
lua_pushnumber(L, t);
return 1;
}
//-------------
static int
_elua_date(lua_State *L)
{
static time_t last_tzset = 0;
struct timeval timev;
struct tm *tm;
time_t tt;
lua_newtable(L);
gettimeofday(&timev, NULL);
tt = (time_t)(timev.tv_sec);
if ((tt > (last_tzset + 1)) || (tt < (last_tzset - 1)))
{
last_tzset = tt;
tzset();
}
tm = localtime(&tt);
if (tm)
{
double t;
lua_pushstring(L, "year");
lua_pushinteger(L, (int)(tm->tm_year + 1900));
lua_settable(L, -3);
lua_pushstring(L, "month");
lua_pushinteger(L, (int)(tm->tm_mon + 1));
lua_settable(L, -3);
lua_pushstring(L, "day");
lua_pushinteger(L, (int)(tm->tm_mday));
lua_settable(L, -3);
lua_pushstring(L, "yearday");
lua_pushinteger(L, (int)(tm->tm_yday));
lua_settable(L, -3);
lua_pushstring(L, "weekday");
lua_pushinteger(L, (int)((tm->tm_wday + 6) % 7));
lua_settable(L, -3);
lua_pushstring(L, "hour");
lua_pushinteger(L, (int)(tm->tm_hour));
lua_settable(L, -3);
lua_pushstring(L, "min");
lua_pushinteger(L, (int)(tm->tm_min));
lua_settable(L, -3);
t = (double)tm->tm_sec + (((double)timev.tv_usec) / 1000000);
lua_pushstring(L, "sec");
lua_pushnumber(L, t);
lua_settable(L, -3);
}
return 1;
}
2010-07-06 17:19:39 -07:00
//-------------
//---------------
//-------------------
//---------------------------
//-------------------------------------------
//----------------------------------------------------------------------------
//-------------
void
_edje_lua2_script_init(Edje *ed)
{
2010-07-06 02:35:34 -07:00
static Edje_Lua_Alloc ela = { MAX_LUA_MEM, 0 };
const luaL_Reg *l;
char buf[256];
void *data;
int size;
if (ed->L) return;
_elua_init();
2010-07-06 02:35:34 -07:00
ed->L = lua_newstate(_elua_alloc, &ela);
lua_atpanic(ed->L, _elua_custom_panic);
// FIXME: figure out optimal gc settings later
// lua_gc(ed->L, LUA_GCSETPAUSE, 200);
// lua_gc(ed->L, LUA_GCSETSTEPMUL, 200);
for (l = _elua_libs; l->func; l++)
{
lua_pushcfunction(ed->L, l->func);
lua_pushstring(ed->L, l->name);
lua_call(ed->L, 1, 0);
}
luaL_register(ed->L, "edje", _elua_edje_api);
luaL_newmetatable(ed->L, "edje");
luaL_register(ed->L, 0, _elua_edje_meta);
lua_pushliteral(ed->L, "__index");
lua_pushvalue(ed->L, -3);
lua_rawset(ed->L, -3);
lua_pop(ed->L, 2);
2010-07-06 02:35:34 -07:00
_elua_table_ptr_set(ed->L, _elua_key, ed);
snprintf(buf, sizeof(buf), "lua_scripts/%i", ed->collection->id);
data = eet_read(ed->file->ef, buf, &size);
if (data)
{
int err;
err = luaL_loadbuffer(ed->L, data, size, "edje_lua_script");
if (err)
{
if (err == LUA_ERRSYNTAX)
ERR("lua load syntax error: %s",
lua_tostring(ed->L, -1));
else if (err == LUA_ERRMEM)
ERR("lua load memory allocation error: %s",
lua_tostring(ed->L, -1));
}
free(data);
if (setjmp(panic_jmp) == 1)
{
ERR("Script init panic");
return;
}
2010-07-06 02:35:34 -07:00
if ((err = lua_pcall(ed->L, 0, 0, 0)))
_edje_lua2_error(ed->L, err);
}
}
void
_edje_lua2_script_shutdown(Edje *ed)
{
if (!ed->L) return;
2010-07-06 02:35:34 -07:00
lua_close(ed->L);
ed->L = NULL;
while (ed->lua_objs)
{
Edje_Lua_Obj *obj = (Edje_Lua_Obj *)ed->lua_objs;
if (obj->free_func)
{
ERR("uncollected Lua object %p", obj);
2010-07-06 02:35:34 -07:00
ed->lua_objs = eina_inlist_remove(ed->lua_objs, ed->lua_objs);
}
else
{
ERR("dangling Lua object %p", obj);
ed->lua_objs = eina_inlist_remove(ed->lua_objs, ed->lua_objs);
}
}
}
void
_edje_lua2_script_load(Edje_Part_Collection *edc, void *data, int size)
{
_elua_init();
}
void
_edje_lua2_script_unload(Edje_Part_Collection *edc)
{
2010-07-06 02:35:34 -07:00
lua_State *L;
if (!lstate) return;
L = lstate;
lua_gc(L, LUA_GCCOLLECT, 0);
}
#endif