From b493973d7d5cb123e8b12f7e0dfd292c05f25458 Mon Sep 17 00:00:00 2001 From: Damjan Adamic Date: Sat, 4 Feb 2017 10:58:06 +0100 Subject: [PATCH] Lua: Use incremental GC and also call it for Widgets (#4369) Fixes #3885: Error in Lua Widget options handled better (does not disable entire Lua state) Disable Lua Widget if any of its functions has error. --- radio/src/cli.cpp | 12 +- radio/src/gui/480x272/bitmapbuffer.h | 5 + radio/src/gui/480x272/screens_setup.cpp | 17 +++ radio/src/gui/480x272/view_statistics.cpp | 10 ++ radio/src/gui/480x272/widget.h | 5 + radio/src/lua/api_general.cpp | 2 +- radio/src/lua/api_lcd.cpp | 14 +- radio/src/lua/api_model.cpp | 4 +- radio/src/lua/interface.cpp | 60 +++++--- radio/src/lua/lua_api.h | 6 +- radio/src/lua/widgets.cpp | 167 ++++++++++++++-------- 11 files changed, 213 insertions(+), 89 deletions(-) diff --git a/radio/src/cli.cpp b/radio/src/cli.cpp index e6832c4cb..e377fb751 100644 --- a/radio/src/cli.cpp +++ b/radio/src/cli.cpp @@ -418,9 +418,15 @@ int cliMemoryInfo(const char ** argv) #if defined(LUA) serialPrint("\nLua:"); - serialPrint("\tScripts %d", luaGetMemUsed(lsScripts)); -#if defined(PCBHORUS) - serialPrint("\tWidgets %d", luaGetMemUsed(lsWidgets)); + uint32_t s = luaGetMemUsed(lsScripts); + serialPrint("\tScripts %u", s); +#if defined(COLORLCD) + uint32_t w = luaGetMemUsed(lsWidgets); + uint32_t e = luaExtraMemoryUsage; + serialPrint("\tWidgets %u", w); + serialPrint("\tExtra %u", e); + serialPrint("------------"); + serialPrint("\tTotal %u", s + w + e); #endif #endif return 0; diff --git a/radio/src/gui/480x272/bitmapbuffer.h b/radio/src/gui/480x272/bitmapbuffer.h index e790557c4..7a5892f2a 100644 --- a/radio/src/gui/480x272/bitmapbuffer.h +++ b/radio/src/gui/480x272/bitmapbuffer.h @@ -79,6 +79,11 @@ class BitmapBufferBase return data; } + uint32_t getDataSize() const + { + return width * height * sizeof(T); + } + inline const display_t * getPixelPtr(coord_t x, coord_t y) const { #if defined(PCBX10) diff --git a/radio/src/gui/480x272/screens_setup.cpp b/radio/src/gui/480x272/screens_setup.cpp index 8811c610c..9908f585b 100644 --- a/radio/src/gui/480x272/screens_setup.cpp +++ b/radio/src/gui/480x272/screens_setup.cpp @@ -176,6 +176,23 @@ int getOptionsCount(const ZoneOption * options) template bool menuSettings(const char * title, const T * object, uint32_t i_flags, event_t event) { + + if (object->getErrorMessage()) { + // display error instead of widget settings + // TODO nicer display (proper word-wrap) + SIMPLE_SUBMENU("Widget Error", ICON_MODEL_LUA_SCRIPTS, 1); + int len = strlen(object->getErrorMessage()); + int y = 3*FH; + const char * p = object->getErrorMessage(); + while (len > 0) { + lcdDrawSizedText(MENUS_MARGIN_LEFT, y, p, 30); + p += 30; + y += FH; + len -= 30; + } + return true; + } + const ZoneOption * options = object->getOptions(); linesCount = getOptionsCount(options); uint8_t mstate_tab[MAX_WIDGET_OPTIONS]; diff --git a/radio/src/gui/480x272/view_statistics.cpp b/radio/src/gui/480x272/view_statistics.cpp index 05c73ad3e..407c32179 100644 --- a/radio/src/gui/480x272/view_statistics.cpp +++ b/radio/src/gui/480x272/view_statistics.cpp @@ -139,6 +139,16 @@ bool menuStatsDebug(event_t event) lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+line*FH, "Lua interval"); lcdDrawNumber(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+line*FH, 10*maxLuaInterval, LEFT, 0, NULL, "ms"); ++line; + + lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+line*FH, "Lua memory"); + lcdDrawText(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+line*FH+1, "[S]", HEADER_COLOR|SMLSIZE); + lcdDrawNumber(lcdNextPos+5, MENU_CONTENT_TOP+line*FH, luaGetMemUsed(lsScripts), LEFT); + lcdDrawText(lcdNextPos+20, MENU_CONTENT_TOP+line*FH+1, "[W]", HEADER_COLOR|SMLSIZE); + lcdDrawNumber(lcdNextPos+5, MENU_CONTENT_TOP+line*FH, luaGetMemUsed(lsWidgets), LEFT); + lcdDrawText(lcdNextPos+20, MENU_CONTENT_TOP+line*FH+1, "[B]", HEADER_COLOR|SMLSIZE); + lcdDrawNumber(lcdNextPos+5, MENU_CONTENT_TOP+line*FH, luaExtraMemoryUsage, LEFT); + ++line; + #endif lcdDrawText(LCD_W/2, MENU_FOOTER_TOP+2, STR_MENUTORESET, CENTERED); diff --git a/radio/src/gui/480x272/widget.h b/radio/src/gui/480x272/widget.h index 257c4de39..fc41f2044 100644 --- a/radio/src/gui/480x272/widget.h +++ b/radio/src/gui/480x272/widget.h @@ -56,6 +56,11 @@ class Widget inline const ZoneOption * getOptions() const; + virtual const char * getErrorMessage() const + { + return NULL; + } + inline ZoneOptionValue * getOptionValue(unsigned int index) const { return &persistentData->options[index]; diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index 6b112f845..18902946b 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -22,7 +22,7 @@ #include #include "opentx.h" #include "stamp.h" -#include "lua/lua_api.h" +#include "lua_api.h" #include "telemetry/frsky.h" #if defined(PCBX12S) diff --git a/radio/src/lua/api_lcd.cpp b/radio/src/lua/api_lcd.cpp index d6b0b5427..d2a9ed02e 100644 --- a/radio/src/lua/api_lcd.cpp +++ b/radio/src/lua/api_lcd.cpp @@ -21,7 +21,7 @@ #include #include #include "opentx.h" -#include "lua/lua_api.h" +#include "lua_api.h" /*luadoc @function lcd.refresh() @@ -339,12 +339,16 @@ static int luaOpenBitmap(lua_State * L) BitmapBuffer ** ptr = (BitmapBuffer **)lua_newuserdata(L, sizeof(BitmapBuffer *)); *ptr = BitmapBuffer::load(filename); - TRACE("luaOpenBitmap: %p", *ptr); if (*ptr == NULL && G(L)->gcrunning) { luaC_fullgc(L, 1); /* try to free some memory... */ *ptr = BitmapBuffer::load(filename); /* try again */ - TRACE("luaOpenBitmap: %p (second try)", *ptr); + } + + if (*ptr) { + uint32_t size = (*ptr)->getDataSize(); + luaExtraMemoryUsage += size; + TRACE("luaOpenBitmap: %p (%u)", *ptr, size); } luaL_getmetatable(L, LUA_BITMAPHANDLE); @@ -389,7 +393,9 @@ static int luaGetBitmapSize(lua_State * L) static int luaDestroyBitmap(lua_State * L) { BitmapBuffer * ptr = checkBitmap(L, 1); - TRACE("luaDestroyBitmap: %p", ptr); + uint32_t size = ptr->getDataSize(); + TRACE("luaDestroyBitmap: %p (%u)", ptr, size); + if (luaExtraMemoryUsage > size) luaExtraMemoryUsage -= size; delete ptr; return 0; } diff --git a/radio/src/lua/api_model.cpp b/radio/src/lua/api_model.cpp index 1e8a6a8b4..671209ee8 100644 --- a/radio/src/lua/api_model.cpp +++ b/radio/src/lua/api_model.cpp @@ -21,13 +21,13 @@ #include #include #include "opentx.h" -#include "lua/lua_api.h" +#include "lua_api.h" #include "timers.h" /*luadoc @function model.getInfo() -Get current Model information +Get current Model information @retval table model information: * `name` (string) model name diff --git a/radio/src/lua/interface.cpp b/radio/src/lua/interface.cpp index 15af7c193..4e944ab87 100644 --- a/radio/src/lua/interface.cpp +++ b/radio/src/lua/interface.cpp @@ -24,7 +24,7 @@ #include #include "opentx.h" #include "bin_allocator.h" -#include "lua/lua_api.h" +#include "lua_api.h" #include "sdcard.h" extern "C" { @@ -47,11 +47,14 @@ bool luaLcdAllowed; int instructionsPercent = 0; char lua_warning_info[LUA_WARNING_INFO_LEN+1]; struct our_longjmp * global_lj = 0; +#if defined(COLORLCD) +uint32_t luaExtraMemoryUsage = 0; +#endif /* custom panic handler */ int custom_lua_atpanic(lua_State * L) { - TRACE("PANIC: unprotected error in call to Lua API (%s)\n", lua_tostring(L, -1)); + TRACE("PANIC: unprotected error in call to Lua API (%s)", lua_tostring(L, -1)); if (global_lj) { longjmp(global_lj->b, 1); /* will never return */ @@ -66,7 +69,7 @@ void luaHook(lua_State * L, lua_Debug *ar) // From now on, as soon as a line is executed, error // keep erroring until you're script reaches the top lua_sethook(L, luaHook, LUA_MASKLINE, 0); - luaL_error(L, ""); + luaL_error(L, "CPU limit"); } } @@ -177,23 +180,45 @@ void luaRegisterLibraries(lua_State * L) #endif } -void luaDoGc(lua_State * L) +#define GC_REPORT_TRESHOLD (2*1024) + +void luaDoGc(lua_State * L, bool full) { if (L) { PROTECT_LUA() { - lua_gc(L, LUA_GCCOLLECT, 0); -#if defined(SIMU) || defined(DEBUG) - static int lastgc = 0; - int gc = luaGetMemUsed(L); - if (gc != lastgc) { - lastgc = gc; - TRACE("GC Use: %dbytes", gc); + if (full) { + lua_gc(L, LUA_GCCOLLECT, 0); } + else { + lua_gc(L, LUA_GCSTEP, 10); + } +#if defined(SIMU) || defined(DEBUG) + if (L == lsScripts) { + static uint32_t lastgcSctipts = 0; + uint32_t gc = luaGetMemUsed(L); + if (gc > (lastgcSctipts + GC_REPORT_TRESHOLD) || (gc + GC_REPORT_TRESHOLD) < lastgcSctipts) { + lastgcSctipts = gc; + TRACE("GC Use Scripts: %u bytes", gc); + } + } +#if defined(COLORLCD) + if (L == lsWidgets) { + static uint32_t lastgcWidgets = 0; + uint32_t gc = luaGetMemUsed(L); + if (gc > (lastgcWidgets + GC_REPORT_TRESHOLD) || (gc + GC_REPORT_TRESHOLD) < lastgcWidgets) { + lastgcWidgets = gc; + TRACE("GC Use Widgets: %u bytes + Extra %u", gc, luaExtraMemoryUsage); + } + } +#endif #endif } else { // we disable Lua for the rest of the session - luaDisable(); + if (L == lsScripts) luaDisable(); +#if defined(COLORLCD) + if (L == lsWidgets) lsWidgets = 0; +#endif } UNPROTECT_LUA(); } @@ -216,7 +241,7 @@ void luaFree(lua_State * L, ScriptInternalData & sid) } UNPROTECT_LUA(); - luaDoGc(L); + luaDoGc(L, true); } #if defined(LUA_COMPILER) @@ -494,7 +519,7 @@ static int luaLoad(lua_State * L, const char * filename, ScriptInternalData & si luaFree(L, sid); } - luaDoGc(L); + luaDoGc(L, true); return sid.state; } @@ -922,11 +947,14 @@ bool luaTask(event_t evt, uint8_t scriptType, bool allowLcdUsage) //todo gc step between scripts } } - luaDoGc(lsScripts); + luaDoGc(lsScripts, false); +#if defined(COLORLCD) + luaDoGc(lsWidgets, false); +#endif return scriptWasRun; } -int luaGetMemUsed(lua_State * L) +uint32_t luaGetMemUsed(lua_State * L) { return L ? (lua_gc(L, LUA_GCCOUNT, 0) << 10) + lua_gc(L, LUA_GCCOUNTB, 0) : 0; } diff --git a/radio/src/lua/lua_api.h b/radio/src/lua/lua_api.h index 328e84335..5aaa8f88c 100644 --- a/radio/src/lua/lua_api.h +++ b/radio/src/lua/lua_api.h @@ -44,6 +44,9 @@ extern "C" { extern lua_State * lsScripts; extern lua_State * lsWidgets; extern bool luaLcdAllowed; +#if defined(COLORLCD) +extern uint32_t luaExtraMemoryUsage; +#endif void luaInit(); void luaInitThemesAndWidgets(); @@ -116,8 +119,9 @@ extern ScriptInputsOutputs scriptInputsOutputs[MAX_SCRIPTS]; void luaClose(lua_State ** L); bool luaTask(event_t evt, uint8_t scriptType, bool allowLcdUsage); void luaExec(const char * filename); +void luaDoGc(lua_State * L, bool full); void luaError(lua_State * L, uint8_t error, bool acknowledge=true); -int luaGetMemUsed(lua_State * L); +uint32_t luaGetMemUsed(lua_State * L); void luaGetValueAndPush(lua_State * L, int src); #define luaGetCpuUsed(idx) scriptInternalData[idx].instructions uint8_t isTelemetryScriptAvailable(uint8_t index); diff --git a/radio/src/lua/widgets.cpp b/radio/src/lua/widgets.cpp index d4b27a29b..4ae351021 100644 --- a/radio/src/lua/widgets.cpp +++ b/radio/src/lua/widgets.cpp @@ -22,7 +22,7 @@ #include #include "opentx.h" #include "bin_allocator.h" -#include "lua/lua_api.h" +#include "lua_api.h" #define WIDGET_SCRIPTS_MAX_INSTRUCTIONS (10000/100) #define MANUAL_SCRIPTS_MAX_INSTRUCTIONS (20000/100) @@ -42,6 +42,7 @@ void exec(int function, int nresults=0) lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, function); if (lua_pcall(lsWidgets, 0, nresults, 0) != 0) { TRACE("Error in theme %s", lua_tostring(lsWidgets, -1)); + // TODO disable theme - revert back to default theme??? } } } @@ -63,46 +64,52 @@ ZoneOption * createOptionsArray(int reference) return NULL; } - lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, reference); - ZoneOption * option = options; - for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) { - luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number - luaL_checktype(lsWidgets, -1, LUA_TTABLE); // value is table - uint8_t field = 0; - for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2) && field<5; lua_pop(lsWidgets, 1), field++) { - switch (field) { - case 0: - luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number - luaL_checktype(lsWidgets, -1, LUA_TSTRING); // value is string - option->name = lua_tostring(lsWidgets, -1); - break; - case 1: - luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number - luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number - option->type = (ZoneOption::Type)lua_tointeger(lsWidgets, -1); - break; - case 2: - luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number - luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number - option->deflt.signedValue = lua_tointeger(lsWidgets, -1); - break; - case 3: - luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number - luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number - option->min.signedValue = lua_tointeger(lsWidgets, -1); - break; - case 4: - luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number - luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number - option->max.signedValue = lua_tointeger(lsWidgets, -1); - break; + PROTECT_LUA() { + lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, reference); + ZoneOption * option = options; + for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) { + luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number + luaL_checktype(lsWidgets, -1, LUA_TTABLE); // value is table + uint8_t field = 0; + for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2) && field<5; lua_pop(lsWidgets, 1), field++) { + switch (field) { + case 0: + luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number + luaL_checktype(lsWidgets, -1, LUA_TSTRING); // value is string + option->name = lua_tostring(lsWidgets, -1); + break; + case 1: + luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number + luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number + option->type = (ZoneOption::Type)lua_tointeger(lsWidgets, -1); + break; + case 2: + luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number + luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number + option->deflt.signedValue = lua_tointeger(lsWidgets, -1); + break; + case 3: + luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number + luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number + option->min.signedValue = lua_tointeger(lsWidgets, -1); + break; + case 4: + luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number + luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number + option->max.signedValue = lua_tointeger(lsWidgets, -1); + break; + } } + option++; } - option++; + option->name = NULL; // sentinel } - - option->name = NULL; // sentinel - + else { + TRACE("error in theme/widget options"); + free(options); + return NULL; + } + UNPROTECT_LUA(); return options; } @@ -111,8 +118,8 @@ class LuaTheme: public Theme friend void luaLoadThemeCallback(); public: - LuaTheme(const char * name, int options): - Theme(name, createOptionsArray(options)), + LuaTheme(const char * name, ZoneOption * options): + Theme(name, options), loadFunction(0), drawBackgroundFunction(0), drawTopbarBackgroundFunction(0), @@ -182,11 +189,14 @@ void luaLoadThemeCallback() } if (name) { - LuaTheme * theme = new LuaTheme(name, themeOptions); - theme->loadFunction = loadFunction; - theme->drawBackgroundFunction = drawBackgroundFunction; - theme->drawTopbarBackgroundFunction = drawTopbarBackgroundFunction; - TRACE("Loaded Lua theme %s", name); + ZoneOption * options = createOptionsArray(themeOptions); + if (options) { + LuaTheme * theme = new LuaTheme(name, options); + theme->loadFunction = loadFunction; + theme->drawBackgroundFunction = drawBackgroundFunction; + theme->drawTopbarBackgroundFunction = drawTopbarBackgroundFunction; + TRACE("Loaded Lua theme %s", name); + } } } @@ -195,23 +205,30 @@ class LuaWidget: public Widget public: LuaWidget(const WidgetFactory * factory, const Zone & zone, Widget::PersistentData * persistentData, int widgetData): Widget(factory, zone, persistentData), - widgetData(widgetData) + widgetData(widgetData), + errorMessage(0) { } virtual ~LuaWidget() { luaL_unref(lsWidgets, LUA_REGISTRYINDEX, widgetData); + if (errorMessage) free(errorMessage); } - virtual void update() const; + virtual void update(); virtual void refresh(); virtual void background(); + virtual const char * getErrorMessage() const; + protected: int widgetData; + char * errorMessage; + + void setErrorMessage(const char * funcName); }; void l_pushtableint(const char * key, int value) @@ -227,8 +244,8 @@ class LuaWidgetFactory: public WidgetFactory friend class LuaWidget; public: - LuaWidgetFactory(const char * name, int widgetOptions, int createFunction): - WidgetFactory(name, createOptionsArray(widgetOptions)), + LuaWidgetFactory(const char * name, ZoneOption * widgetOptions, int createFunction): + WidgetFactory(name, widgetOptions), createFunction(createFunction), updateFunction(0), refreshFunction(0), @@ -273,9 +290,9 @@ class LuaWidgetFactory: public WidgetFactory int backgroundFunction; }; -void LuaWidget::update() const +void LuaWidget::update() { - if (lsWidgets == 0) return; + if (lsWidgets == 0 || errorMessage) return; luaSetInstructionsLimit(lsWidgets, WIDGET_SCRIPTS_MAX_INSTRUCTIONS); LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory; @@ -289,26 +306,48 @@ void LuaWidget::update() const } if (lua_pcall(lsWidgets, 2, 0, 0) != 0) { - TRACE("Error in widget %s update() function: %s", factory->getName(), lua_tostring(lsWidgets, -1)); + setErrorMessage("update()"); } } +void LuaWidget::setErrorMessage(const char * funcName) +{ + TRACE("Error in widget %s %s function: %s", factory->getName(), funcName, lua_tostring(lsWidgets, -1)); + TRACE("Widget disabled"); + size_t needed = snprintf(NULL, 0, "%s: %s", funcName, lua_tostring(lsWidgets, -1)) + 1; + errorMessage = (char *)malloc(needed); + if (errorMessage) { + snprintf(errorMessage, needed, "%s: %s", funcName, lua_tostring(lsWidgets, -1)); + } +} + +const char * LuaWidget::getErrorMessage() const +{ + return errorMessage; +} + void LuaWidget::refresh() { if (lsWidgets == 0) return; + if (errorMessage) { + lcdSetColor(RED); + lcdDrawText(zone.x, zone.y, "Disabled", SMLSIZE|CUSTOM_COLOR); + return; + } + luaSetInstructionsLimit(lsWidgets, WIDGET_SCRIPTS_MAX_INSTRUCTIONS); LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory; lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, factory->refreshFunction); lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, widgetData); if (lua_pcall(lsWidgets, 1, 0, 0) != 0) { - TRACE("Error in widget %s refresh() function: %s", factory->getName(), lua_tostring(lsWidgets, -1)); + setErrorMessage("refresh()"); } } void LuaWidget::background() { - if (lsWidgets == 0) return; + if (lsWidgets == 0 || errorMessage) return; luaSetInstructionsLimit(lsWidgets, WIDGET_SCRIPTS_MAX_INSTRUCTIONS); LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory; @@ -316,7 +355,7 @@ void LuaWidget::background() lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, factory->backgroundFunction); lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, widgetData); if (lua_pcall(lsWidgets, 1, 0, 0) != 0) { - TRACE("Error in widget %s background() function: %s", factory->getName(), lua_tostring(lsWidgets, -1)); + setErrorMessage("background()"); } } } @@ -357,11 +396,14 @@ void luaLoadWidgetCallback() } if (name && createFunction) { - LuaWidgetFactory * factory = new LuaWidgetFactory(name, widgetOptions, createFunction); - factory->updateFunction = updateFunction; - factory->refreshFunction = refreshFunction; - factory->backgroundFunction = backgroundFunction; - TRACE("Loaded Lua widget %s", name); + ZoneOption * options = createOptionsArray(widgetOptions); + if (options) { + LuaWidgetFactory * factory = new LuaWidgetFactory(name, options, createFunction); + factory->updateFunction = updateFunction; + factory->refreshFunction = refreshFunction; + factory->backgroundFunction = backgroundFunction; + TRACE("Loaded Lua widget %s", name); + } } } @@ -385,8 +427,8 @@ void luaLoadFile(const char * filename, void (*callback)()) } } else { - // luaDisable(); - lsWidgets = 0; + // error while loading Lua widget/theme, + // do not disable whole Lua state, just ingnore bad widget/theme return; } UNPROTECT_LUA(); @@ -453,5 +495,6 @@ void luaInitThemesAndWidgets() TRACE("lsWidgets %p", lsWidgets); luaLoadFiles(THEMES_PATH, luaLoadThemeCallback); luaLoadFiles(WIDGETS_PATH, luaLoadWidgetCallback); + luaDoGc(lsWidgets, true); } }