Fixed crash on reschange caused by very subtle pointer management issue; added various debug checks to make sure this doesn't happen again -.- those debug checks should have unnoticeable performance effect on a release build

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@4376 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
auria 2009-12-30 20:59:56 +00:00
parent 75149a100c
commit 47db6ffa41
7 changed files with 72 additions and 6 deletions

View File

@ -42,6 +42,8 @@ using namespace GUIEngine;
Screen::Screen(const char* file) Screen::Screen(const char* file)
{ {
m_magic_number = 0xCAFEC001;
throttleFPS = true; throttleFPS = true;
m_mouse_x = 0; m_mouse_x = 0;
@ -55,6 +57,8 @@ Screen::Screen(const char* file)
Screen::Screen() Screen::Screen()
{ {
m_magic_number = 0xCAFEC001;
m_mouse_x = 0; m_mouse_x = 0;
m_mouse_y = 0; m_mouse_y = 0;
m_loaded = false; m_loaded = false;
@ -62,8 +66,20 @@ Screen::Screen()
m_render_3d = false; m_render_3d = false;
} }
Screen::~Screen()
{
assert(m_magic_number == 0xCAFEC001);
m_magic_number = 0xDEADBEEF;
}
void Screen::forgetWhatWasLoaded() void Screen::forgetWhatWasLoaded()
{ {
assert(m_magic_number == 0xCAFEC001);
for (int n=0; n<m_widgets.size(); n++)
{
assert(m_widgets[n].m_magic_number == 0xCAFEC001);
}
m_loaded = false; m_loaded = false;
m_inited = false; m_inited = false;
m_widgets.clearAndDeleteAll(); m_widgets.clearAndDeleteAll();
@ -77,6 +93,7 @@ void Screen::forgetWhatWasLoaded()
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void Screen::loadFromFile() void Screen::loadFromFile()
{ {
assert(m_magic_number == 0xCAFEC001);
IrrXMLReader* xml = irr::io::createIrrXMLReader( (file_manager->getGUIDir() + "/" + m_filename).c_str() ); IrrXMLReader* xml = irr::io::createIrrXMLReader( (file_manager->getGUIDir() + "/" + m_filename).c_str() );
parseScreenFileDiv(xml, m_widgets); parseScreenFileDiv(xml, m_widgets);
m_loaded = true; m_loaded = true;
@ -86,6 +103,7 @@ void Screen::loadFromFile()
/* small shortcut so this method can be called without arguments */ /* small shortcut so this method can be called without arguments */
void Screen::calculateLayout() void Screen::calculateLayout()
{ {
assert(m_magic_number == 0xCAFEC001);
// build layout // build layout
calculateLayout( m_widgets ); calculateLayout( m_widgets );
} }
@ -97,6 +115,7 @@ void Screen::calculateLayout()
*/ */
void Screen::calculateLayout(ptr_vector<Widget>& widgets, Widget* parent) void Screen::calculateLayout(ptr_vector<Widget>& widgets, Widget* parent)
{ {
assert(m_magic_number == 0xCAFEC001);
const unsigned short widgets_amount = widgets.size(); const unsigned short widgets_amount = widgets.size();
// ----- read x/y/size parameters // ----- read x/y/size parameters
@ -264,6 +283,7 @@ void Screen::calculateLayout(ptr_vector<Widget>& widgets, Widget* parent)
void Screen::addWidgets() void Screen::addWidgets()
{ {
assert(m_magic_number == 0xCAFEC001);
if (!m_loaded) loadFromFile(); if (!m_loaded) loadFromFile();
addWidgetsRecursively( m_widgets ); addWidgetsRecursively( m_widgets );
@ -312,6 +332,7 @@ void Screen::addWidgetsRecursively(ptr_vector<Widget>& widgets, Widget* parent)
*/ */
void Screen::elementsWereDeleted(ptr_vector<Widget>* within_vector) void Screen::elementsWereDeleted(ptr_vector<Widget>* within_vector)
{ {
assert(m_magic_number == 0xCAFEC001);
if (within_vector == NULL) within_vector = &m_widgets; if (within_vector == NULL) within_vector = &m_widgets;
const unsigned short widgets_amount = within_vector->size(); const unsigned short widgets_amount = within_vector->size();
@ -330,11 +351,13 @@ void Screen::elementsWereDeleted(ptr_vector<Widget>* within_vector)
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void Screen::manualAddWidget(Widget* w) void Screen::manualAddWidget(Widget* w)
{ {
assert(m_magic_number == 0xCAFEC001);
m_widgets.push_back(w); m_widgets.push_back(w);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void Screen::manualRemoveWidget(Widget* w) void Screen::manualRemoveWidget(Widget* w)
{ {
assert(m_magic_number == 0xCAFEC001);
m_widgets.remove(w); m_widgets.remove(w);
} }

View File

@ -92,6 +92,8 @@ namespace GUIEngine
/** Will be called to determine if the 3D scene must be rendered when at this screen. */ /** Will be called to determine if the 3D scene must be rendered when at this screen. */
bool m_render_3d; bool m_render_3d;
int m_magic_number;
public: public:
bool throttleFPS; bool throttleFPS;
@ -107,11 +109,12 @@ namespace GUIEngine
/** Next time this menu needs to be shown, don't use cached values, re-calculate everything. /** Next time this menu needs to be shown, don't use cached values, re-calculate everything.
(useful e.g. on reschange, when sizes have changed and must be re-calculated) */ (useful e.g. on reschange, when sizes have changed and must be re-calculated) */
void forgetWhatWasLoaded(); virtual void forgetWhatWasLoaded();
Screen(); /**< creates a dummy incomplete object; only use to override behaviour in sub-class */ Screen(); /**< creates a dummy incomplete object; only use to override behaviour in sub-class */
Screen(const char* filename); Screen(const char* filename);
virtual ~Screen(){} virtual ~Screen();
bool operator ==(const char* filename) const { return m_filename == filename; } bool operator ==(const char* filename) const { return m_filename == filename; }
/** returns an object by name, or NULL if not found */ /** returns an object by name, or NULL if not found */

View File

@ -56,6 +56,8 @@ namespace GUIEngine
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
Widget::Widget(bool reserve_id) Widget::Widget(bool reserve_id)
{ {
m_magic_number = 0xCAFEC001;
x = -1; x = -1;
y = -1; y = -1;
w = -1; w = -1;
@ -88,6 +90,8 @@ Widget::Widget(bool reserve_id)
Widget::~Widget() Widget::~Widget()
{ {
assert(m_magic_number == 0xCAFEC001);
// If any player focused this widget, unset that focus // If any player focused this widget, unset that focus
for (int n=0; n<MAX_PLAYER_COUNT; n++) for (int n=0; n<MAX_PLAYER_COUNT; n++)
{ {
@ -97,10 +101,13 @@ Widget::~Widget()
} }
} }
m_magic_number = 0xDEADBEEF;
} }
void Widget::elementRemoved() void Widget::elementRemoved()
{ {
assert(m_magic_number == 0xCAFEC001);
m_element = NULL; m_element = NULL;
// If any player focused this widget, unset that focus // If any player focused this widget, unset that focus
@ -137,6 +144,7 @@ void Widget::resetIDCounters()
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void Widget::add() void Widget::add()
{ {
assert(m_magic_number == 0xCAFEC001);
if (m_reserve_id) if (m_reserve_id)
{ {
m_reserved_id = getNewID(); m_reserved_id = getNewID();
@ -151,6 +159,8 @@ void Widget::add()
*/ */
void Widget::setFocusForPlayer(const int playerID) void Widget::setFocusForPlayer(const int playerID)
{ {
assert(m_magic_number == 0xCAFEC001);
// Unset focus flag on previous widget that had focus // Unset focus flag on previous widget that had focus
if (GUIEngine::getFocusForPlayer(playerID) != NULL) if (GUIEngine::getFocusForPlayer(playerID) != NULL)
{ {
@ -167,6 +177,8 @@ void Widget::setFocusForPlayer(const int playerID)
void Widget::unsetFocusForPlayer(const int playerID) void Widget::unsetFocusForPlayer(const int playerID)
{ {
assert(m_magic_number == 0xCAFEC001);
if (m_player_focus[playerID]) this->unfocused(playerID); if (m_player_focus[playerID]) this->unfocused(playerID);
m_player_focus[playerID] = false; m_player_focus[playerID] = false;
} }
@ -176,6 +188,8 @@ void Widget::unsetFocusForPlayer(const int playerID)
*/ */
bool Widget::isFocusedForPlayer(const int playerID) bool Widget::isFocusedForPlayer(const int playerID)
{ {
assert(m_magic_number == 0xCAFEC001);
return m_player_focus[playerID]; return m_player_focus[playerID];
} }
@ -189,7 +203,7 @@ bool Widget::isFocusedForPlayer(const int playerID)
* Returns false if couldn't convert to either * Returns false if couldn't convert to either
*/ */
bool Widget::convertToCoord(std::string& x, int* absolute /* out */, int* percentage /* out */) bool Widget::convertToCoord(std::string& x, int* absolute /* out */, int* percentage /* out */)
{ {
bool is_number; bool is_number;
int i; int i;
std::istringstream myStream(x); std::istringstream myStream(x);
@ -211,6 +225,8 @@ bool Widget::convertToCoord(std::string& x, int* absolute /* out */, int* percen
void Widget::move(const int x, const int y, const int w, const int h) void Widget::move(const int x, const int y, const int w, const int h)
{ {
assert(m_magic_number == 0xCAFEC001);
this->x = x; this->x = x;
this->y = y; this->y = y;
this->w = w; this->w = w;
@ -226,6 +242,8 @@ void Widget::move(const int x, const int y, const int w, const int h)
*/ */
void Widget::readCoords(Widget* parent) void Widget::readCoords(Widget* parent)
{ {
assert(m_magic_number == 0xCAFEC001);
/* determine widget position and size if not already done by sizers */ /* determine widget position and size if not already done by sizers */
std::string x = m_properties[PROP_X]; std::string x = m_properties[PROP_X];
std::string y = m_properties[PROP_Y]; std::string y = m_properties[PROP_Y];
@ -360,6 +378,7 @@ void Widget::readCoords(Widget* parent)
void Widget::setParent(IGUIElement* parent) void Widget::setParent(IGUIElement* parent)
{ {
assert(m_magic_number == 0xCAFEC001);
m_parent = parent; m_parent = parent;
} }

View File

@ -93,6 +93,7 @@ namespace GUIEngine
class Widget : public SkinWidgetContainer class Widget : public SkinWidgetContainer
{ {
protected: protected:
int m_magic_number;
friend class EventHandler; friend class EventHandler;
friend class RibbonWidget; friend class RibbonWidget;

View File

@ -684,13 +684,25 @@ KartSelectionScreen::KartSelectionScreen() : Screen("karts.stkgui")
{ {
g_dispatcher = new FocusDispatcher(this); g_dispatcher = new FocusDispatcher(this);
} }
// -----------------------------------------------------------------------------
void KartSelectionScreen::forgetWhatWasLoaded()
{
Screen::forgetWhatWasLoaded();
// this pointer is no more valid
g_dispatcher = NULL;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Return true if event was handled successfully // Return true if event was handled successfully
bool KartSelectionScreen::playerJoin(InputDevice* device, bool firstPlayer) bool KartSelectionScreen::playerJoin(InputDevice* device, bool firstPlayer)
{ {
std::cout << "playerJoin() ==========\n"; std::cout << "playerJoin() ==========\n";
if (g_dispatcher == NULL)
{
g_dispatcher = new FocusDispatcher(this);
}
DynamicRibbonWidget* w = this->getWidget<DynamicRibbonWidget>("karts"); DynamicRibbonWidget* w = this->getWidget<DynamicRibbonWidget>("karts");
if (w == NULL) if (w == NULL)
{ {
@ -717,7 +729,7 @@ bool KartSelectionScreen::playerJoin(InputDevice* device, bool firstPlayer)
{ {
g_dispatcher->setRootID(kartsArea.m_reserved_id); g_dispatcher->setRootID(kartsArea.m_reserved_id);
g_dispatcher->add(); g_dispatcher->add();
m_widgets.push_back(g_dispatcher); if (!m_widgets.contains(g_dispatcher)) m_widgets.push_back(g_dispatcher);
// We keep the ID of the "root" widget, see comment at top // We keep the ID of the "root" widget, see comment at top
g_root_id = kartsArea.m_reserved_id; g_root_id = kartsArea.m_reserved_id;

View File

@ -70,4 +70,7 @@ public:
/** Standard 'Screen' callback every frame */ /** Standard 'Screen' callback every frame */
void onUpdate(float dt, irr::video::IVideoDriver*); void onUpdate(float dt, irr::video::IVideoDriver*);
/** overload */
virtual void forgetWhatWasLoaded();
}; };

View File

@ -129,10 +129,15 @@ bool contains( TYPE* instance ) const
void clearAndDeleteAll() void clearAndDeleteAll()
{ {
for(unsigned int n=0; n<contentsVector.size(); n++) for (unsigned int n=0; n<contentsVector.size(); n++)
{ {
TYPE * pointer = contentsVector[n]; TYPE * pointer = contentsVector[n];
delete pointer; delete pointer;
contentsVector[n] = (TYPE*)0xDEADBEEF;
// When deleting, it's important that the same pointer cannot be
// twice in the vector, resulting in a double delete
assert( !contains(pointer) );
} }
contentsVector.clear(); contentsVector.clear();
} }