Skip to content

Commit

Permalink
GUI: Allow delayed deletion of GuiObject
Browse files Browse the repository at this point in the history
This is achieved by adding a list of GuiObject to delete to GuiManager
and doing the deletion in GuiManager::runLoop.

The main purpose of this is to avoid the deletion of ButtonWidget object
while their ButtonWidget::sendCommand function is being called. For
example the sendCommand of the Apply button of the OptionsDialog
may cause a rebuild (if the GUI language was changed) which tries to
delete the widgets inside the OptionsDialog, including the Apply button.
  • Loading branch information
criezy committed Mar 10, 2017
1 parent 6bb953e commit cc75d17
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 0 deletions.
28 changes: 28 additions & 0 deletions gui/gui-manager.cpp
Expand Up @@ -254,6 +254,23 @@ Dialog *GuiManager::getTopDialog() const {
return _dialogStack.top();
}

void GuiManager::addToTrash(GuiObject* object, Dialog* parent) {
debug(7, "Adding Gui Object %p to trash", object);
GuiObjectTrashItem t;
t.object = object;
t.parent = 0;
// If a dialog was provided, check it is in the dialog stack
if (parent != 0) {
for (int i = 0 ; i < _dialogStack.size() ; ++i) {
if (_dialogStack[i] == parent) {
t.parent = parent;
break;
}
}
}
_guiObjectTrash.push_back(t);
}

void GuiManager::runLoop() {
Dialog * const activeDialog = getTopDialog();
bool didSaveState = false;
Expand Down Expand Up @@ -341,6 +358,17 @@ void GuiManager::runLoop() {
}
}

// Delete GuiObject that have been added to the trash for a delayed deletion
Common::List<GuiObjectTrashItem>::iterator it = _guiObjectTrash.begin();
while (it != _guiObjectTrash.end()) {
if ((*it).parent == 0 || (*it).parent == activeDialog) {
debug(7, "Delayed deletion of Gui Object %p", (*it).object);
delete (*it).object;
it = _guiObjectTrash.erase(it);
} else
++it;
}

if (_lastMousePosition.time + kTooltipDelay < _system->getMillis(true)) {
Widget *wdg = activeDialog->findWidget(_lastMousePosition.x, _lastMousePosition.y);
if (wdg && wdg->hasTooltip() && !(wdg->getFlags() & WIDGET_PRESSED)) {
Expand Down
16 changes: 16 additions & 0 deletions gui/gui-manager.h
Expand Up @@ -27,6 +27,7 @@
#include "common/singleton.h"
#include "common/stack.h"
#include "common/str.h"
#include "common/list.h"

#include "gui/ThemeEngine.h"

Expand All @@ -44,6 +45,7 @@ namespace GUI {

class Dialog;
class ThemeEval;
class GuiObject;

#define g_gui (GUI::GuiManager::instance())

Expand Down Expand Up @@ -99,6 +101,13 @@ class GuiManager : public Common::Singleton<GuiManager> {
*/
bool checkScreenChange();

/**
* Tell the GuiManager to delete the given GuiObject later. If a parent
* dialog is provided and is present in the DialogStack, the object will
* only be deleted when that dialog is the top level dialog.
*/
void addToTrash(GuiObject*, Dialog* parent = 0);

bool _launched;

protected:
Expand Down Expand Up @@ -137,6 +146,13 @@ class GuiManager : public Common::Singleton<GuiManager> {
int _cursorAnimateTimer;
byte _cursor[2048];

// delayed deletion of GuiObject
struct GuiObjectTrashItem {
GuiObject* object;
Dialog* parent;
};
Common::List<GuiObjectTrashItem> _guiObjectTrash;

void initKeymap();
void pushKeymap();
void popKeymap();
Expand Down

0 comments on commit cc75d17

Please sign in to comment.