diff --git a/radio/src/gui/colorlcd/mainview/widget.cpp b/radio/src/gui/colorlcd/mainview/widget.cpp index 6d2bc7820..06ac7094a 100644 --- a/radio/src/gui/colorlcd/mainview/widget.cpp +++ b/radio/src/gui/colorlcd/mainview/widget.cpp @@ -203,8 +203,6 @@ void Widget::onCancel() if (!fullscreen) ButtonBase::onCancel(); } -void Widget::update() {} - void Widget::setFullscreen(bool enable) { if (!!parent->isTopBar() || (enable == fullscreen)) return; @@ -252,7 +250,8 @@ void Widget::setFullscreen(bool enable) onFullscreen(enable); - update(); + if (fullscreen) + updateWithoutRefresh(); } bool Widget::onLongPress() diff --git a/radio/src/gui/colorlcd/mainview/widget.h b/radio/src/gui/colorlcd/mainview/widget.h index 53ad7f8b9..b1a6f0674 100644 --- a/radio/src/gui/colorlcd/mainview/widget.h +++ b/radio/src/gui/colorlcd/mainview/widget.h @@ -106,7 +106,8 @@ class Widget : public ButtonBase virtual bool enableFullScreenRE() const { return true; } // Called when the widget options have changed - virtual void update(); + virtual void updateWithoutRefresh() {} + virtual void update() {} // Called at regular time interval if the widget is hidden or off screen virtual void background() {} diff --git a/radio/src/gui/colorlcd/mainview/widget_settings.cpp b/radio/src/gui/colorlcd/mainview/widget_settings.cpp index 99a1003a9..03d702dc2 100644 --- a/radio/src/gui/colorlcd/mainview/widget_settings.cpp +++ b/radio/src/gui/colorlcd/mainview/widget_settings.cpp @@ -220,6 +220,6 @@ WidgetSettings::WidgetSettings(Widget* w) : void WidgetSettings::onCancel() { - widget->update(); + widget->updateWithoutRefresh(); deleteLater(); } diff --git a/radio/src/gui/colorlcd/standalone_lua.cpp b/radio/src/gui/colorlcd/standalone_lua.cpp index f26ada8c9..fe3598a04 100644 --- a/radio/src/gui/colorlcd/standalone_lua.cpp +++ b/radio/src/gui/colorlcd/standalone_lua.cpp @@ -196,8 +196,8 @@ void StandaloneLuaWindow::deleteLater() { if (_deleted) return; - if (initFunction != LUA_REFNIL) luaL_unref(lsStandalone, LUA_REGISTRYINDEX, initFunction); - if (runFunction != LUA_REFNIL) luaL_unref(lsStandalone, LUA_REGISTRYINDEX, runFunction); + luaL_unref(lsStandalone, LUA_REGISTRYINDEX, initFunction); + luaL_unref(lsStandalone, LUA_REGISTRYINDEX, runFunction); luaLcdBuffer = nullptr; luaClose(&lsStandalone); diff --git a/radio/src/lua/lua_lvgl_widget.cpp b/radio/src/lua/lua_lvgl_widget.cpp index 827c8d2e0..27364e71f 100644 --- a/radio/src/lua/lua_lvgl_widget.cpp +++ b/radio/src/lua/lua_lvgl_widget.cpp @@ -40,13 +40,28 @@ //----------------------------------------------------------------------------- +#if defined(DEBUG) +int32_t refCnt = 0; +#endif + static void clearRef(lua_State *L, int& ref) { +#if defined(DEBUG) if (ref != LUA_REFNIL) - luaL_unref(L, LUA_REGISTRYINDEX, ref); + refCnt -= 1; +#endif + luaL_unref(L, LUA_REGISTRYINDEX, ref); ref = LUA_REFNIL; } +static int getRef(lua_State *L, int t) +{ +#if defined(DEBUG) + refCnt += 1; +#endif + return luaL_ref(L, t); +} + static bool getLuaBool(lua_State *L) { if (lua_isboolean(L, -1)) @@ -59,7 +74,7 @@ static bool getLuaBool(lua_State *L) void LvglParamFuncOrValue::parse(lua_State *L) { if (lua_isfunction(L, -1)) { - function = luaL_ref(L, LUA_REGISTRYINDEX); + function = ::getRef(L, LUA_REGISTRYINDEX); } else if (lua_isboolean(L, -1)) { value = lua_toboolean(L, -1); } else { @@ -95,7 +110,7 @@ void LvglParamFuncOrValue::clearRef(lua_State *L) void LvglParamFuncOrString::parse(lua_State *L) { if (lua_isfunction(L, -1)) { - function = luaL_ref(L, LUA_REGISTRYINDEX); + function = ::getRef(L, LUA_REGISTRYINDEX); } else { txt = luaL_checkstring(L, -1); } @@ -122,11 +137,11 @@ void LvglParamFuncOrString::clearRef(lua_State *L) bool LvglGetSetParams::parseGetSetParam(lua_State *L, const char *key) { if (!strcmp(key, "get")) { - getFunction = luaL_ref(L, LUA_REGISTRYINDEX); + getFunction = ::getRef(L, LUA_REGISTRYINDEX); return true; } if (!strcmp(key, "set")) { - setFunction = luaL_ref(L, LUA_REGISTRYINDEX); + setFunction = ::getRef(L, LUA_REGISTRYINDEX); return true; } return false; @@ -248,16 +263,22 @@ bool LvglScrollableParams::parseScrollableParam(lua_State *L, const char *key) return true; } if (!strcmp(key, "scrollTo")) { - scrollToFunction = luaL_ref(L, LUA_REGISTRYINDEX); + scrollToFunction = ::getRef(L, LUA_REGISTRYINDEX); return true; } if (!strcmp(key, "scrolled")) { - scrolledFunction = luaL_ref(L, LUA_REGISTRYINDEX); + scrolledFunction = ::getRef(L, LUA_REGISTRYINDEX); return true; } return false; } +void LvglScrollableParams::clearScrollableRefs(lua_State *L) +{ + clearRef(L, scrollToFunction); + clearRef(L, scrolledFunction); +} + //----------------------------------------------------------------------------- static int pcallcont (lua_State *L, int status, lua_KContext extra) { @@ -340,7 +361,7 @@ int LvglWidgetObjectBase::getRef(lua_State *L) lua_setmetatable(L, -2); // Save reference - luaRef = luaL_ref(L, LUA_REGISTRYINDEX); + luaRef = ::getRef(L, LUA_REGISTRYINDEX); lvglManager->saveLvglObjectRef(luaRef); return luaRef; @@ -627,11 +648,11 @@ void LvglWidgetObjectBase::parseParam(lua_State *L, const char *key) } else if (!strcmp(key, "opacity")) { opacity.parse(L); } else if (!strcmp(key, "visible")) { - getVisibleFunction = luaL_ref(L, LUA_REGISTRYINDEX); + getVisibleFunction = ::getRef(L, LUA_REGISTRYINDEX); } else if (!strcmp(key, "size")) { - getSizeFunction = luaL_ref(L, LUA_REGISTRYINDEX); + getSizeFunction = ::getRef(L, LUA_REGISTRYINDEX); } else if (!strcmp(key, "pos")) { - getPosFunction = luaL_ref(L, LUA_REGISTRYINDEX); + getPosFunction = ::getRef(L, LUA_REGISTRYINDEX); } } @@ -991,7 +1012,7 @@ void LvglWidgetLine::parseParam(lua_State *L, const char *key) if (parseThicknessParam(L, key)) return; if (!strcmp(key, "pts")) { if (lua_isfunction(L, -1)) { - getPointsFunction = luaL_ref(L, LUA_REGISTRYINDEX); + getPointsFunction = ::getRef(L, LUA_REGISTRYINDEX); } else { ptsHash = getPts(L); } @@ -1134,7 +1155,7 @@ void LvglWidgetTriangle::parseParam(lua_State *L, const char *key) { if (!strcmp(key, "pts")) { if (lua_isfunction(L, -1)) { - getPointsFunction = luaL_ref(L, LUA_REGISTRYINDEX); + getPointsFunction = ::getRef(L, LUA_REGISTRYINDEX); } else { luaL_checktype(L, -1, LUA_TTABLE); getPt(L, 0); @@ -1426,7 +1447,7 @@ void LvglWidgetObject::parseParam(lua_State *L, const char *key) } } } else if (!strcmp(key, "active")) { - getActiveFunction = luaL_ref(L, LUA_REGISTRYINDEX); + getActiveFunction = ::getRef(L, LUA_REGISTRYINDEX); } else { LvglWidgetObjectBase::parseParam(L, key); } @@ -1520,7 +1541,7 @@ bool LvglWidgetBox::callRefs(lua_State *L) void LvglWidgetBox::clearRefs(lua_State *L) { clearAlignRefs(L); - clearRef(L, scrollToFunction); + clearScrollableRefs(L); LvglWidgetObject::clearRefs(L); } @@ -1948,7 +1969,7 @@ void LvglWidgetTextButtonBase::parseParam(lua_State *L, const char *key) } else if (!strcmp(key, "textColor")) { textColor.parse(L); } else if (!strcmp(key, "press")) { - pressFunction = luaL_ref(L, LUA_REGISTRYINDEX); + pressFunction = ::getRef(L, LUA_REGISTRYINDEX); } else if (!parseTextParam(L, key)) { LvglWidgetObject::parseParam(L, key); } @@ -2013,7 +2034,7 @@ void LvglWidgetTextButton::parseParam(lua_State *L, const char *key) if (!strcmp(key, "checked")) { checked = getLuaBool(L); } else if (!strcmp(key, "longpress")) { - longPressFunction = luaL_ref(L, LUA_REGISTRYINDEX); + longPressFunction = ::getRef(L, LUA_REGISTRYINDEX); } else { LvglWidgetTextButtonBase::parseParam(L, key); } @@ -2069,7 +2090,7 @@ void LvglWidgetTextButton::build(lua_State *L) void LvglWidgetMomentaryButton::parseParam(lua_State *L, const char *key) { if (!strcmp(key, "release")) { - releaseFunction = luaL_ref(L, LUA_REGISTRYINDEX); + releaseFunction = ::getRef(L, LUA_REGISTRYINDEX); } else { LvglWidgetTextButtonBase::parseParam(L, key); } @@ -2145,7 +2166,7 @@ void LvglWidgetTextEdit::parseParam(lua_State *L, const char *key) if (maxLen > 128) maxLen = 128; if (maxLen <= 0) maxLen = 32; } else if (!strcmp(key, "set")) { - setFunction = luaL_ref(L, LUA_REGISTRYINDEX); + setFunction = ::getRef(L, LUA_REGISTRYINDEX); } else { LvglWidgetObject::parseParam(L, key); } @@ -2190,9 +2211,9 @@ void LvglWidgetNumberEdit::parseParam(lua_State *L, const char *key) if (parseGetSetParam(L, key)) return; if (!strcmp(key, "display")) { - dispFunction = luaL_ref(L, LUA_REGISTRYINDEX); + dispFunction = ::getRef(L, LUA_REGISTRYINDEX); } else if (!strcmp(key, "edited")) { - editedFunction = luaL_ref(L, LUA_REGISTRYINDEX); + editedFunction = ::getRef(L, LUA_REGISTRYINDEX); } else { LvglWidgetObject::parseParam(L, key); } @@ -2401,18 +2422,18 @@ void LvglWidgetPage::parseParam(lua_State *L, const char *key) if (parseTitleParam(L, key)) return; if (parseScrollableParam(L, key)) return; if (!strcmp(key, "back")) { - backActionFunction = luaL_ref(L, LUA_REGISTRYINDEX); + backActionFunction = ::getRef(L, LUA_REGISTRYINDEX); } else if (!strcmp(key, "menu")) { - menuActionFunction = luaL_ref(L, LUA_REGISTRYINDEX); + menuActionFunction = ::getRef(L, LUA_REGISTRYINDEX); } else if (!strcmp(key, "prevButton")) { luaL_checktype(L, -1, LUA_TTABLE); for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { const char *key = lua_tostring(L, -2); if (!strcmp(key, "press")) { - prevActionFunction = luaL_ref(L, LUA_REGISTRYINDEX); + prevActionFunction = ::getRef(L, LUA_REGISTRYINDEX); lua_pushnil(L); } else if (!strcmp(key, "active")) { - prevActiveFunction = luaL_ref(L, LUA_REGISTRYINDEX); + prevActiveFunction = ::getRef(L, LUA_REGISTRYINDEX); lua_pushnil(L); } } @@ -2421,10 +2442,10 @@ void LvglWidgetPage::parseParam(lua_State *L, const char *key) for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { const char *key = lua_tostring(L, -2); if (!strcmp(key, "press")) { - nextActionFunction = luaL_ref(L, LUA_REGISTRYINDEX); + nextActionFunction = ::getRef(L, LUA_REGISTRYINDEX); lua_pushnil(L); } else if (!strcmp(key, "active")) { - nextActiveFunction = luaL_ref(L, LUA_REGISTRYINDEX); + nextActiveFunction = ::getRef(L, LUA_REGISTRYINDEX); lua_pushnil(L); } } @@ -2483,6 +2504,7 @@ void LvglWidgetPage::clearRefs(lua_State *L) { clearAlignRefs(L); clearTitleRefs(L); + clearScrollableRefs(L); subtitle.clearRef(L); clearRef(L, backActionFunction); clearRef(L, menuActionFunction); @@ -2548,7 +2570,7 @@ void LvglWidgetDialog::parseParam(lua_State *L, const char *key) { if (parseTitleParam(L, key)) return; if (!strcmp(key, "close")) { - closeFunction = luaL_ref(L, LUA_REGISTRYINDEX); + closeFunction = ::getRef(L, LUA_REGISTRYINDEX); } else { LvglWidgetObject::parseParam(L, key); } @@ -2586,9 +2608,9 @@ void LvglWidgetConfirmDialog::parseParam(lua_State *L, const char *key) if (parseTitleParam(L, key)) return; if (parseMessageParam(L, key)) return; if (!strcmp(key, "confirm")) { - confirmFunction = luaL_ref(L, LUA_REGISTRYINDEX); + confirmFunction = ::getRef(L, LUA_REGISTRYINDEX); } else if (!strcmp(key, "cancel")) { - cancelFunction = luaL_ref(L, LUA_REGISTRYINDEX); + cancelFunction = ::getRef(L, LUA_REGISTRYINDEX); } else { LvglWidgetObject::parseParam(L, key); } @@ -2655,7 +2677,7 @@ void LvglWidgetChoice::parseParam(lua_State *L, const char *key) if (parseTitleParam(L, key)) return; if (parseValuesParam(L, key)) return; if (!strcmp(key, "filter")) { - filterFunction = luaL_ref(L, LUA_REGISTRYINDEX); + filterFunction = ::getRef(L, LUA_REGISTRYINDEX); } else if (!strcmp(key, "popupWidth")) { popupWidth = luaL_checkinteger(L, -1); } else { diff --git a/radio/src/lua/lua_lvgl_widget.h b/radio/src/lua/lua_lvgl_widget.h index 57b5e34e8..370daab67 100644 --- a/radio/src/lua/lua_lvgl_widget.h +++ b/radio/src/lua/lua_lvgl_widget.h @@ -231,6 +231,7 @@ class LvglScrollableParams int scrolledFunction = LUA_REFNIL; bool parseScrollableParam(lua_State *L, const char *key); + void clearScrollableRefs(lua_State *L); }; //----------------------------------------------------------------------------- diff --git a/radio/src/lua/lua_widget.cpp b/radio/src/lua/lua_widget.cpp index 9d2c9dd2d..0cee00c14 100644 --- a/radio/src/lua/lua_widget.cpp +++ b/radio/src/lua/lua_widget.cpp @@ -251,7 +251,7 @@ LuaWidget::LuaWidget(const WidgetFactory* factory, Window* parent, if (lua_pcall(lsWidgets, 3, 1, 0) == LUA_OK) { luaScriptContextRef = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); } else { - luaScriptContextRef = LUA_NOREF; + luaScriptContextRef = LUA_REFNIL; setErrorMessage("create()"); } @@ -267,9 +267,9 @@ LuaWidget::LuaWidget(const WidgetFactory* factory, Window* parent, LuaWidget::~LuaWidget() { - luaL_unref(lsWidgets, LUA_REGISTRYINDEX, luaScriptContextRef); luaL_unref(lsWidgets, LUA_REGISTRYINDEX, zoneRectDataRef); - free(errorMessage); + if (errorMessage) + free(errorMessage); } void LuaWidget::onClicked() @@ -308,12 +308,12 @@ void LuaWidget::foreground() refresh(nullptr); if (!errorMessage) { if (!callRefs(lsWidgets)) { - setErrorMessage("function"); + setErrorMessage("foreground calRefs error"); } } refreshInstructionsPercent = instructionsPercent; } else { - setErrorMessage("function"); + setErrorMessage("foreground protect Lua error"); } luaScriptManager = save; UNPROTECT_LUA(); @@ -328,11 +328,11 @@ void LuaWidget::foreground() #endif } -void LuaWidget::update() +void LuaWidget::updateWithoutRefresh() { - Widget::update(); + Widget::updateWithoutRefresh(); - if (lsWidgets == 0 || errorMessage) return; + if (lsWidgets == 0 || errorMessage || luaFactory()->updateFunction == LUA_REFNIL) return; luaSetInstructionsLimit(lsWidgets, MAX_INSTRUCTIONS); lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaFactory()->updateFunction); @@ -366,6 +366,18 @@ void LuaWidget::update() if (lua_pcall(lsWidgets, 2, 0, 0) != 0) setErrorMessage("update()"); + luaScriptManager = save; +} + +void LuaWidget::update() +{ + updateWithoutRefresh(); + + Widget::update(); + + auto save = luaScriptManager; + luaScriptManager = this; + if (useLvglLayout()) { if (!lv_obj_has_flag(lvobj, LV_OBJ_FLAG_HIDDEN)) { lv_area_t a; @@ -374,10 +386,10 @@ void LuaWidget::update() if (a.x2 >= 0 && a.x1 < LCD_W) { PROTECT_LUA() { if (!callRefs(lsWidgets)) { - setErrorMessage("function"); + setErrorMessage("update callRefs error"); } } else { - setErrorMessage("function"); + setErrorMessage("update protect Lua error"); } UNPROTECT_LUA(); } @@ -429,7 +441,7 @@ void LuaWidget::updateZoneRect(rect_t rect, bool updateUI) lua_pop(lsWidgets, 1); if (changed && updateUI) - update(); + updateWithoutRefresh(); } } @@ -452,7 +464,8 @@ void LuaWidget::setErrorMessage(const char* funcName) lua_err); TRACE("Widget disabled"); - errorMessage = (char*)malloc(err_len + 1); + if (!errorMessage) + errorMessage = (char*)malloc(err_len + 1); if (errorMessage) { snprintf(errorMessage, err_len, "ERROR in %s: %s", funcName, lua_err); @@ -469,7 +482,7 @@ const char* LuaWidget::getErrorMessage() const { return errorMessage; } void LuaWidget::refresh(BitmapBuffer* dc) { - if (lsWidgets == 0) return; + if (lsWidgets == 0 || luaFactory()->refreshFunction == LUA_REFNIL) return; if (errorMessage) { if (dc) { @@ -531,7 +544,7 @@ void LuaWidget::background() { if (lsWidgets == 0 || errorMessage) return; - if (luaFactory()->backgroundFunction) { + if (luaFactory()->backgroundFunction != LUA_REFNIL) { luaSetInstructionsLimit(lsWidgets, MAX_INSTRUCTIONS); lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaFactory()->backgroundFunction); lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaScriptContextRef); @@ -605,6 +618,7 @@ void LuaScriptManager::createTelemetryQueue() LuaScriptManager::~LuaScriptManager() { + luaL_unref(lsWidgets, LUA_REGISTRYINDEX, luaScriptContextRef); if (luaInputTelemetryFifo != nullptr) { deregisterTelemetryQueue(luaInputTelemetryFifo); delete luaInputTelemetryFifo; diff --git a/radio/src/lua/lua_widget.h b/radio/src/lua/lua_widget.h index 88ec8750c..44bf26d4d 100644 --- a/radio/src/lua/lua_widget.h +++ b/radio/src/lua/lua_widget.h @@ -94,7 +94,7 @@ class LuaScriptManager : public LuaEventHandler TelemetryQueue* telemetryQueue() { return luaInputTelemetryFifo; } protected: - int luaScriptContextRef = 0; + int luaScriptContextRef = LUA_REFNIL; std::vector lvglObjectRefs; LvglWidgetObjectBase* tempParent = nullptr; #if defined(LUA) @@ -118,6 +118,7 @@ class LuaWidget : public Widget, public LuaScriptManager // Widget interface const char* getErrorMessage() const override; + void updateWithoutRefresh() override; void update() override; void background() override; void foreground() override; diff --git a/radio/src/lua/lua_widget_factory.cpp b/radio/src/lua/lua_widget_factory.cpp index c3d9059d7..9667f1581 100644 --- a/radio/src/lua/lua_widget_factory.cpp +++ b/radio/src/lua/lua_widget_factory.cpp @@ -49,6 +49,13 @@ LuaWidgetFactory::LuaWidgetFactory(const char* name, WidgetOption* widgetOptions LuaWidgetFactory::~LuaWidgetFactory() { unregisterWidget(this); + luaL_unref(lsWidgets, LUA_REGISTRYINDEX, optionDefinitionsReference); + luaL_unref(lsWidgets, LUA_REGISTRYINDEX, createFunction); + luaL_unref(lsWidgets, LUA_REGISTRYINDEX, updateFunction); + luaL_unref(lsWidgets, LUA_REGISTRYINDEX, refreshFunction); + luaL_unref(lsWidgets, LUA_REGISTRYINDEX, backgroundFunction); + luaL_unref(lsWidgets, LUA_REGISTRYINDEX, translateFunction); + if (name) delete name; if (displayName) delete displayName; @@ -108,7 +115,7 @@ void LuaWidgetFactory::translateOptions(WidgetOption * options) if (lsWidgets == 0) return; // No translations provided - if (!translateFunction) return; + if (translateFunction == LUA_REFNIL) return; #if defined(ALL_LANGS) char lang[3]; diff --git a/radio/src/lua/widgets.cpp b/radio/src/lua/widgets.cpp index 2861789eb..a577bbecf 100644 --- a/radio/src/lua/widgets.cpp +++ b/radio/src/lua/widgets.cpp @@ -103,8 +103,8 @@ void luaLoadWidgetCallback(const char* filename) TRACE("luaLoadWidgetCallback()"); const char * name=NULL; - int optionDefinitionsReference = LUA_REFNIL, createFunction = 0, updateFunction = 0, - refreshFunction = 0, backgroundFunction = 0, translateFunction = 0; + int optionDefinitionsReference = LUA_REFNIL, createFunction = LUA_REFNIL, updateFunction = LUA_REFNIL, + refreshFunction = LUA_REFNIL, backgroundFunction = LUA_REFNIL, translateFunction = LUA_REFNIL; bool lvglLayout = false; luaL_checktype(lsWidgets, -1, LUA_TTABLE); @@ -143,7 +143,7 @@ void luaLoadWidgetCallback(const char* filename) } } - if (name && createFunction) { + if (name && createFunction != LUA_REFNIL) { WidgetOption * options = LuaWidgetFactory::parseOptionDefinitions(optionDefinitionsReference); if (options) { new LuaWidgetFactory(strdup(name), options, optionDefinitionsReference,