[Date Prev][Date Next][Thread Prev][Thread Next][Thread Index]

[XaraXtreme-commits] Commit Complete



Commit by  : alex
Repository : xara
Revision   : 1651
Date       : Wed Aug  2 20:46:41 BST 2006

Changed paths:
   M /Trunk/XaraLX/wxOil/camelot.cpp
   M /Trunk/XaraLX/wxOil/camelot.h

Do not crash if hotkeys delete windows


Diff:
Index: Trunk/XaraLX/wxOil/camelot.h
===================================================================
--- Trunk/XaraLX/wxOil/camelot.h	(revision 1650)
+++ Trunk/XaraLX/wxOil/camelot.h	(revision 1651)
@@ -223,4 +223,141 @@
 
 #endif
 
+
+
+/*******************************************************************************************
+
+>	class wxWindowDeletionWatcher : public wxObject
+
+	Author:		Alex_Bligh <alex@xxxxxxxxxxx>
+	Created:	02/07/2006
+	Purpose:	A derived event to watch for the deletion of windows
+	Notes:		In the OIL
+	See Also:	
+
+********************************************************************************************/
+
+class wxWindowDeletionWatcher;
+WX_DECLARE_HASH_MAP( wxWindow *, wxWindowDeletionWatcher *, wxPointerHash, wxPointerEqual, WindowToWindowDeletionWatcher );
+
+class wxWindowDeletionWatcher : public wxObject
+{
+public:
+	wxWindowDeletionWatcher(wxWindow * pWatchedWindow = NULL) : m_HasBeenDeleted(FALSE), m_pWatchedWindow(pWatchedWindow), m_pNext(NULL), m_pPrev(NULL)
+	{
+		WindowToWindowDeletionWatcher::iterator i = GetHashEntry(m_pWatchedWindow);
+
+		// If there is no list, create a new hash entry, and we are done
+		if (i == s_UndeletedWindowHash->end() || !(i->second))
+		{
+			ERROR3IF(i != s_UndeletedWindowHash->end(), "wxWindowDeletionWatcher list non-empty but has NULL pointer");
+			(*s_UndeletedWindowHash)[m_pWatchedWindow]=this;
+		}
+		else
+		{
+			// we are going to stick it on the front of the list
+			m_pNext = i->second; // save the current list (may be NULL).
+			i->second = this; // stick us on the list
+
+			m_pPrev = NULL;
+			m_pNext->m_pPrev=this;
+		}
+		if (m_pWatchedWindow->IsBeingDeleted())
+			RegisterWindowDeletion(m_pWatchedWindow);
+	}
+
+	~wxWindowDeletionWatcher()
+	{
+		RemoveFromList();
+	}
+
+	void RemoveFromList()
+	{
+		if (m_HasBeenDeleted)
+		{
+			ERROR3IF(m_pNext || m_pPrev, "a deleted window appears to still be on the wxWindowDeletionWatcher list");
+			return; // it's not on a list anyway
+		}
+
+		BOOL Empty = TRUE;
+		if (m_pNext)
+		{
+			ERROR3IF(m_pNext->m_pPrev != this, "bad wxWindowDeletionWatcher next pointer");
+			m_pNext->m_pPrev = m_pPrev;
+			Empty = FALSE;
+		}
+		if (m_pPrev)
+		{
+			ERROR3IF(m_pPrev->m_pNext != this, "bad wxWindowDeletionWatcher prev pointer");
+			m_pPrev->m_pNext = m_pNext;
+			Empty = FALSE;
+		}
+		m_pPrev = m_pNext = NULL; // disconnect
+
+		if (Empty)
+		{
+			// Delete the hash table entry
+			WindowToWindowDeletionWatcher::iterator i = GetHashEntry(m_pWatchedWindow);
+			if (i->second != this)
+			{
+				ERROR3("wxWindowWatcher list appeared to be newly emptied but I wasn't the first item on it");
+			}
+			if (i != s_UndeletedWindowHash->end())
+				s_UndeletedWindowHash->erase(i);
+			else
+			{
+				ERROR3("Can't find wxWindowDeletionWatcher list");
+			}
+		}
+	}
+
+	BOOL HasBeenDeleted() const {return m_HasBeenDeleted;}
+
+	static void RegisterWindowDeletion(wxWindow * pWindow)
+	{
+		WindowToWindowDeletionWatcher::iterator i = GetHashEntry(pWindow);
+		if (i != s_UndeletedWindowHash->end())
+		{
+			// OK, there's an entry there
+			wxWindowDeletionWatcher * pWDW = i->second; // as "i" may become invalid
+			ERROR3IF(!pWDW, "Empty list in wxWindowDeletionWatcher::RegisterWindowDeletion");
+			while (pWDW)
+			{
+				ERROR3IF(pWDW->m_pWatchedWindow != pWindow, "Window on the wrong list in wxWindowDeletionWatcher::RegisterWindowDeletion");
+				wxWindowDeletionWatcher * next = pWDW->m_pNext; // as removing from the list erases the next pointer
+				pWDW->m_HasBeenDeleted = TRUE;
+				pWDW->RemoveFromList(); // note we don't delete the WDW object
+				pWDW = next;			
+			}
+		}
+	}
+
+	static void DeInit()
+	{
+		if (s_UndeletedWindowHash)
+		{
+			ERROR3IF(!s_UndeletedWindowHash->empty(), "wxWindowDeletionWatcher::DeInit() found hash of watched windows was non-empty; someone leaked a wxWindowDeletionWatcher");
+			s_UndeletedWindowHash->clear();
+			delete s_UndeletedWindowHash;
+			s_UndeletedWindowHash = NULL;
+		}
+	}
+
+private:
+	static WindowToWindowDeletionWatcher::iterator GetHashEntry(wxWindow * pWindow) {EnsureHash(); return s_UndeletedWindowHash->find(pWindow);}
+
+	static BOOL EnsureHash() {if (!s_UndeletedWindowHash) s_UndeletedWindowHash = new WindowToWindowDeletionWatcher; return s_UndeletedWindowHash!=NULL;}
+
+	BOOL m_HasBeenDeleted;
+	wxWindow * m_pWatchedWindow;
+
+	// whilst the windows remain undeleted, they sit on this list
+	wxWindowDeletionWatcher * m_pNext;
+	wxWindowDeletionWatcher * m_pPrev;
+
+	static WindowToWindowDeletionWatcher * s_UndeletedWindowHash;
+
+	DECLARE_DYNAMIC_CLASS(wxWindowDeletionWatcher);
+};
+
 #endif //_CAMELOT_H_
Index: Trunk/XaraLX/wxOil/camelot.cpp
===================================================================
--- Trunk/XaraLX/wxOil/camelot.cpp	(revision 1650)
+++ Trunk/XaraLX/wxOil/camelot.cpp	(revision 1651)
@@ -153,6 +153,8 @@
 //#endif
 
 BOOL CCamApp::InInitOrDeInit = TRUE;
+IMPLEMENT_DYNAMIC_CLASS( wxWindowDeletionWatcher, wxObject);
+WindowToWindowDeletionWatcher * wxWindowDeletionWatcher::s_UndeletedWindowHash = NULL;
 
 /********************************************************************************************
 
@@ -260,13 +262,20 @@
 {
 	static /*TYPENOTE: Correct*/ long	lLastTimeStamp = 0;
 
+	wxObject* pEventObject = event.GetEventObject();
+
+	if (( event.GetEventType() == wxEVT_DESTROY ) && pEventObject->IsKindOf(CLASSINFO(wxWindow)))
+	{
+		// Register window destruction
+		wxWindowDeletionWatcher::RegisterWindowDeletion((wxWindow *)pEventObject);
+	}
+
 	if (PrintMonitor::IsPrintingNow())
 	{
 		// Disable processing of paint messages for various controls which may use GDraw or GBrush to paint, as this
 		// appears to upset printing
 		if (event.IsKindOf(CLASSINFO(wxPaintEvent)))
 		{
-			wxObject* pEventObject = event.GetEventObject();
 			if (!pEventObject->IsKindOf(CLASSINFO(wxCamArtControl)))
 			{	
 				// TRACEUSER("amb", _T("CCamApp::FilterEvent caught paint for %s"), pEventObject->GetClassInfo()->GetClassName());
@@ -280,7 +289,6 @@
 #if 0 && defined(_DEBUG)
 	if ( event.GetEventType() == wxEVT_SET_FOCUS )
 	{
-		wxObject* pEventObject = event.GetEventObject();
 		TRACEUSER("amb", _T("CCamApp::FilterEvent focus to %s"), pEventObject->GetClassInfo()->GetClassName());
 		if (pEventObject->IsKindOf(CLASSINFO(CRenderWnd)))
 		{
@@ -290,9 +298,10 @@
 #endif
 
 	if (( event.GetEventType() == wxEVT_CREATE )
-		&& (event.GetEventObject()->IsKindOf(CLASSINFO(wxTopLevelWindow)))
-		&& !(event.GetEventObject()->IsKindOf(CLASSINFO(wxAdvSplashScreen))) // Don't trigger this on the creation of the splash screen itself
-		&& !(event.GetEventObject()->IsKindOf(CLASSINFO(wxSplashScreen)))
+		&& pEventObject
+		&& (pEventObject->IsKindOf(CLASSINFO(wxTopLevelWindow)))
+		&& !(pEventObject->IsKindOf(CLASSINFO(wxAdvSplashScreen))) // Don't trigger this on the creation of the splash screen itself
+		&& !(pEventObject->IsKindOf(CLASSINFO(wxSplashScreen)))
 		)
 	{
 		// a top level window is about to be created. End the splash screen if it is up as it may obscure it
@@ -302,7 +311,6 @@
 #if defined(_DEBUG)
 	if( event.GetEventType() == wxEVT_CHAR )
 	{
-		wxObject* pEventObject = event.GetEventObject();
 		if (pEventObject)
 		{
 			TRACEUSER( "jlh92", _T("KeyEvent 4 %s CH
"),
@@ -320,7 +328,6 @@
 			return -1;
 		lLastTimeStamp = event.GetTimestamp();
 
-		wxObject* pEventObject = event.GetEventObject();
 		TRACEUSER( "jlh92", _T("KeyEvent 4 %s %s
"),
 			((wxWindow*)pEventObject)->GetClassInfo()->GetClassName(),
 			event.GetEventType() == wxEVT_KEY_DOWN ? _T("KD") : _T("KU") );
@@ -389,9 +396,29 @@
 		TRACEUSER("amb", _T("CCamApp::FilterEvent handle"));
 		TRACEUSER( "jlh92", _T("Handled!
") );
 
+		// Do our best to see if the object is deleted.
+		wxWindowDeletionWatcher * wd = NULL;
+		if (pEventObject->IsKindOf(CLASSINFO(wxWindow)))
+		{
+			wd = new wxWindowDeletionWatcher((wxWindow*)pEventObject);
+			if (!wd)
+				return -1;
+		}
+
 		// Process keyboard messages (and mark event as handled)
 		if( HandleKeyPress( (wxKeyEvent&)event ) )
-			return -1;
+		{
+			BOOL deleted = wd && wd->HasBeenDeleted();
+			if (wd)
+				delete wd;
+			if (deleted)
+				return 1; // event handled. Do NOT anything else here as the object may by now
+						// have been deleted (e.g. FileClose hotkey).
+			else
+				return -1;
+		}
+		if (wd)
+			delete wd;
 	}
 	
 	return -1;
@@ -1152,6 +1179,9 @@
 	DeInitUserHelp();
 #endif
 
+	// zap this after we know all windows have gone
+	wxWindowDeletionWatcher::DeInit();
+
 	::wxHandleFatalExceptions(FALSE);
 	return wxApp::OnExit();
 }


Xara