fix wxWindow::PushEventHandler and related wxWindow functions for the stack management; currently they don't work well when passing event handlers which are part of an event handler chain (see wx-dev thread 'wxWindow event handler stack'); implement wxEvtHandler Unlink() and IsUnlinked() functions and document them; revise docs of all involved functions of both wxEvtHandler and wxWindow, adding images for better explanations

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58291 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Francesco Montorsi
2009-01-22 11:53:09 +00:00
parent 47009083ce
commit 7f853dd046
16 changed files with 303 additions and 119 deletions

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -184,7 +184,7 @@ in the previous section. However the similarities end here and both the syntax
and the possibilities of handling events in this way are rather different. and the possibilities of handling events in this way are rather different.
Let us start by looking at the syntax: the first obvious difference is that you Let us start by looking at the syntax: the first obvious difference is that you
need not use @c DECLARE_EVENT_TABLE() nor @c BEGIN_EVENT_TABLE and the need not use DECLARE_EVENT_TABLE() nor BEGIN_EVENT_TABLE() and the
associated macros. Instead, in any place in your code, but usually in associated macros. Instead, in any place in your code, but usually in
the code of the class defining the handler itself (and definitely not in the the code of the class defining the handler itself (and definitely not in the
global scope as with the event tables), call its Connect() method like this: global scope as with the event tables), call its Connect() method like this:
@@ -331,10 +331,20 @@ doesn't count as having handled the event and the search continues):
<li value="5"> <li value="5">
The event is passed to the next event handler, if any, in the event handler The event is passed to the next event handler, if any, in the event handler
chain, i.e., the steps (1) to (4) are done for it. This chain can be formed chain, i.e., the steps (1) to (4) are done for it. This chain can be formed
using wxEvtHandler::SetNextHandler() or wxWindow::PushEventHandler() but using wxEvtHandler::SetNextHandler():
usually there is no next event handler and chaining event handlers using @image html overview_eventhandling_chain.png
these functions is much less useful now that Connect() exists so this step (referring to the image, if @c A->ProcessEvent is called and it doesn't handle
will almost never do anything. the event, @c B->ProcessEvent will be called and so on...).
In the case of wxWindow you can build a stack (implemented using wxEvtHandler
double-linked list) using wxWindow::PushEventHandler():
@image html overview_eventhandling_winstack.png
(referring to the image, if @c W->ProcessEvent is called, it immediately calls
@c A->ProcessEvent; if nor @c A nor @c B handle the event, then the wxWindow
itself is used - i.e. the dynamically connected event handlers and static
event table entries of wxWindow are looked as the last possibility, after
all pushed event handlers were tested).
Note however that usually there are no wxEvtHandler chains nor wxWindows stacks
so this step will usually do anything.
</li> </li>
<li value="6"> <li value="6">
@@ -349,7 +359,7 @@ doesn't count as having handled the event and the search continues):
<li value="7"> <li value="7">
Finally, i.e., if the event is still not processed, the wxApp object itself Finally, i.e., if the event is still not processed, the wxApp object itself
gets a last chance to process it. (which derives from wxEvtHandler) gets a last chance to process it.
</li> </li>
</ol> </ol>

View File

@@ -283,7 +283,7 @@ HR {
} }
.memproto, .memdoc { .memproto, .memdoc {
border: 1px solid #84b0c7; border: 1px solid #84b0c7;
} }
.memproto { .memproto {
@@ -400,6 +400,10 @@ H2 > A.anchor {
color: black; color: black;
} }
IMG {
margin: 20px;
}
IMG.logo { IMG.logo {
float: right; float: right;
margin: 20px; margin: 20px;

View File

@@ -2668,14 +2668,27 @@ public:
wxEvtHandler(); wxEvtHandler();
virtual ~wxEvtHandler(); virtual ~wxEvtHandler();
// Event handler chain
// -------------------
wxEvtHandler *GetNextHandler() const { return m_nextHandler; } wxEvtHandler *GetNextHandler() const { return m_nextHandler; }
wxEvtHandler *GetPreviousHandler() const { return m_previousHandler; } wxEvtHandler *GetPreviousHandler() const { return m_previousHandler; }
void SetNextHandler(wxEvtHandler *handler) { m_nextHandler = handler; } virtual void SetNextHandler(wxEvtHandler *handler) { m_nextHandler = handler; }
void SetPreviousHandler(wxEvtHandler *handler) { m_previousHandler = handler; } virtual void SetPreviousHandler(wxEvtHandler *handler) { m_previousHandler = handler; }
void SetEvtHandlerEnabled(bool enabled) { m_enabled = enabled; } void SetEvtHandlerEnabled(bool enabled) { m_enabled = enabled; }
bool GetEvtHandlerEnabled() const { return m_enabled; } bool GetEvtHandlerEnabled() const { return m_enabled; }
void Unlink();
bool IsUnlinked() const;
// Event queuing and processing
// ----------------------------
// Process an event right now: this can only be called from the main // Process an event right now: this can only be called from the main
// thread, use QueueEvent() for scheduling the events for // thread, use QueueEvent() for scheduling the events for
// processing from other threads. // processing from other threads.
@@ -2686,6 +2699,7 @@ public:
// when called from C code (e.g. in GTK+ callback) when the exception // when called from C code (e.g. in GTK+ callback) when the exception
// wouldn't correctly propagate to wxEventLoop. // wouldn't correctly propagate to wxEventLoop.
bool SafelyProcessEvent(wxEvent& event); bool SafelyProcessEvent(wxEvent& event);
// NOTE: uses ProcessEvent()
// Schedule the given event to be processed later. It takes ownership of // Schedule the given event to be processed later. It takes ownership of
// the event pointer, i.e. it will be deleted later. This is safe to call // the event pointer, i.e. it will be deleted later. This is safe to call
@@ -2708,11 +2722,17 @@ public:
} }
void ProcessPendingEvents(); void ProcessPendingEvents();
// NOTE: uses ProcessEvent()
#if wxUSE_THREADS #if wxUSE_THREADS
bool ProcessThreadEvent(const wxEvent& event); bool ProcessThreadEvent(const wxEvent& event);
// NOTE: uses AddPendingEvent()
#endif #endif
// Connecting and disconnecting
// ----------------------------
// Dynamic association of a member function handler with the event handler, // Dynamic association of a member function handler with the event handler,
// winid and event type // winid and event type
void Connect(int winid, void Connect(int winid,

View File

@@ -792,7 +792,7 @@ public:
// replace the event handler (allows to completely subclass the // replace the event handler (allows to completely subclass the
// window) // window)
void SetEventHandler( wxEvtHandler *handler ) { m_eventHandler = handler; } void SetEventHandler( wxEvtHandler *handler );
// push/pop event handler: allows to chain a custom event handler to // push/pop event handler: allows to chain a custom event handler to
// alreasy existing ones // alreasy existing ones
@@ -806,13 +806,17 @@ public:
// be there) // be there)
bool RemoveEventHandler(wxEvtHandler *handler); bool RemoveEventHandler(wxEvtHandler *handler);
// Process an event by calling GetEventHandler()->ProcessEvent() and // Process an event by calling GetEventHandler()->ProcessEvent() and
// handling any exceptions thrown by event handlers. It's mostly useful // handling any exceptions thrown by event handlers. It's mostly useful
// when processing wx events when called from C code (e.g. in GTK+ // when processing wx events when called from C code (e.g. in GTK+
// callback) when the exception wouldn't correctly propagate to // callback) when the exception wouldn't correctly propagate to
// wxEventLoop. // wxEventLoop.
bool HandleWindowEvent(wxEvent& event) const; bool HandleWindowEvent(wxEvent& event) const;
// disable wxEvtHandler double-linked list mechanism:
virtual void SetNextHandler(wxEvtHandler *handler);
virtual void SetPreviousHandler(wxEvtHandler *handler);
// validators // validators
// ---------- // ----------

View File

@@ -258,7 +258,7 @@ public:
wxWindow is (and therefore all window classes are) derived from this class. wxWindow is (and therefore all window classes are) derived from this class.
When events are received, wxEvtHandler invokes the method listed in the When events are received, wxEvtHandler invokes the method listed in the
event table using itself as the object. When using multiple inheritance event table using itself as the object. When using multiple inheritance
<b>it is imperative that the wxEvtHandler(-derived) class is the first <b>it is imperative that the wxEvtHandler(-derived) class is the first
class inherited</b> such that the @c this pointer for the overall object class inherited</b> such that the @c this pointer for the overall object
will be identical to the @c this pointer of the wxEvtHandler portion. will be identical to the @c this pointer of the wxEvtHandler portion.
@@ -279,8 +279,8 @@ public:
/** /**
Destructor. Destructor.
If the handler is part of a chain, the destructor will unlink itself and If the handler is part of a chain, the destructor will unlink itself
restore the previous and next handlers so that they point to each other. (see Unlink()).
*/ */
virtual ~wxEvtHandler(); virtual ~wxEvtHandler();
@@ -382,17 +382,23 @@ public:
The normal order of event table searching is as follows: The normal order of event table searching is as follows:
-# If the object is disabled (via a call to wxEvtHandler::SetEvtHandlerEnabled) -# If the object is disabled (via a call to wxEvtHandler::SetEvtHandlerEnabled)
the function skips to step (6). the function skips to step (6).
-# If the object is a wxWindow, ProcessEvent() is recursively called on the -# If the object is a wxWindow, ProcessEvent() is recursively called on the
window's wxValidator. If this returns @true, the function exits. window's wxValidator. If this returns @true, the function exits.
-# SearchEventTable() is called for this event handler. If this fails, the base -# SearchEventTable() is called for this event handler. If this fails, the base
class table is tried, and so on until no more tables exist or an appropriate class table is tried, and so on until no more tables exist or an appropriate
function was found, in which case the function exits. function was found, in which case the function exits.
-# The search is applied down the entire chain of event handlers (usually the -# The search is applied down the entire chain of event handlers (usually the
chain has a length of one). If this succeeds, the function exits. chain has a length of one). This chain can be formed using wxEvtHandler::SetNextHandler():
@image html overview_eventhandling_chain.png
(referring to the image, if @c A->ProcessEvent is called and it doesn't handle
the event, @c B->ProcessEvent will be called and so on...).
Note that in the case of wxWindow you can build a stack of event handlers
(see wxWindow::PushEventHandler() for more info).
If any of the handlers of the chain return @true, the function exits.
-# If the object is a wxWindow and the event is a wxCommandEvent, ProcessEvent() -# If the object is a wxWindow and the event is a wxCommandEvent, ProcessEvent()
is recursively applied to the parent window's event handler. is recursively applied to the parent window's event handler.
If this returns true, the function exits. If this returns @true, the function exits.
-# Finally, ProcessEvent() is called on the wxApp object. -# Finally, ProcessEvent() is called on the wxApp object.
@param event @param event
@@ -620,7 +626,10 @@ public:
/** /**
@name Event handler chain @name Event handler chaining
wxEvtHandler can be arranged in a double-linked list of handlers
which is automatically iterated by ProcessEvent() if needed.
*/ */
//@{ //@{
@@ -664,21 +673,60 @@ public:
/** /**
Sets the pointer to the next handler. Sets the pointer to the next handler.
@param handler @remarks
Event handler to be set as the next handler. See ProcessEvent() for more info about how the chains of event handlers
are internally used.
Also remember that wxEvtHandler uses double-linked lists and thus if you
use this function, you should also call SetPreviousHandler() on the
argument passed to this function:
@code
handlerA->SetNextHandler(handlerB);
handlerB->SetPreviousHandler(handlerA);
@endcode
@see GetNextHandler(), SetPreviousHandler(), GetPreviousHandler(), @param handler
wxWindow::PushEventHandler, wxWindow::PopEventHandler The event handler to be set as the next handler.
Cannot be @NULL.
@see @ref overview_eventhandling_processing
*/ */
void SetNextHandler(wxEvtHandler* handler); virtual void SetNextHandler(wxEvtHandler* handler);
/** /**
Sets the pointer to the previous handler. Sets the pointer to the previous handler.
All remarks about SetNextHandler() apply to this function as well.
@param handler @param handler
Event handler to be set as the previous handler. The event handler to be set as the previous handler.
Cannot be @NULL.
@see @ref overview_eventhandling_processing
*/ */
void SetPreviousHandler(wxEvtHandler* handler); virtual void SetPreviousHandler(wxEvtHandler* handler);
/**
Unlinks this event handler from the chain it's part of (if any);
then links the "previous" event handler to the "next" one
(so that the chain won't be interrupted).
E.g. if before calling Unlink() you have the following chain:
@image html evthandler_unlink_before.png
then after calling @c B->Unlink() you'll have:
@image html evthandler_unlink_after.png
@since 2.9.0
*/
void Unlink();
/**
Returns @true if the next and the previous handler pointers of this
event handler instance are @NULL.
@since 2.9.0
@see SetPreviousHandler(), SetNextHandler()
*/
bool IsUnlinked() const;
//@} //@}
}; };

View File

@@ -1656,6 +1656,9 @@ public:
/** /**
@name Event-handling functions @name Event-handling functions
wxWindow allows you to build a (sort of) stack of event handlers which
can be used to override the window's own event handling.
*/ */
//@{ //@{
@@ -1669,9 +1672,8 @@ public:
wxEvtHandler* GetEventHandler() const; wxEvtHandler* GetEventHandler() const;
/** /**
This function will generate the appropriate call to This function will generate the appropriate call to Navigate() if the key
Navigate() if the key event is one normally used for event is one normally used for keyboard navigation and return @true in this case.
keyboard navigation and return @true in this case.
@return Returns @true if the key pressed was for navigation and was @return Returns @true if the key pressed was for navigation and was
handled, @false otherwise. handled, @false otherwise.
@@ -1691,44 +1693,62 @@ public:
/** /**
Removes and returns the top-most event handler on the event handler stack. Removes and returns the top-most event handler on the event handler stack.
@param deleteHandler E.g. in the case of:
If this is @true, the handler will be deleted after it is removed. @image html overview_eventhandling_winstack.png
The default value is @false. when calling @c W->PopEventHandler(), the event handler @c A will be
removed and @c B will be the first handler of the stack.
@see SetEventHandler(), GetEventHandler(), Note that it's an error to call this function when no event handlers
PushEventHandler(), wxEvtHandler::ProcessEvent, wxEvtHandler were pushed on this window (i.e. when the window itself is its only
event handler).
@param deleteHandler
If this is @true, the handler will be deleted after it is removed
(and the returned value will be @NULL).
@see @ref overview_eventhandling_processing
*/ */
wxEvtHandler* PopEventHandler(bool deleteHandler = false); wxEvtHandler* PopEventHandler(bool deleteHandler = false);
/** /**
Pushes this event handler onto the event stack for the window. Pushes this event handler onto the event stack for the window.
An event handler is an object that is capable of processing the events sent
to a window. By default, the window is its own event handler, but an application
may wish to substitute another, for example to allow central implementation
of event-handling for a variety of different window classes.
wxWindow::PushEventHandler allows an application to set up a @e stack
of event handlers, where an event not handled by one event handler is
handed to the next one in the chain.
E.g. if you have two event handlers @c A and @c B and a wxWindow instance
@c W and you call:
@code
W->PushEventHandler(A);
W->PushEventHandler(B);
@endcode
you will end up with the following situation:
@image html overview_eventhandling_winstack.png
Note that you can use wxWindow::PopEventHandler to remove the event handler.
@param handler @param handler
Specifies the handler to be pushed. Specifies the handler to be pushed.
It must not be part of a wxEvtHandler chain; an assert will fail
if it's not unlinked (see wxEvtHandler::IsUnlinked).
@remarks An event handler is an object that is capable of processing the @see @ref overview_eventhandling_processing
events sent to a window. By default, the window is its
own event handler, but an application may wish to
substitute another, for example to allow central
implementation of event-handling for a variety of
different window classes.
wxWindow::PushEventHandler allows an application to set up a
chain of event handlers, where an event not handled by one event
handler is handed to the next one in the chain.
Use wxWindow::PopEventHandler to remove the event handler.
@see SetEventHandler(), GetEventHandler(),
PopEventHandler(), wxEvtHandler::ProcessEvent, wxEvtHandler
*/ */
void PushEventHandler(wxEvtHandler* handler); void PushEventHandler(wxEvtHandler* handler);
/** /**
Find the given @a handler in the windows event handler chain and remove Find the given @a handler in the windows event handler stack and unlinks
(but not delete) it from it. (but not delete) it. See wxEvtHandler::Unlink() for more info.
@param handler @param handler
The event handler to remove, must be non-@NULL and The event handler to remove, must be non-@NULL and
must be present in this windows event handlers chain must be present in this windows event handlers stack.
@return Returns @true if it was found and @false otherwise (this also @return Returns @true if it was found and @false otherwise (this also
results in an assert failure so this function should results in an assert failure so this function should
@@ -1741,27 +1761,41 @@ public:
/** /**
Sets the event handler for this window. Sets the event handler for this window.
Note that if you use this function you may want to use as the "next" handler
of @a handler the window itself; in this way when @a handler doesn't process
an event, the window itself will have a chance to do it.
@param handler @param handler
Specifies the handler to be set. Specifies the handler to be set. Cannot be @NULL.
@remarks An event handler is an object that is capable of processing the @see @ref overview_eventhandling_processing
events sent to a window. By default, the window is its
own event handler, but an application may wish to
substitute another, for example to allow central
implementation of event-handling for a variety of
different window classes.
It is usually better to use wxWindow::PushEventHandler since
this sets up a chain of event handlers, where an event not
handled by one event handler is handed to the next one in the chain.
@see GetEventHandler(), PushEventHandler(),
PopEventHandler(), wxEvtHandler::ProcessEvent, wxEvtHandler
*/ */
void SetEventHandler(wxEvtHandler* handler); void SetEventHandler(wxEvtHandler* handler);
/**
wxWindows cannot be used to form event handler chains; this function
thus will assert when called.
Note that instead you can use PushEventHandler() or SetEventHandler() to
implement a stack of event handlers to override wxWindow's own
event handling mechanism.
*/
virtual void SetNextHandler(wxEvtHandler* handler);
/**
wxWindows cannot be used to form event handler chains; this function
thus will assert when called.
Note that instead you can use PushEventHandler() or SetEventHandler() to
implement a stack of event handlers to override wxWindow's own
event handling mechanism.
*/
virtual void SetPreviousHandler(wxEvtHandler* handler);
//@} //@}
/** /**
@name Window styles functions @name Window styles functions
*/ */

View File

@@ -1036,12 +1036,7 @@ wxEvtHandler::wxEvtHandler()
wxEvtHandler::~wxEvtHandler() wxEvtHandler::~wxEvtHandler()
{ {
// Takes itself out of the list of handlers Unlink();
if (m_previousHandler)
m_previousHandler->m_nextHandler = m_nextHandler;
if (m_nextHandler)
m_nextHandler->m_previousHandler = m_previousHandler;
if (m_dynamicEvents) if (m_dynamicEvents)
{ {
@@ -1103,6 +1098,26 @@ wxEvtHandler::~wxEvtHandler()
delete m_clientObject; delete m_clientObject;
} }
void wxEvtHandler::Unlink()
{
// this event handler must take itself out of the chain of handlers:
if (m_previousHandler)
m_previousHandler->SetNextHandler(m_nextHandler);
if (m_nextHandler)
m_nextHandler->SetPreviousHandler(m_previousHandler);
m_nextHandler = NULL;
m_previousHandler = NULL;
}
bool wxEvtHandler::IsUnlinked() const
{
return m_previousHandler == NULL &&
m_nextHandler == NULL;
}
#if wxUSE_THREADS #if wxUSE_THREADS
bool wxEvtHandler::ProcessThreadEvent(const wxEvent& event) bool wxEvtHandler::ProcessThreadEvent(const wxEvent& event)

View File

@@ -1096,73 +1096,121 @@ bool wxWindowBase::Reparent(wxWindowBase *newParent)
// event handler stuff // event handler stuff
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void wxWindowBase::PushEventHandler(wxEvtHandler *handler) void wxWindowBase::SetEventHandler(wxEvtHandler *handler)
{ {
wxCHECK_RET(handler != NULL, "SetEventHandler(NULL) called");
m_eventHandler = handler;
}
void wxWindowBase::SetNextHandler(wxEvtHandler *WXUNUSED(handler))
{
// disable wxEvtHandler chain mechanism for wxWindows:
// wxWindow uses its own stack mechanism which doesn't mix well with wxEvtHandler's one
wxFAIL_MSG("wxWindow cannot be part of a wxEvtHandler chain");
}
void wxWindowBase::SetPreviousHandler(wxEvtHandler *WXUNUSED(handler))
{
// we can't simply wxFAIL here as in SetNextHandler: in fact the last
// handler of our stack when is destroyed will be Unlink()ed and thus
// will call this function to update the pointer of this window...
//wxFAIL_MSG("wxWindow cannot be part of a wxEvtHandler chain");
}
void wxWindowBase::PushEventHandler(wxEvtHandler *handlerToPush)
{
wxCHECK_RET( handlerToPush != NULL, "PushEventHandler(NULL) called" );
// the new handler is going to be part of the wxWindow stack of event handlers:
// it can't be part also of an event handler double-linked chain:
wxASSERT_MSG(handlerToPush->IsUnlinked(),
"The handler being pushed in the wxWindow stack shouldn't be part of "
"a wxEvtHandler chain; call Unlink() on it first");
wxEvtHandler *handlerOld = GetEventHandler(); wxEvtHandler *handlerOld = GetEventHandler();
wxCHECK_RET( handlerOld, "an old event handler is NULL?" );
handler->SetNextHandler(handlerOld); // now use wxEvtHandler double-linked list to implement a stack:
handlerToPush->SetNextHandler(handlerOld);
if ( handlerOld ) if (handlerOld != this)
GetEventHandler()->SetPreviousHandler(handler); handlerOld->SetPreviousHandler(handlerToPush);
SetEventHandler(handler); SetEventHandler(handlerToPush);
#ifdef __WXDEBUG__
// final checks of the operations done above:
wxASSERT_MSG( handlerToPush->GetPreviousHandler() == NULL,
"the first handler of the wxWindow stack should have no previous handlers set" );
wxASSERT_MSG( handlerToPush->GetNextHandler() != NULL,
"the first handler of the wxWindow stack should have non-NULL next handler" );
wxEvtHandler* pLast = handlerToPush;
while (pLast && pLast != this)
pLast = pLast->GetNextHandler();
wxASSERT_MSG( pLast->GetNextHandler() == NULL,
"the last handler of the wxWindow stack should have this window as next handler" );
#endif
} }
wxEvtHandler *wxWindowBase::PopEventHandler(bool deleteHandler) wxEvtHandler *wxWindowBase::PopEventHandler(bool deleteHandler)
{ {
wxEvtHandler *handlerA = GetEventHandler(); // we need to pop the wxWindow stack, i.e. we need to remove the first handler
if ( handlerA )
wxEvtHandler *firstHandler = GetEventHandler();
wxCHECK_MSG( firstHandler != NULL, NULL, "wxWindow cannot have a NULL event handler" );
wxCHECK_MSG( firstHandler != this, NULL, "cannot pop the wxWindow itself" );
wxCHECK_MSG( firstHandler->GetPreviousHandler() == NULL, NULL,
"the first handler of the wxWindow stack should have no previous handlers set" );
wxEvtHandler *secondHandler = firstHandler->GetNextHandler();
wxCHECK_MSG( secondHandler != NULL, NULL,
"the first handler of the wxWindow stack should have non-NULL next handler" );
firstHandler->SetNextHandler(NULL);
secondHandler->SetPreviousHandler(NULL);
// now firstHandler is completely unlinked; set secondHandler as the new window event handler
SetEventHandler(secondHandler);
if ( deleteHandler )
{ {
wxEvtHandler *handlerB = handlerA->GetNextHandler(); delete firstHandler;
handlerA->SetNextHandler(NULL); firstHandler = NULL;
if ( handlerB )
handlerB->SetPreviousHandler(NULL);
SetEventHandler(handlerB);
if ( deleteHandler )
{
delete handlerA;
handlerA = NULL;
}
} }
return handlerA; return firstHandler;
} }
bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handler) bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handlerToRemove)
{ {
wxCHECK_MSG( handler, false, _T("RemoveEventHandler(NULL) called") ); wxCHECK_MSG( handlerToRemove != NULL, false, "RemoveEventHandler(NULL) called" );
wxCHECK_MSG( handlerToRemove != this, false, "Cannot remove the window itself" );
wxEvtHandler *handlerPrev = NULL, if (handlerToRemove == GetEventHandler())
*handlerCur = GetEventHandler(); {
while ( handlerCur ) // removing the first event handler is equivalent to "popping" the stack
PopEventHandler(false);
return true;
}
// NOTE: the wxWindow event handler list is always terminated with "this" handler
wxEvtHandler *handlerCur = GetEventHandler()->GetNextHandler();
while ( handlerCur != this )
{ {
wxEvtHandler *handlerNext = handlerCur->GetNextHandler(); wxEvtHandler *handlerNext = handlerCur->GetNextHandler();
if ( handlerCur == handler ) if ( handlerCur == handlerToRemove )
{ {
if ( handlerPrev ) handlerCur->Unlink();
{
handlerPrev->SetNextHandler(handlerNext);
}
else
{
SetEventHandler(handlerNext);
}
if ( handlerNext )
{
handlerNext->SetPreviousHandler ( handlerPrev );
}
handler->SetNextHandler(NULL);
handler->SetPreviousHandler(NULL);
wxASSERT_MSG( handlerCur != GetEventHandler(),
"the case Remove == Pop should was already handled" );
return true; return true;
} }
handlerPrev = handlerCur;
handlerCur = handlerNext; handlerCur = handlerNext;
} }
@@ -1173,6 +1221,7 @@ bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handler)
bool wxWindowBase::HandleWindowEvent(wxEvent& event) const bool wxWindowBase::HandleWindowEvent(wxEvent& event) const
{ {
// SafelyProcessEvent() will handle exceptions nicely
return GetEventHandler()->SafelyProcessEvent(event); return GetEventHandler()->SafelyProcessEvent(event);
} }