mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-29 22:20:33 +00:00
Prevent stale pointers in UI widgets
This commit is contained in:
parent
ac21cf3bb3
commit
481e63ffa7
@ -238,6 +238,11 @@ namespace MWLua
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LuaManager::synchronizedUpdate()
|
void LuaManager::synchronizedUpdate()
|
||||||
|
{
|
||||||
|
mLua.protectedCall([&](LuaUtil::LuaView&) { synchronizedUpdateUnsafe(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaManager::synchronizedUpdateUnsafe()
|
||||||
{
|
{
|
||||||
if (mNewGameStarted)
|
if (mNewGameStarted)
|
||||||
{
|
{
|
||||||
|
@ -170,6 +170,7 @@ namespace MWLua
|
|||||||
LocalScripts* createLocalScripts(const MWWorld::Ptr& ptr,
|
LocalScripts* createLocalScripts(const MWWorld::Ptr& ptr,
|
||||||
std::optional<LuaUtil::ScriptIdsWithInitializationData> autoStartConf = std::nullopt);
|
std::optional<LuaUtil::ScriptIdsWithInitializationData> autoStartConf = std::nullopt);
|
||||||
void reloadAllScriptsImpl();
|
void reloadAllScriptsImpl();
|
||||||
|
void synchronizedUpdateUnsafe();
|
||||||
|
|
||||||
bool mInitialized = false;
|
bool mInitialized = false;
|
||||||
bool mGlobalScriptsStarted = false;
|
bool mGlobalScriptsStarted = false;
|
||||||
|
@ -113,6 +113,7 @@ namespace LuaUi
|
|||||||
ContentView content(LuaUtil::cast<sol::table>(contentObj));
|
ContentView content(LuaUtil::cast<sol::table>(contentObj));
|
||||||
result.resize(content.size());
|
result.resize(content.size());
|
||||||
size_t minSize = std::min(children.size(), content.size());
|
size_t minSize = std::min(children.size(), content.size());
|
||||||
|
std::vector<WidgetExtension*> toDestroy;
|
||||||
for (size_t i = 0; i < minSize; i++)
|
for (size_t i = 0; i < minSize; i++)
|
||||||
{
|
{
|
||||||
WidgetExtension* ext = children[i];
|
WidgetExtension* ext = children[i];
|
||||||
@ -121,7 +122,7 @@ namespace LuaUi
|
|||||||
{
|
{
|
||||||
WidgetExtension* root = pluckElementRoot(child, depth);
|
WidgetExtension* root = pluckElementRoot(child, depth);
|
||||||
if (ext != root)
|
if (ext != root)
|
||||||
destroyChild(ext);
|
toDestroy.emplace_back(ext);
|
||||||
result[i] = root;
|
result[i] = root;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -133,14 +134,12 @@ namespace LuaUi
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
destroyChild(ext);
|
toDestroy.emplace_back(ext);
|
||||||
ext = createWidget(newLayout, false, depth);
|
ext = createWidget(newLayout, false, depth);
|
||||||
}
|
}
|
||||||
result[i] = ext;
|
result[i] = ext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (size_t i = minSize; i < children.size(); i++)
|
|
||||||
destroyChild(children[i]);
|
|
||||||
for (size_t i = minSize; i < content.size(); i++)
|
for (size_t i = minSize; i < content.size(); i++)
|
||||||
{
|
{
|
||||||
sol::object child = content.at(i);
|
sol::object child = content.at(i);
|
||||||
@ -149,6 +148,11 @@ namespace LuaUi
|
|||||||
else
|
else
|
||||||
result[i] = createWidget(child.as<sol::table>(), false, depth);
|
result[i] = createWidget(child.as<sol::table>(), false, depth);
|
||||||
}
|
}
|
||||||
|
// Don't destroy anything until element creation has had a chance to throw
|
||||||
|
for (size_t i = minSize; i < children.size(); i++)
|
||||||
|
destroyChild(children[i]);
|
||||||
|
for (WidgetExtension* ext : toDestroy)
|
||||||
|
destroyChild(ext);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,7 +221,9 @@ namespace LuaUi
|
|||||||
std::string setLayer(WidgetExtension* ext, const sol::table& layout)
|
std::string setLayer(WidgetExtension* ext, const sol::table& layout)
|
||||||
{
|
{
|
||||||
MyGUI::ILayer* layerNode = ext->widget()->getLayer();
|
MyGUI::ILayer* layerNode = ext->widget()->getLayer();
|
||||||
std::string currentLayer = layerNode ? layerNode->getName() : std::string();
|
std::string_view currentLayer;
|
||||||
|
if (layerNode)
|
||||||
|
currentLayer = layerNode->getName();
|
||||||
std::string newLayer = layout.get_or(LayoutKeys::layer, std::string());
|
std::string newLayer = layout.get_or(LayoutKeys::layer, std::string());
|
||||||
if (!newLayer.empty() && !MyGUI::LayerManager::getInstance().isExist(newLayer))
|
if (!newLayer.empty() && !MyGUI::LayerManager::getInstance().isExist(newLayer))
|
||||||
throw std::logic_error(std::string("Layer ") + newLayer + " doesn't exist");
|
throw std::logic_error(std::string("Layer ") + newLayer + " doesn't exist");
|
||||||
@ -278,9 +284,20 @@ namespace LuaUi
|
|||||||
WidgetExtension* parent = mRoot->getParent();
|
WidgetExtension* parent = mRoot->getParent();
|
||||||
auto children = parent->children();
|
auto children = parent->children();
|
||||||
auto it = std::find(children.begin(), children.end(), mRoot);
|
auto it = std::find(children.begin(), children.end(), mRoot);
|
||||||
mRoot = createWidget(layout(), true, 0);
|
|
||||||
assert(it != children.end());
|
assert(it != children.end());
|
||||||
*it = mRoot;
|
try
|
||||||
|
{
|
||||||
|
mRoot = createWidget(layout(), true, 0);
|
||||||
|
*it = mRoot;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
// Remove mRoot from its parent's children even if we couldn't replace it
|
||||||
|
children.erase(it);
|
||||||
|
parent->setChildren(children);
|
||||||
|
mRoot = nullptr;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
parent->setChildren(children);
|
parent->setChildren(children);
|
||||||
mRoot->updateCoord();
|
mRoot->updateCoord();
|
||||||
}
|
}
|
||||||
@ -300,6 +317,10 @@ namespace LuaUi
|
|||||||
{
|
{
|
||||||
if (mRoot != nullptr)
|
if (mRoot != nullptr)
|
||||||
{
|
{
|
||||||
|
// If someone decided to destroy an element used as another element's content, we need to detach it
|
||||||
|
// first so the parent doesn't end up holding a stale pointer
|
||||||
|
if (WidgetExtension* parent = mRoot->getParent())
|
||||||
|
parent->detachChildrenIf([&](WidgetExtension* child) { return child == mRoot; });
|
||||||
destroyRoot(mRoot);
|
destroyRoot(mRoot);
|
||||||
mRoot = nullptr;
|
mRoot = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -126,6 +126,7 @@ namespace LuaUi
|
|||||||
{
|
{
|
||||||
mParent = nullptr;
|
mParent = nullptr;
|
||||||
widget()->detachFromWidget();
|
widget()->detachFromWidget();
|
||||||
|
widget()->detachFromLayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
WidgetExtension* WidgetExtension::findDeep(std::string_view flagName)
|
WidgetExtension* WidgetExtension::findDeep(std::string_view flagName)
|
||||||
|
@ -179,7 +179,7 @@ namespace LuaUi
|
|||||||
|
|
||||||
void updateVisible();
|
void updateVisible();
|
||||||
|
|
||||||
void detachChildrenIf(auto&& predicate, std::vector<WidgetExtension*> children)
|
void detachChildrenIf(auto&& predicate, std::vector<WidgetExtension*>& children)
|
||||||
{
|
{
|
||||||
for (auto it = children.begin(); it != children.end();)
|
for (auto it = children.begin(); it != children.end();)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user