[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