]> git.saurik.com Git - wxWidgets.git/commitdiff
fix wxWindow::PushEventHandler and related wxWindow functions for the stack managemen...
authorFrancesco Montorsi <f18m_cpp217828@yahoo.it>
Thu, 22 Jan 2009 11:53:09 +0000 (11:53 +0000)
committerFrancesco Montorsi <f18m_cpp217828@yahoo.it>
Thu, 22 Jan 2009 11:53:09 +0000 (11:53 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58291 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

16 files changed:
docs/doxygen/images/evthandler_unlink_after.dia [new file with mode: 0644]
docs/doxygen/images/evthandler_unlink_after.png [new file with mode: 0644]
docs/doxygen/images/evthandler_unlink_before.dia [new file with mode: 0644]
docs/doxygen/images/evthandler_unlink_before.png [new file with mode: 0644]
docs/doxygen/images/overview_eventhandling_chain.dia [new file with mode: 0644]
docs/doxygen/images/overview_eventhandling_chain.png [new file with mode: 0644]
docs/doxygen/images/overview_eventhandling_winstack.dia [new file with mode: 0644]
docs/doxygen/images/overview_eventhandling_winstack.png [new file with mode: 0644]
docs/doxygen/overviews/eventhandling.h
docs/doxygen/wxwidgets.css
include/wx/event.h
include/wx/window.h
interface/wx/event.h
interface/wx/window.h
src/common/event.cpp
src/common/wincmn.cpp

diff --git a/docs/doxygen/images/evthandler_unlink_after.dia b/docs/doxygen/images/evthandler_unlink_after.dia
new file mode 100644 (file)
index 0000000..bf494db
Binary files /dev/null and b/docs/doxygen/images/evthandler_unlink_after.dia differ
diff --git a/docs/doxygen/images/evthandler_unlink_after.png b/docs/doxygen/images/evthandler_unlink_after.png
new file mode 100644 (file)
index 0000000..f96ffcc
Binary files /dev/null and b/docs/doxygen/images/evthandler_unlink_after.png differ
diff --git a/docs/doxygen/images/evthandler_unlink_before.dia b/docs/doxygen/images/evthandler_unlink_before.dia
new file mode 100644 (file)
index 0000000..14e9fbf
Binary files /dev/null and b/docs/doxygen/images/evthandler_unlink_before.dia differ
diff --git a/docs/doxygen/images/evthandler_unlink_before.png b/docs/doxygen/images/evthandler_unlink_before.png
new file mode 100644 (file)
index 0000000..fa4c931
Binary files /dev/null and b/docs/doxygen/images/evthandler_unlink_before.png differ
diff --git a/docs/doxygen/images/overview_eventhandling_chain.dia b/docs/doxygen/images/overview_eventhandling_chain.dia
new file mode 100644 (file)
index 0000000..b9d12e3
Binary files /dev/null and b/docs/doxygen/images/overview_eventhandling_chain.dia differ
diff --git a/docs/doxygen/images/overview_eventhandling_chain.png b/docs/doxygen/images/overview_eventhandling_chain.png
new file mode 100644 (file)
index 0000000..fa4c931
Binary files /dev/null and b/docs/doxygen/images/overview_eventhandling_chain.png differ
diff --git a/docs/doxygen/images/overview_eventhandling_winstack.dia b/docs/doxygen/images/overview_eventhandling_winstack.dia
new file mode 100644 (file)
index 0000000..8b82bea
Binary files /dev/null and b/docs/doxygen/images/overview_eventhandling_winstack.dia differ
diff --git a/docs/doxygen/images/overview_eventhandling_winstack.png b/docs/doxygen/images/overview_eventhandling_winstack.png
new file mode 100644 (file)
index 0000000..397a97c
Binary files /dev/null and b/docs/doxygen/images/overview_eventhandling_winstack.png differ
index 8c6511a0c050938c1b6c28dfd8e9a88abd2df13f..3ee135fc24bef9de6f1df682abc3178c610bcc08 100644 (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.\r
 \r
 Let us start by looking at the syntax: the first obvious difference is that you\r
-need not use @c DECLARE_EVENT_TABLE() nor @c BEGIN_EVENT_TABLE and the\r
+need not use DECLARE_EVENT_TABLE() nor BEGIN_EVENT_TABLE() and the\r
 associated macros. Instead, in any place in your code, but usually in\r
 the code of the class defining the handler itself (and definitely not in the\r
 global scope as with the event tables), call its Connect() method like this:\r
@@ -331,10 +331,20 @@ doesn't count as having handled the event and the search continues):
     <li value="5">\r
     The event is passed to the next event handler, if any, in the event handler\r
     chain, i.e., the steps (1) to (4) are done for it. This chain can be formed\r
-    using wxEvtHandler::SetNextHandler() or wxWindow::PushEventHandler() but\r
-    usually there is no next event handler and chaining event handlers using\r
-    these functions is much less useful now that Connect() exists so this step\r
-    will almost never do anything.\r
+    using wxEvtHandler::SetNextHandler():\r
+        @image html overview_eventhandling_chain.png\r
+    (referring to the image, if @c A->ProcessEvent is called and it doesn't handle\r
+     the event, @c B->ProcessEvent will be called and so on...).\r
+    In the case of wxWindow you can build a stack (implemented using wxEvtHandler\r
+    double-linked list) using wxWindow::PushEventHandler():\r
+        @image html overview_eventhandling_winstack.png\r
+    (referring to the image, if @c W->ProcessEvent is called, it immediately calls\r
+     @c A->ProcessEvent; if nor @c A nor @c B handle the event, then the wxWindow\r
+     itself is used - i.e. the dynamically connected event handlers and static\r
+     event table entries of wxWindow are looked as the last possibility, after\r
+     all pushed event handlers were tested).\r
+    Note however that usually there are no wxEvtHandler chains nor wxWindows stacks\r
+    so this step will usually do anything.\r
     </li>\r
 \r
     <li value="6">\r
@@ -349,7 +359,7 @@ doesn't count as having handled the event and the search continues):
 \r
     <li value="7">\r
     Finally, i.e., if the event is still not processed, the wxApp object itself\r
-    gets a last chance to process it.\r
+    (which derives from wxEvtHandler) gets a last chance to process it.\r
     </li>\r
 </ol>\r
 \r
index 9f32c5b8489b37ab9b20fa74d45893f7ad280933..22957b7128622565a20e240a0dd2df1b607a4e46 100644 (file)
@@ -283,7 +283,7 @@ HR {
 }
 
 .memproto, .memdoc {
-       border: 1px solid #84b0c7;      
+       border: 1px solid #84b0c7;
 }
 
 .memproto {
@@ -400,6 +400,10 @@ H2 > A.anchor {
        color: black;
 }
 
+IMG {
+    margin: 20px;
+}
+
 IMG.logo {
        float: right;
        margin: 20px;
index 42c5406b1398372c6c3e48f4d27449be8f3b3a0f..b1c8df4821c4018ac87553b548ccd7bda773de7f 100644 (file)
@@ -2668,14 +2668,27 @@ public:
     wxEvtHandler();
     virtual ~wxEvtHandler();
 
+
+    // Event handler chain
+    // -------------------
+
     wxEvtHandler *GetNextHandler() const { return m_nextHandler; }
     wxEvtHandler *GetPreviousHandler() const { return m_previousHandler; }
-    void SetNextHandler(wxEvtHandler *handler) { m_nextHandler = handler; }
-    void SetPreviousHandler(wxEvtHandler *handler) { m_previousHandler = handler; }
+    virtual void SetNextHandler(wxEvtHandler *handler) { m_nextHandler = handler; }
+    virtual void SetPreviousHandler(wxEvtHandler *handler) { m_previousHandler = handler; }
 
     void SetEvtHandlerEnabled(bool enabled) { m_enabled = 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
     // thread, use QueueEvent() for scheduling the events for
     // processing from other threads.
@@ -2686,6 +2699,7 @@ public:
     // when called from C code (e.g. in GTK+ callback) when the exception
     // wouldn't correctly propagate to wxEventLoop.
     bool SafelyProcessEvent(wxEvent& event);
+        // NOTE: uses ProcessEvent()
 
     // 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
@@ -2708,11 +2722,17 @@ public:
     }
 
     void ProcessPendingEvents();
+        // NOTE: uses ProcessEvent()
 
 #if wxUSE_THREADS
     bool ProcessThreadEvent(const wxEvent& event);
+        // NOTE: uses AddPendingEvent()
 #endif
 
+
+    // Connecting and disconnecting
+    // ----------------------------
+
     // Dynamic association of a member function handler with the event handler,
     // winid and event type
     void Connect(int winid,
index 3a626d5a881e61524180686bd9d23c25c02b1271..932ac84f3656181628fd4e54d0ac25be714b71d1 100644 (file)
@@ -792,7 +792,7 @@ public:
 
         // replace the event handler (allows to completely subclass the
         // window)
-    void SetEventHandler( wxEvtHandler *handler ) { m_eventHandler = handler; }
+    void SetEventHandler( wxEvtHandler *handler );
 
         // push/pop event handler: allows to chain a custom event handler to
         // alreasy existing ones
@@ -806,13 +806,17 @@ public:
         // be there)
     bool RemoveEventHandler(wxEvtHandler *handler);
 
-    // Process an event by calling GetEventHandler()->ProcessEvent() and
-    // handling any exceptions thrown by event handlers. It's mostly useful
-    // when processing wx events when called from C code (e.g. in GTK+
-    // callback) when the exception wouldn't correctly propagate to
-    // wxEventLoop.
+        // Process an event by calling GetEventHandler()->ProcessEvent() and
+        // handling any exceptions thrown by event handlers. It's mostly useful
+        // when processing wx events when called from C code (e.g. in GTK+
+        // callback) when the exception wouldn't correctly propagate to
+        // wxEventLoop.
     bool HandleWindowEvent(wxEvent& event) const;
 
+        // disable wxEvtHandler double-linked list mechanism:
+    virtual void SetNextHandler(wxEvtHandler *handler);
+    virtual void SetPreviousHandler(wxEvtHandler *handler);
+
     // validators
     // ----------
 
index 8f76631f11c0a9985fe047118ea2702ca70a70b8..7fa2d397e6c581e2ab0bc38a125cfe1b698ae139 100644 (file)
@@ -258,7 +258,7 @@ public:
     wxWindow is (and therefore all window classes are) derived from this class.
 
     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
     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.
@@ -279,8 +279,8 @@ public:
     /**
         Destructor.
 
-        If the handler is part of a chain, the destructor will unlink itself and
-        restore the previous and next handlers so that they point to each other.
+        If the handler is part of a chain, the destructor will unlink itself
+        (see Unlink()).
     */
     virtual ~wxEvtHandler();
 
@@ -382,17 +382,23 @@ public:
 
         The normal order of event table searching is as follows:
         -# 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
-            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
-            class table is tried, and so on until no more tables exist or an appropriate
-            function was found, in which case the function exits.
+           class table is tried, and so on until no more tables exist or an appropriate
+           function was found, in which case the function exits.
         -# 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()
-            is recursively applied to the parent window's event handler.
-            If this returns true, the function exits.
+           is recursively applied to the parent window's event handler.
+           If this returns @true, the function exits.
         -# Finally, ProcessEvent() is called on the wxApp object.
 
         @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.
 
+        @remarks
+        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
+
         @param handler
-            Event handler to be set as the next handler.
+            The event handler to be set as the next handler.
+            Cannot be @NULL.
 
-        @see GetNextHandler(), SetPreviousHandler(), GetPreviousHandler(),
-             wxWindow::PushEventHandler, wxWindow::PopEventHandler
+        @see @ref overview_eventhandling_processing
     */
-    void SetNextHandler(wxEvtHandler* handler);
+    virtual void SetNextHandler(wxEvtHandler* handler);
 
     /**
         Sets the pointer to the previous handler.
+        All remarks about SetNextHandler() apply to this function as well.
 
         @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
+    */
+    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()
     */
-    void SetPreviousHandler(wxEvtHandler* handler);
+    bool IsUnlinked() const;
 
     //@}
 };
index 3bfeaf9b37a73419deea360fff0968ccd9abc44e..a77ebf36043818b4ffc674a01ca424f00a85b6ba 100644 (file)
@@ -1656,6 +1656,9 @@ public:
 
     /**
         @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;
 
     /**
-        This function will generate the appropriate call to
-        Navigate() if the key event is one normally used for
-        keyboard navigation and return @true in this case.
+        This function will generate the appropriate call to Navigate() if the key
+        event is one normally used for keyboard navigation and return @true in this case.
 
         @return Returns @true if the key pressed was for navigation and was
                 handled, @false otherwise.
@@ -1691,44 +1693,62 @@ public:
     /**
         Removes and returns the top-most event handler on the event handler stack.
 
+        E.g. in the case of:
+            @image html overview_eventhandling_winstack.png
+        when calling @c W->PopEventHandler(), the event handler @c A will be
+        removed and @c B will be the first handler of the stack.
+
+        Note that it's an error to call this function when no event handlers
+        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.
-            The default value is @false.
+            If this is @true, the handler will be deleted after it is removed
+            (and the returned value will be @NULL).
 
-        @see SetEventHandler(), GetEventHandler(),
-             PushEventHandler(), wxEvtHandler::ProcessEvent, wxEvtHandler
+        @see @ref overview_eventhandling_processing
     */
     wxEvtHandler* PopEventHandler(bool deleteHandler = false);
 
     /**
         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
             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
-                 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
+        @see @ref overview_eventhandling_processing
     */
     void PushEventHandler(wxEvtHandler* handler);
 
     /**
-        Find the given @a handler in the windows event handler chain and remove
-        (but not delete) it from it.
+        Find the given @a handler in the windows event handler stack and unlinks
+        (but not delete) it. See wxEvtHandler::Unlink() for more info.
 
         @param handler
             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
                 results in an assert failure so this function should
@@ -1741,27 +1761,41 @@ public:
     /**
         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
-            Specifies the handler to be set.
-
-        @remarks 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.
-                 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
+            Specifies the handler to be set. Cannot be @NULL.
+
+        @see @ref overview_eventhandling_processing
     */
     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
     */
index 3ee0d136ed3fc7652352054dbaee41f82c2f7304..4d349cf956cb90649b9a7b2d2561586c9f4ccffa 100644 (file)
@@ -1036,12 +1036,7 @@ wxEvtHandler::wxEvtHandler()
 
 wxEvtHandler::~wxEvtHandler()
 {
-    // Takes itself out of the list of handlers
-    if (m_previousHandler)
-        m_previousHandler->m_nextHandler = m_nextHandler;
-
-    if (m_nextHandler)
-        m_nextHandler->m_previousHandler = m_previousHandler;
+    Unlink();
 
     if (m_dynamicEvents)
     {
@@ -1103,6 +1098,26 @@ wxEvtHandler::~wxEvtHandler()
         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
 
 bool wxEvtHandler::ProcessThreadEvent(const wxEvent& event)
index 964585411ae2aa7b9834a210a6f133389dcb56d7..878bca5ae8c6abd5e3059f3c15b5d9bba23af67d 100644 (file)
@@ -1096,73 +1096,121 @@ bool wxWindowBase::Reparent(wxWindowBase *newParent)
 // 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();
+    wxCHECK_RET( handlerOld, "an old event handler is NULL?" );
+
+    // now use wxEvtHandler double-linked list to implement a stack:
+    handlerToPush->SetNextHandler(handlerOld);
 
-    handler->SetNextHandler(handlerOld);
+    if (handlerOld != this)
+        handlerOld->SetPreviousHandler(handlerToPush);
 
-    if ( handlerOld )
-        GetEventHandler()->SetPreviousHandler(handler);
+    SetEventHandler(handlerToPush);
 
-    SetEventHandler(handler);
+#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 *handlerA = GetEventHandler();
-    if ( handlerA )
-    {
-        wxEvtHandler *handlerB = handlerA->GetNextHandler();
-        handlerA->SetNextHandler(NULL);
+    // we need to pop the wxWindow stack, i.e. we need to remove the first handler
 
-        if ( handlerB )
-            handlerB->SetPreviousHandler(NULL);
-        SetEventHandler(handlerB);
+    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" );
 
-        if ( deleteHandler )
-        {
-            delete handlerA;
-            handlerA = NULL;
-        }
+    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 )
+    {
+        delete firstHandler;
+        firstHandler = 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" );
+
+    if (handlerToRemove == GetEventHandler())
+    {
+        // removing the first event handler is equivalent to "popping" the stack
+        PopEventHandler(false);
+        return true;
+    }
 
-    wxEvtHandler *handlerPrev = NULL,
-                 *handlerCur = GetEventHandler();
-    while ( handlerCur )
+    // NOTE: the wxWindow event handler list is always terminated with "this" handler
+    wxEvtHandler *handlerCur = GetEventHandler()->GetNextHandler();
+    while ( handlerCur != this )
     {
         wxEvtHandler *handlerNext = handlerCur->GetNextHandler();
 
-        if ( handlerCur == handler )
+        if ( handlerCur == handlerToRemove )
         {
-            if ( handlerPrev )
-            {
-                handlerPrev->SetNextHandler(handlerNext);
-            }
-            else
-            {
-                SetEventHandler(handlerNext);
-            }
-
-            if ( handlerNext )
-            {
-                handlerNext->SetPreviousHandler ( handlerPrev );
-            }
-
-            handler->SetNextHandler(NULL);
-            handler->SetPreviousHandler(NULL);
+            handlerCur->Unlink();
 
+            wxASSERT_MSG( handlerCur != GetEventHandler(),
+                        "the case Remove == Pop should was already handled" );
             return true;
         }
 
-        handlerPrev = handlerCur;
         handlerCur = handlerNext;
     }
 
@@ -1173,6 +1221,7 @@ bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handler)
 
 bool wxWindowBase::HandleWindowEvent(wxEvent& event) const
 {
+    // SafelyProcessEvent() will handle exceptions nicely
     return GetEventHandler()->SafelyProcessEvent(event);
 }