]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/event.cpp
fixing overrelease and out-of-bounds write, fixes #13725
[wxWidgets.git] / src / common / event.cpp
index 4d349cf956cb90649b9a7b2d2561586c9f4ccffa..4bc798968278b10caf853d2b617959b682951804 100644 (file)
 #endif
 
 #include "wx/event.h"
+#include "wx/eventfilter.h"
 #include "wx/evtloop.h"
 
 #ifndef WX_PRECOMP
     #include "wx/list.h"
+    #include "wx/log.h"
     #include "wx/app.h"
     #include "wx/utils.h"
     #include "wx/stopwatch.h"
@@ -38,6 +40,7 @@
         #include "wx/window.h"
         #include "wx/control.h"
         #include "wx/dc.h"
+        #include "wx/spinbutt.h"
         #include "wx/textctrl.h"
         #include "wx/validate.h"
     #endif // wxUSE_GUI
@@ -46,7 +49,7 @@
 #include "wx/thread.h"
 
 #if wxUSE_BASE
-    #include "wx/ptr_scpd.h"
+    #include "wx/scopedptr.h"
 
     wxDECLARE_SCOPED_PTR(wxEvent, wxEventPtr)
     wxDEFINE_SCOPED_PTR(wxEvent, wxEventPtr)
@@ -60,6 +63,7 @@
     IMPLEMENT_DYNAMIC_CLASS(wxEvtHandler, wxObject)
     IMPLEMENT_ABSTRACT_CLASS(wxEvent, wxObject)
     IMPLEMENT_DYNAMIC_CLASS(wxIdleEvent, wxEvent)
+    IMPLEMENT_DYNAMIC_CLASS(wxThreadEvent, wxEvent)
 #endif // wxUSE_BASE
 
 #if wxUSE_GUI
@@ -115,7 +119,7 @@ wxEventHashTable &wxEvtHandler::GetEventHashTable() const
 wxEventHashTable wxEvtHandler::sm_eventHashTable(wxEvtHandler::sm_eventTable);
 
 const wxEventTableEntry wxEvtHandler::sm_eventTableEntries[] =
-    { DECLARE_EVENT_TABLE_TERMINATOR() };
+    { wxDECLARE_EVENT_TABLE_TERMINATOR() };
 
 
 // wxUSE_MEMORY_TRACING considers memory freed from the static objects dtors
@@ -123,7 +127,7 @@ const wxEventTableEntry wxEvtHandler::sm_eventTableEntries[] =
 // the memory leaks when using it, however this breaks re-initializing the
 // library (i.e. repeated calls to wxInitialize/wxUninitialize) because the
 // event tables won't be rebuilt the next time, so disable this by default
-#if defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING
+#if wxUSE_MEMORY_TRACING
 
 class wxEventTableEntryModule: public wxModule
 {
@@ -137,168 +141,181 @@ public:
 
 IMPLEMENT_DYNAMIC_CLASS(wxEventTableEntryModule, wxModule)
 
-#endif // __WXDEBUG__ && wxUSE_MEMORY_TRACING
+#endif // wxUSE_MEMORY_TRACING
 
 // ----------------------------------------------------------------------------
 // global variables
 // ----------------------------------------------------------------------------
 
-// List containing event handlers with pending events (each handler can occur
-// at most once here)
-wxList *wxHandlersWithPendingEvents = NULL;
-
-#if wxUSE_THREADS
-    // protects wxHandlersWithPendingEvents list
-    wxCriticalSection *wxHandlersWithPendingEventsLocker = NULL;
-#endif
-
 // common event types are defined here, other event types are defined by the
 // components which use them
 
 const wxEventType wxEVT_FIRST = 10000;
 const wxEventType wxEVT_USER_FIRST = wxEVT_FIRST + 2000;
+const wxEventType wxEVT_NULL = wxNewEventType();
 
-DEFINE_EVENT_TYPE(wxEVT_NULL)
-wxDEFINE_EVENT( wxEVT_IDLE, wxIdleEvent )
+wxDEFINE_EVENT( wxEVT_IDLE, wxIdleEvent );
+
+// Thread and asynchronous call events
+wxDEFINE_EVENT( wxEVT_THREAD, wxThreadEvent );
+wxDEFINE_EVENT( wxEVT_ASYNC_METHOD_CALL, wxAsyncMethodCallEvent );
 
 #endif // wxUSE_BASE
 
 #if wxUSE_GUI
 
-wxDEFINE_EVENT( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_MENU_SELECTED, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_SLIDER_UPDATED, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_SCROLLBAR_UPDATED, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_VLBOX_SELECTED, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_TOOL_RCLICKED, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_TOOL_ENTER, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_TOOL_DROPDOWN_CLICKED, wxCommandEvent )
+wxDEFINE_EVENT( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_MENU_SELECTED, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_SLIDER_UPDATED, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_SCROLLBAR_UPDATED, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_VLBOX_SELECTED, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_TOOL_RCLICKED, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_TOOL_ENTER, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_TOOL_DROPDOWN_CLICKED, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_COMBOBOX_DROPDOWN, wxCommandEvent);
+wxDEFINE_EVENT( wxEVT_COMMAND_COMBOBOX_CLOSEUP, wxCommandEvent);
 
 // Mouse event types
-wxDEFINE_EVENT( wxEVT_LEFT_DOWN, wxMouseEvent )
-wxDEFINE_EVENT( wxEVT_LEFT_UP, wxMouseEvent )
-wxDEFINE_EVENT( wxEVT_MIDDLE_DOWN, wxMouseEvent )
-wxDEFINE_EVENT( wxEVT_MIDDLE_UP, wxMouseEvent )
-wxDEFINE_EVENT( wxEVT_RIGHT_DOWN, wxMouseEvent )
-wxDEFINE_EVENT( wxEVT_RIGHT_UP, wxMouseEvent )
-wxDEFINE_EVENT( wxEVT_MOTION, wxMouseEvent )
-wxDEFINE_EVENT( wxEVT_ENTER_WINDOW, wxMouseEvent )
-wxDEFINE_EVENT( wxEVT_LEAVE_WINDOW, wxMouseEvent )
-wxDEFINE_EVENT( wxEVT_LEFT_DCLICK, wxMouseEvent )
-wxDEFINE_EVENT( wxEVT_MIDDLE_DCLICK, wxMouseEvent )
-wxDEFINE_EVENT( wxEVT_RIGHT_DCLICK, wxMouseEvent )
-wxDEFINE_EVENT( wxEVT_SET_FOCUS, wxFocusEvent )
-wxDEFINE_EVENT( wxEVT_KILL_FOCUS, wxFocusEvent )
-wxDEFINE_EVENT( wxEVT_CHILD_FOCUS, wxChildFocusEvent )
-wxDEFINE_EVENT( wxEVT_MOUSEWHEEL, wxMouseEvent )
-wxDEFINE_EVENT( wxEVT_AUX1_DOWN, wxMouseEvent )
-wxDEFINE_EVENT( wxEVT_AUX1_UP, wxMouseEvent )
-wxDEFINE_EVENT( wxEVT_AUX1_DCLICK, wxMouseEvent )
-wxDEFINE_EVENT( wxEVT_AUX2_DOWN, wxMouseEvent )
-wxDEFINE_EVENT( wxEVT_AUX2_UP, wxMouseEvent )
-wxDEFINE_EVENT( wxEVT_AUX2_DCLICK, wxMouseEvent )
+wxDEFINE_EVENT( wxEVT_LEFT_DOWN, wxMouseEvent );
+wxDEFINE_EVENT( wxEVT_LEFT_UP, wxMouseEvent );
+wxDEFINE_EVENT( wxEVT_MIDDLE_DOWN, wxMouseEvent );
+wxDEFINE_EVENT( wxEVT_MIDDLE_UP, wxMouseEvent );
+wxDEFINE_EVENT( wxEVT_RIGHT_DOWN, wxMouseEvent );
+wxDEFINE_EVENT( wxEVT_RIGHT_UP, wxMouseEvent );
+wxDEFINE_EVENT( wxEVT_MOTION, wxMouseEvent );
+wxDEFINE_EVENT( wxEVT_ENTER_WINDOW, wxMouseEvent );
+wxDEFINE_EVENT( wxEVT_LEAVE_WINDOW, wxMouseEvent );
+wxDEFINE_EVENT( wxEVT_LEFT_DCLICK, wxMouseEvent );
+wxDEFINE_EVENT( wxEVT_MIDDLE_DCLICK, wxMouseEvent );
+wxDEFINE_EVENT( wxEVT_RIGHT_DCLICK, wxMouseEvent );
+wxDEFINE_EVENT( wxEVT_SET_FOCUS, wxFocusEvent );
+wxDEFINE_EVENT( wxEVT_KILL_FOCUS, wxFocusEvent );
+wxDEFINE_EVENT( wxEVT_CHILD_FOCUS, wxChildFocusEvent );
+wxDEFINE_EVENT( wxEVT_MOUSEWHEEL, wxMouseEvent );
+wxDEFINE_EVENT( wxEVT_AUX1_DOWN, wxMouseEvent );
+wxDEFINE_EVENT( wxEVT_AUX1_UP, wxMouseEvent );
+wxDEFINE_EVENT( wxEVT_AUX1_DCLICK, wxMouseEvent );
+wxDEFINE_EVENT( wxEVT_AUX2_DOWN, wxMouseEvent );
+wxDEFINE_EVENT( wxEVT_AUX2_UP, wxMouseEvent );
+wxDEFINE_EVENT( wxEVT_AUX2_DCLICK, wxMouseEvent );
 
 // Character input event type
-wxDEFINE_EVENT( wxEVT_CHAR, wxKeyEvent )
-wxDEFINE_EVENT( wxEVT_CHAR_HOOK, wxKeyEvent )
-wxDEFINE_EVENT( wxEVT_NAVIGATION_KEY, wxNavigationKeyEvent )
-wxDEFINE_EVENT( wxEVT_KEY_DOWN, wxKeyEvent )
-wxDEFINE_EVENT( wxEVT_KEY_UP, wxKeyEvent )
+wxDEFINE_EVENT( wxEVT_CHAR, wxKeyEvent );
+wxDEFINE_EVENT( wxEVT_AFTER_CHAR, wxKeyEvent );
+wxDEFINE_EVENT( wxEVT_CHAR_HOOK, wxKeyEvent );
+wxDEFINE_EVENT( wxEVT_NAVIGATION_KEY, wxNavigationKeyEvent );
+wxDEFINE_EVENT( wxEVT_KEY_DOWN, wxKeyEvent );
+wxDEFINE_EVENT( wxEVT_KEY_UP, wxKeyEvent );
 #if wxUSE_HOTKEY
-wxDEFINE_EVENT( wxEVT_HOTKEY, wxKeyEvent )
+wxDEFINE_EVENT( wxEVT_HOTKEY, wxKeyEvent );
 #endif
 
 // Set cursor event
-wxDEFINE_EVENT( wxEVT_SET_CURSOR, wxSetCursorEvent )
+wxDEFINE_EVENT( wxEVT_SET_CURSOR, wxSetCursorEvent );
 
 // wxScrollbar and wxSlider event identifiers
-wxDEFINE_EVENT( wxEVT_SCROLL_TOP, wxScrollEvent )
-wxDEFINE_EVENT( wxEVT_SCROLL_BOTTOM, wxScrollEvent )
-wxDEFINE_EVENT( wxEVT_SCROLL_LINEUP, wxScrollEvent )
-wxDEFINE_EVENT( wxEVT_SCROLL_LINEDOWN, wxScrollEvent )
-wxDEFINE_EVENT( wxEVT_SCROLL_PAGEUP, wxScrollEvent )
-wxDEFINE_EVENT( wxEVT_SCROLL_PAGEDOWN, wxScrollEvent )
-wxDEFINE_EVENT( wxEVT_SCROLL_THUMBTRACK, wxScrollEvent )
-wxDEFINE_EVENT( wxEVT_SCROLL_THUMBRELEASE, wxScrollEvent )
-wxDEFINE_EVENT( wxEVT_SCROLL_CHANGED, wxScrollEvent )
+wxDEFINE_EVENT( wxEVT_SCROLL_TOP, wxScrollEvent );
+wxDEFINE_EVENT( wxEVT_SCROLL_BOTTOM, wxScrollEvent );
+wxDEFINE_EVENT( wxEVT_SCROLL_LINEUP, wxScrollEvent );
+wxDEFINE_EVENT( wxEVT_SCROLL_LINEDOWN, wxScrollEvent );
+wxDEFINE_EVENT( wxEVT_SCROLL_PAGEUP, wxScrollEvent );
+wxDEFINE_EVENT( wxEVT_SCROLL_PAGEDOWN, wxScrollEvent );
+wxDEFINE_EVENT( wxEVT_SCROLL_THUMBTRACK, wxScrollEvent );
+wxDEFINE_EVENT( wxEVT_SCROLL_THUMBRELEASE, wxScrollEvent );
+wxDEFINE_EVENT( wxEVT_SCROLL_CHANGED, wxScrollEvent );
+
+// Due to a bug in older wx versions, wxSpinEvents were being sent with type of
+// wxEVT_SCROLL_LINEUP, wxEVT_SCROLL_LINEDOWN and wxEVT_SCROLL_THUMBTRACK. But
+// with the type-safe events in place, these event types are associated with
+// wxScrollEvent. To allow handling of spin events, new event types have been
+// defined in spinbutt.h/spinnbuttcmn.cpp. To maintain backward compatibility
+// the spin event types are being initialized with the scroll event types.
+
+#if wxUSE_SPINBTN
+
+wxDEFINE_EVENT_ALIAS( wxEVT_SPIN_UP,   wxSpinEvent, wxEVT_SCROLL_LINEUP );
+wxDEFINE_EVENT_ALIAS( wxEVT_SPIN_DOWN, wxSpinEvent, wxEVT_SCROLL_LINEDOWN );
+wxDEFINE_EVENT_ALIAS( wxEVT_SPIN,      wxSpinEvent, wxEVT_SCROLL_THUMBTRACK );
+
+#endif // wxUSE_SPINBTN
 
 // Scroll events from wxWindow
-wxDEFINE_EVENT( wxEVT_SCROLLWIN_TOP, wxScrollWinEvent )
-wxDEFINE_EVENT( wxEVT_SCROLLWIN_BOTTOM, wxScrollWinEvent )
-wxDEFINE_EVENT( wxEVT_SCROLLWIN_LINEUP, wxScrollWinEvent )
-wxDEFINE_EVENT( wxEVT_SCROLLWIN_LINEDOWN, wxScrollWinEvent )
-wxDEFINE_EVENT( wxEVT_SCROLLWIN_PAGEUP, wxScrollWinEvent )
-wxDEFINE_EVENT( wxEVT_SCROLLWIN_PAGEDOWN, wxScrollWinEvent )
-wxDEFINE_EVENT( wxEVT_SCROLLWIN_THUMBTRACK, wxScrollWinEvent )
-wxDEFINE_EVENT( wxEVT_SCROLLWIN_THUMBRELEASE, wxScrollWinEvent )
+wxDEFINE_EVENT( wxEVT_SCROLLWIN_TOP, wxScrollWinEvent );
+wxDEFINE_EVENT( wxEVT_SCROLLWIN_BOTTOM, wxScrollWinEvent );
+wxDEFINE_EVENT( wxEVT_SCROLLWIN_LINEUP, wxScrollWinEvent );
+wxDEFINE_EVENT( wxEVT_SCROLLWIN_LINEDOWN, wxScrollWinEvent );
+wxDEFINE_EVENT( wxEVT_SCROLLWIN_PAGEUP, wxScrollWinEvent );
+wxDEFINE_EVENT( wxEVT_SCROLLWIN_PAGEDOWN, wxScrollWinEvent );
+wxDEFINE_EVENT( wxEVT_SCROLLWIN_THUMBTRACK, wxScrollWinEvent );
+wxDEFINE_EVENT( wxEVT_SCROLLWIN_THUMBRELEASE, wxScrollWinEvent );
 
 // System events
-wxDEFINE_EVENT( wxEVT_SIZE, wxSizeEvent )
-wxDEFINE_EVENT( wxEVT_SIZING, wxSizeEvent )
-wxDEFINE_EVENT( wxEVT_MOVE, wxMoveEvent )
-wxDEFINE_EVENT( wxEVT_MOVING, wxMoveEvent )
-wxDEFINE_EVENT( wxEVT_MOVE_START, wxMoveEvent )
-wxDEFINE_EVENT( wxEVT_MOVE_END, wxMoveEvent )
-wxDEFINE_EVENT( wxEVT_CLOSE_WINDOW, wxCloseEvent )
-wxDEFINE_EVENT( wxEVT_END_SESSION, wxCloseEvent )
-wxDEFINE_EVENT( wxEVT_QUERY_END_SESSION, wxCloseEvent )
-wxDEFINE_EVENT( wxEVT_HIBERNATE, wxActivateEvent )
-wxDEFINE_EVENT( wxEVT_ACTIVATE_APP, wxActivateEvent )
-wxDEFINE_EVENT( wxEVT_ACTIVATE, wxActivateEvent )
-wxDEFINE_EVENT( wxEVT_CREATE, wxWindowCreateEvent )
-wxDEFINE_EVENT( wxEVT_DESTROY, wxWindowDestroyEvent )
-wxDEFINE_EVENT( wxEVT_SHOW, wxShowEvent )
-wxDEFINE_EVENT( wxEVT_ICONIZE, wxIconizeEvent )
-wxDEFINE_EVENT( wxEVT_MAXIMIZE, wxMaximizeEvent )
-wxDEFINE_EVENT( wxEVT_MOUSE_CAPTURE_CHANGED, wxMouseCaptureChangedEvent )
-wxDEFINE_EVENT( wxEVT_MOUSE_CAPTURE_LOST, wxMouseCaptureLostEvent )
-wxDEFINE_EVENT( wxEVT_PAINT, wxPaintEvent )
-wxDEFINE_EVENT( wxEVT_ERASE_BACKGROUND, wxEraseEvent )
-wxDEFINE_EVENT( wxEVT_NC_PAINT, wxNcPaintEvent )
-wxDEFINE_EVENT( wxEVT_MENU_OPEN, wxMenuEvent )
-wxDEFINE_EVENT( wxEVT_MENU_CLOSE, wxMenuEvent )
-wxDEFINE_EVENT( wxEVT_MENU_HIGHLIGHT, wxMenuEvent )
-wxDEFINE_EVENT( wxEVT_CONTEXT_MENU, wxContextMenuEvent )
-wxDEFINE_EVENT( wxEVT_SYS_COLOUR_CHANGED, wxSysColourChangedEvent )
-wxDEFINE_EVENT( wxEVT_DISPLAY_CHANGED, wxDisplayChangedEvent )
-wxDEFINE_EVENT( wxEVT_QUERY_NEW_PALETTE, wxQueryNewPaletteEvent )
-wxDEFINE_EVENT( wxEVT_PALETTE_CHANGED, wxPaletteChangedEvent )
-wxDEFINE_EVENT( wxEVT_JOY_BUTTON_DOWN, wxJoystickEvent )
-wxDEFINE_EVENT( wxEVT_JOY_BUTTON_UP, wxJoystickEvent )
-wxDEFINE_EVENT( wxEVT_JOY_MOVE, wxJoystickEvent )
-wxDEFINE_EVENT( wxEVT_JOY_ZMOVE, wxJoystickEvent )
-wxDEFINE_EVENT( wxEVT_DROP_FILES, wxDropFilesEvent )
-wxDEFINE_EVENT( wxEVT_INIT_DIALOG, wxInitDialogEvent )
-wxDEFINE_EVENT( wxEVT_UPDATE_UI, wxUpdateUIEvent )
+wxDEFINE_EVENT( wxEVT_SIZE, wxSizeEvent );
+wxDEFINE_EVENT( wxEVT_SIZING, wxSizeEvent );
+wxDEFINE_EVENT( wxEVT_MOVE, wxMoveEvent );
+wxDEFINE_EVENT( wxEVT_MOVING, wxMoveEvent );
+wxDEFINE_EVENT( wxEVT_MOVE_START, wxMoveEvent );
+wxDEFINE_EVENT( wxEVT_MOVE_END, wxMoveEvent );
+wxDEFINE_EVENT( wxEVT_CLOSE_WINDOW, wxCloseEvent );
+wxDEFINE_EVENT( wxEVT_END_SESSION, wxCloseEvent );
+wxDEFINE_EVENT( wxEVT_QUERY_END_SESSION, wxCloseEvent );
+wxDEFINE_EVENT( wxEVT_HIBERNATE, wxActivateEvent );
+wxDEFINE_EVENT( wxEVT_ACTIVATE_APP, wxActivateEvent );
+wxDEFINE_EVENT( wxEVT_ACTIVATE, wxActivateEvent );
+wxDEFINE_EVENT( wxEVT_CREATE, wxWindowCreateEvent );
+wxDEFINE_EVENT( wxEVT_DESTROY, wxWindowDestroyEvent );
+wxDEFINE_EVENT( wxEVT_SHOW, wxShowEvent );
+wxDEFINE_EVENT( wxEVT_ICONIZE, wxIconizeEvent );
+wxDEFINE_EVENT( wxEVT_MAXIMIZE, wxMaximizeEvent );
+wxDEFINE_EVENT( wxEVT_MOUSE_CAPTURE_CHANGED, wxMouseCaptureChangedEvent );
+wxDEFINE_EVENT( wxEVT_MOUSE_CAPTURE_LOST, wxMouseCaptureLostEvent );
+wxDEFINE_EVENT( wxEVT_PAINT, wxPaintEvent );
+wxDEFINE_EVENT( wxEVT_ERASE_BACKGROUND, wxEraseEvent );
+wxDEFINE_EVENT( wxEVT_NC_PAINT, wxNcPaintEvent );
+wxDEFINE_EVENT( wxEVT_MENU_OPEN, wxMenuEvent );
+wxDEFINE_EVENT( wxEVT_MENU_CLOSE, wxMenuEvent );
+wxDEFINE_EVENT( wxEVT_MENU_HIGHLIGHT, wxMenuEvent );
+wxDEFINE_EVENT( wxEVT_CONTEXT_MENU, wxContextMenuEvent );
+wxDEFINE_EVENT( wxEVT_SYS_COLOUR_CHANGED, wxSysColourChangedEvent );
+wxDEFINE_EVENT( wxEVT_DISPLAY_CHANGED, wxDisplayChangedEvent );
+wxDEFINE_EVENT( wxEVT_QUERY_NEW_PALETTE, wxQueryNewPaletteEvent );
+wxDEFINE_EVENT( wxEVT_PALETTE_CHANGED, wxPaletteChangedEvent );
+wxDEFINE_EVENT( wxEVT_JOY_BUTTON_DOWN, wxJoystickEvent );
+wxDEFINE_EVENT( wxEVT_JOY_BUTTON_UP, wxJoystickEvent );
+wxDEFINE_EVENT( wxEVT_JOY_MOVE, wxJoystickEvent );
+wxDEFINE_EVENT( wxEVT_JOY_ZMOVE, wxJoystickEvent );
+wxDEFINE_EVENT( wxEVT_DROP_FILES, wxDropFilesEvent );
+wxDEFINE_EVENT( wxEVT_INIT_DIALOG, wxInitDialogEvent );
+wxDEFINE_EVENT( wxEVT_UPDATE_UI, wxUpdateUIEvent );
 
 // Clipboard events
-wxDEFINE_EVENT( wxEVT_COMMAND_TEXT_COPY, wxClipboardTextEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_TEXT_CUT, wxClipboardTextEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_TEXT_PASTE, wxClipboardTextEvent )
+wxDEFINE_EVENT( wxEVT_COMMAND_TEXT_COPY, wxClipboardTextEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_TEXT_CUT, wxClipboardTextEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_TEXT_PASTE, wxClipboardTextEvent );
 
 // Generic command events
 // Note: a click is a higher-level event than button down/up
-wxDEFINE_EVENT( wxEVT_COMMAND_LEFT_CLICK, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_LEFT_DCLICK, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_RIGHT_CLICK, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_RIGHT_DCLICK, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_SET_FOCUS, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_KILL_FOCUS, wxCommandEvent )
-wxDEFINE_EVENT( wxEVT_COMMAND_ENTER, wxCommandEvent )
+wxDEFINE_EVENT( wxEVT_COMMAND_LEFT_CLICK, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_LEFT_DCLICK, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_RIGHT_CLICK, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_RIGHT_DCLICK, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_SET_FOCUS, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_KILL_FOCUS, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMMAND_ENTER, wxCommandEvent );
 
 // Help events
-wxDEFINE_EVENT( wxEVT_HELP, wxHelpEvent )
-wxDEFINE_EVENT( wxEVT_DETAILED_HELP, wxHelpEvent )
+wxDEFINE_EVENT( wxEVT_HELP, wxHelpEvent );
+wxDEFINE_EVENT( wxEVT_DETAILED_HELP, wxHelpEvent );
 
 #endif // wxUSE_GUI
 
@@ -334,15 +351,14 @@ wxEventFunctor::~wxEventFunctor()
 // ----------------------------------------------------------------------------
 
 /*
- * General wxWidgets events, covering
- * all interesting things that might happen (button clicking, resizing,
- * setting text in widgets, etc.).
+ * General wxWidgets events, covering all interesting things that might happen
+ * (button clicking, resizing, setting text in widgets, etc.).
  *
  * For each completely new event type, derive a new event class.
  *
  */
 
-wxEvent::wxEvent(int theId, wxEventType commandType )
+wxEvent::wxEvent(int theId, wxEventType commandType)
 {
     m_eventType = commandType;
     m_eventObject = NULL;
@@ -350,6 +366,7 @@ wxEvent::wxEvent(int theId, wxEventType commandType )
     m_id = theId;
     m_skipped = false;
     m_callbackUserData = NULL;
+    m_handlerToProcessOnlyIn = NULL;
     m_isCommandEvent = false;
     m_propagationLevel = wxEVENT_PROPAGATE_NONE;
     m_wasProcessed = false;
@@ -362,6 +379,7 @@ wxEvent::wxEvent(const wxEvent& src)
     , m_timeStamp(src.m_timeStamp)
     , m_id(src.m_id)
     , m_callbackUserData(src.m_callbackUserData)
+    , m_handlerToProcessOnlyIn(NULL)
     , m_propagationLevel(src.m_propagationLevel)
     , m_skipped(src.m_skipped)
     , m_isCommandEvent(src.m_isCommandEvent)
@@ -378,6 +396,7 @@ wxEvent& wxEvent::operator=(const wxEvent& src)
     m_timeStamp = src.m_timeStamp;
     m_id = src.m_id;
     m_callbackUserData = src.m_callbackUserData;
+    m_handlerToProcessOnlyIn = NULL;
     m_propagationLevel = src.m_propagationLevel;
     m_skipped = src.m_skipped;
     m_isCommandEvent = src.m_isCommandEvent;
@@ -391,33 +410,21 @@ wxEvent& wxEvent::operator=(const wxEvent& src)
 
 #if wxUSE_GUI
 
-/*
- * Command events
- *
- */
-
-#ifdef __VISUALC__
-    // 'this' : used in base member initializer list (for m_commandString)
-    #pragma warning(disable:4355)
-#endif
+// ----------------------------------------------------------------------------
+// wxCommandEvent
+// ----------------------------------------------------------------------------
 
 wxCommandEvent::wxCommandEvent(wxEventType commandType, int theId)
               : wxEvent(theId, commandType)
 {
     m_clientData = NULL;
     m_clientObject = NULL;
-    m_extraLong = 0;
-    m_commandInt = 0;
     m_isCommandEvent = true;
 
     // the command events are propagated upwards by default
     m_propagationLevel = wxEVENT_PROPAGATE_MAX;
 }
 
-#ifdef __VISUALC__
-    #pragma warning(default:4355)
-#endif
-
 wxString wxCommandEvent::GetString() const
 {
     if (m_eventType != wxEVT_COMMAND_TEXT_UPDATED || !m_eventObject)
@@ -436,9 +443,9 @@ wxString wxCommandEvent::GetString() const
     }
 }
 
-/*
- * UI update events
- */
+// ----------------------------------------------------------------------------
+// wxUpdateUIEvent
+// ----------------------------------------------------------------------------
 
 #if wxUSE_LONGLONG
 wxLongLong wxUpdateUIEvent::sm_lastUpdate = 0;
@@ -458,6 +465,13 @@ bool wxUpdateUIEvent::CanUpdate(wxWindowBase *win)
        ((win->GetExtraStyle() & wxWS_EX_PROCESS_UI_UPDATES) == 0)))
         return false;
 
+    // Don't update children of the hidden windows: this is useless as any
+    // change to their state won't be seen by the user anyhow. Notice that this
+    // argument doesn't apply to the hidden windows (with visible parent)
+    // themselves as they could be shown by their EVT_UPDATE_UI handler.
+    if ( win->GetParent() && !win->GetParent()->IsShownOnScreen() )
+        return false;
+
     if (sm_updateInterval == -1)
         return false;
 
@@ -495,9 +509,9 @@ void wxUpdateUIEvent::ResetUpdateTime()
 #endif
 }
 
-/*
- * Scroll events
- */
+// ----------------------------------------------------------------------------
+// wxScrollEvent
+// ----------------------------------------------------------------------------
 
 wxScrollEvent::wxScrollEvent(wxEventType commandType,
                              int id,
@@ -509,9 +523,9 @@ wxScrollEvent::wxScrollEvent(wxEventType commandType,
     m_commandInt = pos;
 }
 
-/*
- * ScrollWin events
- */
+// ----------------------------------------------------------------------------
+// wxScrollWinEvent
+// ----------------------------------------------------------------------------
 
 wxScrollWinEvent::wxScrollWinEvent(wxEventType commandType,
                                    int pos,
@@ -522,10 +536,9 @@ wxScrollWinEvent::wxScrollWinEvent(wxEventType commandType,
     m_commandInt = pos;
 }
 
-/*
- * Mouse events
- *
- */
+// ----------------------------------------------------------------------------
+// wxMouseEvent
+// ----------------------------------------------------------------------------
 
 wxMouseEvent::wxMouseEvent(wxEventType commandType)
 {
@@ -542,10 +555,10 @@ wxMouseEvent::wxMouseEvent(wxEventType commandType)
 
     m_clickCount = -1;
 
+    m_wheelAxis = wxMOUSE_WHEEL_VERTICAL;
     m_wheelRotation = 0;
     m_wheelDelta = 0;
     m_linesPerAction = 0;
-    m_wheelAxis = 0;
 }
 
 void wxMouseEvent::Assign(const wxMouseEvent& event)
@@ -692,34 +705,6 @@ bool wxMouseEvent::Button(int but) const
     }
 }
 
-bool wxMouseEvent::ButtonIsDown(int but) const
-{
-    switch (but)
-    {
-        default:
-            wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonIsDown"));
-            // fall through
-
-        case wxMOUSE_BTN_ANY:
-            return LeftIsDown() || MiddleIsDown() || RightIsDown() || Aux1Down() || Aux2Down();
-
-        case wxMOUSE_BTN_LEFT:
-            return LeftIsDown();
-
-        case wxMOUSE_BTN_MIDDLE:
-            return MiddleIsDown();
-
-        case wxMOUSE_BTN_RIGHT:
-            return RightIsDown();
-
-        case wxMOUSE_BTN_AUX1:
-            return Aux1IsDown();
-
-        case wxMOUSE_BTN_AUX2:
-            return Aux2IsDown();
-    }
-}
-
 int wxMouseEvent::GetButton() const
 {
     for ( int i = 1; i < wxMOUSE_BTN_MAX; i++ )
@@ -740,52 +725,145 @@ wxPoint wxMouseEvent::GetLogicalPosition(const wxDC& dc) const
     return pt;
 }
 
-
-/*
- * Keyboard event
- *
- */
+// ----------------------------------------------------------------------------
+// wxKeyEvent
+// ----------------------------------------------------------------------------
 
 wxKeyEvent::wxKeyEvent(wxEventType type)
 {
     m_eventType = type;
-    m_keyCode = 0;
-    m_scanCode = 0;
+    m_keyCode = WXK_NONE;
 #if wxUSE_UNICODE
-    m_uniChar = 0;
+    m_uniChar = WXK_NONE;
 #endif
+
+    m_x =
+    m_y = wxDefaultCoord;
+    m_hasPosition = false;
+
+    InitPropagation();
 }
 
 wxKeyEvent::wxKeyEvent(const wxKeyEvent& evt)
           : wxEvent(evt),
             wxKeyboardState(evt)
 {
-    m_x = evt.m_x;
-    m_y = evt.m_y;
+    DoAssignMembers(evt);
 
-    m_keyCode = evt.m_keyCode;
+    InitPropagation();
+}
+
+wxKeyEvent::wxKeyEvent(wxEventType eventType, const wxKeyEvent& evt)
+          : wxEvent(evt),
+            wxKeyboardState(evt)
+{
+    DoAssignMembers(evt);
 
-    m_scanCode = evt.m_scanCode;
-    m_rawCode = evt.m_rawCode;
-    m_rawFlags = evt.m_rawFlags;
+    m_eventType = eventType;
 
-#if wxUSE_UNICODE
-    m_uniChar = evt.m_uniChar;
-#endif
+    InitPropagation();
+}
+
+void wxKeyEvent::InitPositionIfNecessary() const
+{
+    if ( m_hasPosition )
+        return;
+
+    // We're const because we're called from const Get[XY]() methods but we
+    // need to update the "cached" values.
+    wxKeyEvent& self = const_cast<wxKeyEvent&>(*this);
+    self.m_hasPosition = true;
+
+    // The only position we can possibly associate with the keyboard event on
+    // the platforms where it doesn't carry it already is the mouse position.
+    wxGetMousePosition(&self.m_x, &self.m_y);
+
+    // If this event is associated with a window, the position should be in its
+    // client coordinates, but otherwise leave it in screen coordinates as what
+    // else can we use?
+    wxWindow* const win = wxDynamicCast(GetEventObject(), wxWindow);
+    if ( win )
+        win->ScreenToClient(&self.m_x, &self.m_y);
+}
+
+wxCoord wxKeyEvent::GetX() const
+{
+    InitPositionIfNecessary();
+
+    return m_x;
+}
+
+wxCoord wxKeyEvent::GetY() const
+{
+    InitPositionIfNecessary();
+
+    return m_y;
 }
 
+bool wxKeyEvent::IsKeyInCategory(int category) const
+{
+    switch ( GetKeyCode() )
+    {
+        case WXK_LEFT:
+        case WXK_RIGHT:
+        case WXK_UP:
+        case WXK_DOWN:
+        case WXK_NUMPAD_LEFT:
+        case WXK_NUMPAD_RIGHT:
+        case WXK_NUMPAD_UP:
+        case WXK_NUMPAD_DOWN:
+            return (category & WXK_CATEGORY_ARROW) != 0;
+
+        case WXK_PAGEDOWN:
+        case WXK_END:
+        case WXK_NUMPAD_PAGEUP:
+        case WXK_NUMPAD_PAGEDOWN:
+            return (category & WXK_CATEGORY_PAGING) != 0;
+
+        case WXK_HOME:
+        case WXK_PAGEUP:
+        case WXK_NUMPAD_HOME:
+        case WXK_NUMPAD_END:
+            return (category & WXK_CATEGORY_JUMP) != 0;
+
+        case WXK_TAB:
+        case WXK_NUMPAD_TAB:
+            return (category & WXK_CATEGORY_TAB) != 0;
+
+        case WXK_BACK:
+        case WXK_DELETE:
+        case WXK_NUMPAD_DELETE:
+            return (category & WXK_CATEGORY_CUT) != 0;
+
+        default:
+            return false;
+    }
+}
+
+// ----------------------------------------------------------------------------
+// wxWindowCreateEvent
+// ----------------------------------------------------------------------------
+
 wxWindowCreateEvent::wxWindowCreateEvent(wxWindow *win)
 {
     SetEventType(wxEVT_CREATE);
     SetEventObject(win);
 }
 
+// ----------------------------------------------------------------------------
+// wxWindowDestroyEvent
+// ----------------------------------------------------------------------------
+
 wxWindowDestroyEvent::wxWindowDestroyEvent(wxWindow *win)
 {
     SetEventType(wxEVT_DESTROY);
     SetEventObject(win);
 }
 
+// ----------------------------------------------------------------------------
+// wxChildFocusEvent
+// ----------------------------------------------------------------------------
+
 wxChildFocusEvent::wxChildFocusEvent(wxWindow *win)
                  : wxCommandEvent(wxEVT_CHILD_FOCUS)
 {
@@ -854,13 +932,12 @@ void wxEventHashTable::Clear()
         delete eTTnode;
     }
 
-    delete[] m_eventTypeTable;
-    m_eventTypeTable = NULL;
+    wxDELETEA(m_eventTypeTable);
 
     m_size = 0;
 }
 
-#if defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING
+#if wxUSE_MEMORY_TRACING
 
 // Clear all tables
 void wxEventHashTable::ClearAll()
@@ -873,7 +950,7 @@ void wxEventHashTable::ClearAll()
     }
 }
 
-#endif // __WXDEBUG__ && wxUSE_MEMORY_TRACING
+#endif // wxUSE_MEMORY_TRACING
 
 bool wxEventHashTable::HandleEvent(wxEvent &event, wxEvtHandler *self)
 {
@@ -927,7 +1004,7 @@ void wxEventHashTable::InitHashTable()
         table = table->baseTable;
     }
 
-    // Lets free some memory.
+    // Let's free some memory.
     size_t i;
     for(i = 0; i < m_size; i++)
     {
@@ -1017,10 +1094,6 @@ void wxEventHashTable::GrowEventTypeTable()
 // wxEvtHandler
 // ----------------------------------------------------------------------------
 
-/*
- * Event handler
- */
-
 wxEvtHandler::wxEvtHandler()
 {
     m_nextHandler = NULL;
@@ -1049,7 +1122,7 @@ wxEvtHandler::~wxEvtHandler()
 
             // Remove ourselves from sink destructor notifications
             // (this has usually been done, in wxTrackable destructor)
-            wxEvtHandler *eventSink = entry->m_fn->GetHandler();
+            wxEvtHandler *eventSink = entry->m_fn->GetEvtHandler();
             if ( eventSink )
             {
                 wxEventConnectionRef * const
@@ -1065,33 +1138,13 @@ wxEvtHandler::~wxEvtHandler()
             delete entry;
         }
         delete m_dynamicEvents;
-    };
-
-    if (m_pendingEvents)
-        m_pendingEvents->DeleteContents(true);
-    delete m_pendingEvents;
-
-    // Remove us from wxHandlersWithPendingEvents if necessary.
-    if ( wxHandlersWithPendingEvents )
-    {
-#if wxUSE_THREADS
-        if (wxHandlersWithPendingEventsLocker)
-            wxENTER_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
-#endif
+    }
 
-        if ( wxHandlersWithPendingEvents->DeleteObject(this) )
-        {
-            // check that we were present only once in the list
-            wxASSERT_MSG( !wxHandlersWithPendingEvents->Find(this),
-                          "Handler occurs twice in wxHandlersWithPendingEvents list" );
-        }
-        //else: we weren't in this list at all, it's ok
+    // Remove us from the list of the pending events if necessary.
+    if (wxTheApp)
+        wxTheApp->RemovePendingEventHandler(this);
 
-#if wxUSE_THREADS
-        if (wxHandlersWithPendingEventsLocker)
-            wxLEAVE_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
-#endif
-    }
+    DeletePendingEvents();
 
     // we only delete object data, not untyped
     if ( m_clientDataType == wxClientData_Object )
@@ -1118,6 +1171,45 @@ bool wxEvtHandler::IsUnlinked() const
            m_nextHandler == NULL;
 }
 
+wxEventFilter* wxEvtHandler::ms_filterList = NULL;
+
+/* static */ void wxEvtHandler::AddFilter(wxEventFilter* filter)
+{
+    wxCHECK_RET( filter, "NULL filter" );
+
+    filter->m_next = ms_filterList;
+    ms_filterList = filter;
+}
+
+/* static */ void wxEvtHandler::RemoveFilter(wxEventFilter* filter)
+{
+    wxEventFilter* prev = NULL;
+    for ( wxEventFilter* f = ms_filterList; f; f = f->m_next )
+    {
+        if ( f == filter )
+        {
+            // Set the previous list element or the list head to the next
+            // element.
+            if ( prev )
+                prev->m_next = f->m_next;
+            else
+                ms_filterList = f->m_next;
+
+            // Also reset the next pointer in the filter itself just to avoid
+            // having possibly dangling pointers, even though it's not strictly
+            // necessary.
+            f->m_next = NULL;
+
+            // Skip the assert below.
+            return;
+        }
+
+        prev = f;
+    }
+
+    wxFAIL_MSG( "Filter not found" );
+}
+
 #if wxUSE_THREADS
 
 bool wxEvtHandler::ProcessThreadEvent(const wxEvent& event)
@@ -1137,25 +1229,30 @@ void wxEvtHandler::QueueEvent(wxEvent *event)
 {
     wxCHECK_RET( event, "NULL event can't be posted" );
 
+    if (!wxTheApp)
+    {
+        // we need an event loop which manages the list of event handlers with
+        // pending events... cannot proceed without it!
+        wxLogDebug("No application object! Cannot queue this event!");
+
+        // anyway delete the given event to avoid memory leaks
+        delete event;
+
+        return;
+    }
+
     // 1) Add this event to our list of pending events
     wxENTER_CRIT_SECT( m_pendingEventsLock );
 
     if ( !m_pendingEvents )
-      m_pendingEvents = new wxList;
+        m_pendingEvents = new wxList;
 
     m_pendingEvents->Append(event);
 
     // 2) Add this event handler to list of event handlers that
     //    have pending events.
 
-    wxENTER_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
-
-    if ( !wxHandlersWithPendingEvents )
-        wxHandlersWithPendingEvents = new wxList;
-    if ( !wxHandlersWithPendingEvents->Find(this) )
-        wxHandlersWithPendingEvents->Append(this);
-
-    wxLEAVE_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
+    wxTheApp->AppendPendingEventHandler(this);
 
     // only release m_pendingEventsLock now because otherwise there is a race
     // condition as described in the ticket #9093: we could process the event
@@ -1170,8 +1267,27 @@ void wxEvtHandler::QueueEvent(wxEvent *event)
     wxWakeUpIdle();
 }
 
+void wxEvtHandler::DeletePendingEvents()
+{
+    if (m_pendingEvents)
+        m_pendingEvents->DeleteContents(true);
+    wxDELETE(m_pendingEvents);
+}
+
 void wxEvtHandler::ProcessPendingEvents()
 {
+    if (!wxTheApp)
+    {
+        // we need an event loop which manages the list of event handlers with
+        // pending events... cannot proceed without it!
+        wxLogDebug("No application object! Cannot process pending events!");
+        return;
+    }
+
+    // we need to process only a single pending event in this call because
+    // each call to ProcessEvent() could result in the destruction of this
+    // same event handler (see the comment at the end of this function)
+
     wxENTER_CRIT_SECT( m_pendingEventsLock );
 
     // this method is only called by wxApp if this handler does have
@@ -1180,26 +1296,44 @@ void wxEvtHandler::ProcessPendingEvents()
                  "should have pending events if called" );
 
     wxList::compatibility_iterator node = m_pendingEvents->GetFirst();
-    wxEventPtr event(static_cast<wxEvent *>(node->GetData()));
+    wxEvent* pEvent = static_cast<wxEvent *>(node->GetData());
+
+    // find the first event which can be processed now:
+    wxEventLoopBase* evtLoop = wxEventLoopBase::GetActive();
+    if (evtLoop && evtLoop->IsYielding())
+    {
+        while (node && pEvent && !evtLoop->IsEventAllowedInsideYield(pEvent->GetEventCategory()))
+        {
+            node = node->GetNext();
+            pEvent = node ? static_cast<wxEvent *>(node->GetData()) : NULL;
+        }
+
+        if (!node)
+        {
+            // all our events are NOT processable now... signal this:
+            wxTheApp->DelayPendingEventHandler(this);
+
+            // see the comment at the beginning of evtloop.h header for the
+            // logic behind YieldFor() and behind DelayPendingEventHandler()
+
+            wxLEAVE_CRIT_SECT( m_pendingEventsLock );
+
+            return;
+        }
+    }
+
+    wxEventPtr event(pEvent);
 
     // it's important we remove event from list before processing it, else a
     // nested event loop, for example from a modal dialog, might process the
     // same event again.
     m_pendingEvents->Erase(node);
 
-    // if there are no more pending events left, we don't need to stay in this
-    // list
     if ( m_pendingEvents->IsEmpty() )
     {
-#if wxUSE_THREADS
-        if (wxHandlersWithPendingEventsLocker)
-            wxENTER_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
-#endif
-        wxHandlersWithPendingEvents->DeleteObject(this);
-#if wxUSE_THREADS
-        if (wxHandlersWithPendingEventsLocker)
-            wxLEAVE_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
-#endif
+        // if there are no more pending events left, we don't need to
+        // stay in this list
+        wxTheApp->RemovePendingEventHandler(this);
     }
 
     wxLEAVE_CRIT_SECT( m_pendingEventsLock );
@@ -1211,13 +1345,10 @@ void wxEvtHandler::ProcessPendingEvents()
     // of this object any more
 }
 
-/*
- * Event table stuff
- */
-/* static */ bool
-wxEvtHandler::ProcessEventIfMatchesId(const wxEventTableEntryBase& entry,
-                                      wxEvtHandler *handler,
-                                      wxEvent& event)
+/* static */
+bool wxEvtHandler::ProcessEventIfMatchesId(const wxEventTableEntryBase& entry,
+                                           wxEvtHandler *handler,
+                                           wxEvent& event)
 {
     int tableId1 = entry.m_id,
         tableId2 = entry.m_lastId;
@@ -1255,15 +1386,8 @@ wxEvtHandler::ProcessEventIfMatchesId(const wxEventTableEntryBase& entry,
     return false;
 }
 
-bool wxEvtHandler::TryParent(wxEvent& event)
+bool wxEvtHandler::DoTryApp(wxEvent& event)
 {
-    if ( GetNextHandler() )
-    {
-        // the next handler will pass it to wxTheApp if it doesn't process it,
-        // so return from here to avoid doing it again
-        return GetNextHandler()->TryParent(event);
-    }
-
     if ( wxTheApp && (this != wxTheApp) )
     {
         // Special case: don't pass wxEVT_IDLE to wxApp, since it'll always
@@ -1279,54 +1403,160 @@ bool wxEvtHandler::TryParent(wxEvent& event)
     return false;
 }
 
+bool wxEvtHandler::TryBefore(wxEvent& event)
+{
+#if WXWIN_COMPATIBILITY_2_8
+    // call the old virtual function to keep the code overriding it working
+    return TryValidator(event);
+#else
+    wxUnusedVar(event);
+    return false;
+#endif
+}
+
+bool wxEvtHandler::TryAfter(wxEvent& event)
+{
+    // We only want to pass the window to the application object once even if
+    // there are several chained handlers. Ensure that this is what happens by
+    // only calling DoTryApp() if there is no next handler (which would do it).
+    //
+    // Notice that, unlike simply calling TryAfter() on the last handler in the
+    // chain only from ProcessEvent(), this also works with wxWindow object in
+    // the middle of the chain: its overridden TryAfter() will still be called
+    // and propagate the event upwards the window hierarchy even if it's not
+    // the last one in the chain (which, admittedly, shouldn't happen often).
+    if ( GetNextHandler() )
+        return GetNextHandler()->TryAfter(event);
+
+#if WXWIN_COMPATIBILITY_2_8
+    // as above, call the old virtual function for compatibility
+    return TryParent(event);
+#else
+    return DoTryApp(event);
+#endif
+}
+
 bool wxEvtHandler::ProcessEvent(wxEvent& event)
 {
-    // allow the application to hook into event processing
+    // The very first thing we do is to allow any registered filters to hook
+    // into event processing in order to globally pre-process all events.
     //
-    // note that we should only do it if we're the first event handler called
+    // Note that we should only do it if we're the first event handler called
     // to avoid calling FilterEvent() multiple times as the event goes through
-    // the event handler chain and possibly upwards the window hierarchy
+    // the event handler chain and possibly upwards the window hierarchy.
     if ( !event.WasProcessed() )
     {
-        if ( wxTheApp )
+        for ( wxEventFilter* f = ms_filterList; f; f = f->m_next )
         {
-            int rc = wxTheApp->FilterEvent(event);
-            if ( rc != -1 )
+            int rc = f->FilterEvent(event);
+            if ( rc != wxEventFilter::Event_Skip )
             {
-                wxASSERT_MSG( rc == 1 || rc == 0,
-                              "unexpected wxApp::FilterEvent return value" );
+                wxASSERT_MSG( rc == wxEventFilter::Event_Ignore ||
+                                rc == wxEventFilter::Event_Processed,
+                              "unexpected FilterEvent() return value" );
 
-                return rc != 0;
+                return rc != wxEventFilter::Event_Ignore;
             }
             //else: proceed normally
         }
     }
 
-    if ( ProcessEventHere(event) )
+    // Short circuit the event processing logic if we're requested to process
+    // this event in this handler only, see DoTryChain() for more details.
+    if ( event.ShouldProcessOnlyIn(this) )
+        return TryBeforeAndHere(event);
+
+
+    // Try to process the event in this handler itself.
+    if ( ProcessEventLocally(event) )
+    {
+        // It is possible that DoTryChain() called from ProcessEventLocally()
+        // returned true but the event was not really processed: this happens
+        // if a custom handler ignores the request to process the event in this
+        // handler only and in this case we should skip the post processing
+        // done in TryAfter() but still return the correct value ourselves to
+        // indicate whether we did or did not find a handler for this event.
+        return !event.GetSkipped();
+    }
+
+    // If we still didn't find a handler, propagate the event upwards the
+    // window chain and/or to the application object.
+    if ( TryAfter(event) )
         return true;
 
-    // pass the event to the next handler, notice that we shouldn't call
-    // TryParent() even if it doesn't handle the event as the last handler in
-    // the chain will do it
-    if ( GetNextHandler() )
-        return GetNextHandler()->ProcessEvent(event);
 
-    // propagate the event upwards the window chain and/or to the application
-    // object if it wasn't processed at this level
-    return TryParent(event);
+    // No handler found anywhere, bail out.
+    return false;
+}
+
+bool wxEvtHandler::ProcessEventLocally(wxEvent& event)
+{
+    // Try the hooks which should be called before our own handlers and this
+    // handler itself first. Notice that we should not call ProcessEvent() on
+    // this one as we're already called from it, which explains why we do it
+    // here and not in DoTryChain()
+    return TryBeforeAndHere(event) || DoTryChain(event);
+}
+
+bool wxEvtHandler::DoTryChain(wxEvent& event)
+{
+    for ( wxEvtHandler *h = GetNextHandler(); h; h = h->GetNextHandler() )
+    {
+        // We need to process this event at the level of this handler only
+        // right now, the pre-/post-processing was either already done by
+        // ProcessEvent() from which we were called or will be done by it when
+        // we return.
+        //
+        // However we must call ProcessEvent() and not TryHereOnly() because the
+        // existing code (including some in wxWidgets itself) expects the
+        // overridden ProcessEvent() in its custom event handlers pushed on a
+        // window to be called.
+        //
+        // So we must call ProcessEvent() but it must not do what it usually
+        // does. To resolve this paradox we set up a special flag inside the
+        // object itself to let ProcessEvent() know that it shouldn't do any
+        // pre/post-processing for this event if it gets it. Note that this
+        // only applies to this handler, if the event is passed to another one
+        // by explicitly calling its ProcessEvent(), pre/post-processing should
+        // be done as usual.
+        //
+        // Final complication is that if the implementation of ProcessEvent()
+        // called wxEvent::DidntHonourProcessOnlyIn() (as the gross hack that
+        // is wxScrollHelperEvtHandler::ProcessEvent() does) and ignored our
+        // request to process event in this handler only, we have to compensate
+        // for it by not processing the event further because this was already
+        // done by that rogue event handler.
+        wxEventProcessInHandlerOnly processInHandlerOnly(event, h);
+        if ( h->ProcessEvent(event) )
+        {
+            // Make sure "skipped" flag is not set as the event was really
+            // processed in this case. Normally it shouldn't be set anyhow but
+            // make sure just in case the user code does something strange.
+            event.Skip(false);
+
+            return true;
+        }
+
+        if ( !event.ShouldProcessOnlyIn(h) )
+        {
+            // Still return true to indicate that no further processing should
+            // be undertaken but ensure that "skipped" flag is set so that the
+            // caller knows that the event was not really processed.
+            event.Skip();
+
+            return true;
+        }
+    }
+
+    return false;
 }
 
-bool wxEvtHandler::ProcessEventHere(wxEvent& event)
+bool wxEvtHandler::TryHereOnly(wxEvent& event)
 {
     // If the event handler is disabled it doesn't process any events
     if ( !GetEvtHandlerEnabled() )
         return false;
 
-    // If we have a validator, it has higher priority than our own event
-    // handlers
-    if ( TryValidator(event) )
-        return true;
-
     // Handle per-instance dynamic event tables first
     if ( m_dynamicEvents && SearchDynamicEventTable(event) )
         return true;
@@ -1335,6 +1565,17 @@ bool wxEvtHandler::ProcessEventHere(wxEvent& event)
     if ( GetEventHashTable().HandleEvent(event, this) )
         return true;
 
+#ifdef wxHAS_CALL_AFTER
+    // There is an implicit entry for async method calls processing in every
+    // event handler:
+    if ( event.GetEventType() == wxEVT_ASYNC_METHOD_CALL &&
+            event.GetEventObject() == this )
+    {
+        static_cast<wxAsyncMethodCallEvent&>(event).Execute();
+        return true;
+    }
+#endif // wxHAS_CALL_AFTER
+
     // We don't have a handler for this event.
     return false;
 }
@@ -1350,9 +1591,15 @@ bool wxEvtHandler::SafelyProcessEvent(wxEvent& event)
     }
     catch ( ... )
     {
-        wxEventLoopBase *loop = wxEventLoopBase::GetActive();
+        // notice that we do it in 2 steps to avoid warnings about possibly
+        // uninitialized loop variable from some versions of g++ which are not
+        // smart enough to figure out that GetActive() doesn't throw and so
+        // that loop will always be initialized
+        wxEventLoopBase *loop = NULL;
         try
         {
+            loop = wxEventLoopBase::GetActive();
+
             if ( !wxTheApp || !wxTheApp->OnExceptionInMainLoop() )
             {
                 if ( loop )
@@ -1375,7 +1622,6 @@ bool wxEvtHandler::SafelyProcessEvent(wxEvent& event)
 #endif // wxUSE_EXCEPTIONS
 }
 
-
 bool wxEvtHandler::SearchEventTable(wxEventTable& table, wxEvent& event)
 {
     const wxEventType eventType = event.GetEventType();
@@ -1392,10 +1638,11 @@ bool wxEvtHandler::SearchEventTable(wxEventTable& table, wxEvent& event)
     return false;
 }
 
-void wxEvtHandler::Subscribe( int id, int lastId,
-                            wxEventType eventType,
-                            wxEventFunctor *func,
-                            wxObject *userData )
+void wxEvtHandler::DoBind(int id,
+                          int lastId,
+                          wxEventType eventType,
+                          wxEventFunctor *func,
+                          wxObject *userData)
 {
     wxDynamicEventTableEntry *entry =
         new wxDynamicEventTableEntry(eventType, id, lastId, func, userData);
@@ -1407,7 +1654,7 @@ void wxEvtHandler::Subscribe( int id, int lastId,
     m_dynamicEvents->Insert( (wxObject*) entry );
 
     // Make sure we get to know when a sink is destroyed
-    wxEvtHandler *eventSink = func->GetHandler();
+    wxEvtHandler *eventSink = func->GetEvtHandler();
     if ( eventSink && eventSink != this )
     {
         wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink);
@@ -1419,24 +1666,15 @@ void wxEvtHandler::Subscribe( int id, int lastId,
 }
 
 bool
-wxEvtHandler::Unsubscribe(int id,
-                          int lastId,
-                          wxEventType eventType,
-                          const wxEventFunctor& func,
-                          wxObject *userData)
+wxEvtHandler::DoUnbind(int id,
+                       int lastId,
+                       wxEventType eventType,
+                       const wxEventFunctor& func,
+                       wxObject *userData)
 {
     if (!m_dynamicEvents)
         return false;
 
-    // Remove connection from tracker node (wxEventConnectionRef)
-    wxEvtHandler *eventSink = func.GetHandler();
-    if ( eventSink && eventSink != this )
-    {
-        wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink);
-        if ( evtConnRef )
-            evtConnRef->DecRef();
-    }
-
     wxList::compatibility_iterator node = m_dynamicEvents->GetFirst();
     while (node)
     {
@@ -1445,9 +1683,18 @@ wxEvtHandler::Unsubscribe(int id,
         if ((entry->m_id == id) &&
             ((entry->m_lastId == lastId) || (lastId == wxID_ANY)) &&
             ((entry->m_eventType == eventType) || (eventType == wxEVT_NULL)) &&
-            entry->m_fn->Matches(func) &&
+            entry->m_fn->IsMatching(func) &&
             ((entry->m_callbackUserData == userData) || !userData))
         {
+            // Remove connection from tracker node (wxEventConnectionRef)
+            wxEvtHandler *eventSink = entry->m_fn->GetEvtHandler();
+            if ( eventSink && eventSink != this )
+            {
+                wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink);
+                if ( evtConnRef )
+                    evtConnRef->DecRef();
+            }
+
             delete entry->m_callbackUserData;
             m_dynamicEvents->Erase( node );
             delete entry;
@@ -1474,7 +1721,7 @@ bool wxEvtHandler::SearchDynamicEventTable( wxEvent& event )
 
         if ( event.GetEventType() == entry->m_eventType )
         {
-            wxEvtHandler *handler = entry->m_fn->GetHandler();
+            wxEvtHandler *handler = entry->m_fn->GetEvtHandler();
             if ( !handler )
                handler = this;
             if ( ProcessEventIfMatchesId(*entry, handler, event) )
@@ -1555,7 +1802,7 @@ void wxEvtHandler::OnSinkDestroyed( wxEvtHandler *sink )
         wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData();
         node_nxt = node->GetNext();
 
-        if ( entry->m_fn->GetHandler() == sink )
+        if ( entry->m_fn->GetEvtHandler() == sink )
         {
             delete entry->m_callbackUserData;
             m_dynamicEvents->Erase( node );