// Author: Julian Smart
// Modified by:
// Created: 01/02/97
-// RCS-ID: $Id$
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#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"
#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
#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)
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
wxEventHashTable wxEvtHandler::sm_eventHashTable(wxEvtHandler::sm_eventTable);
const wxEventTableEntry wxEvtHandler::sm_eventTableEntries[] =
- { DECLARE_EVENT_TABLE_ENTRY(wxEVT_NULL, 0, 0, (wxObjectEventFunction)NULL, NULL) };
+ { wxDECLARE_EVENT_TABLE_TERMINATOR() };
// wxUSE_MEMORY_TRACING considers memory freed from the static objects dtors
// 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
{
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 *wxPendingEvents = NULL;
-
-#if wxUSE_THREADS
- // protects wxPendingEvents list
- wxCriticalSection *wxPendingEventsLocker = 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)
-DEFINE_EVENT_TYPE(wxEVT_IDLE)
-DEFINE_EVENT_TYPE(wxEVT_SOCKET)
-DEFINE_EVENT_TYPE(wxEVT_TIMER)
+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
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_BUTTON_CLICKED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_CHECKBOX_CLICKED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_CHOICE_SELECTED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LISTBOX_SELECTED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_MENU_SELECTED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_SLIDER_UPDATED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_RADIOBOX_SELECTED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_RADIOBUTTON_SELECTED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_SCROLLBAR_UPDATED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_VLBOX_SELECTED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_COMBOBOX_SELECTED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TOOL_RCLICKED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TOOL_ENTER)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPINCTRL_UPDATED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TOOL_DROPDOWN_CLICKED)
+wxDEFINE_EVENT( wxEVT_BUTTON, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_CHECKBOX, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_CHOICE, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_LISTBOX, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_LISTBOX_DCLICK, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_CHECKLISTBOX, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_MENU, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_SLIDER, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_RADIOBOX, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_RADIOBUTTON, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_SCROLLBAR, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_VLBOX, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMBOBOX, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_TOOL_RCLICKED, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_TOOL_ENTER, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_SPINCTRL, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_SPINCTRLDOUBLE, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_TOOL_DROPDOWN, wxCommandEvent );
+wxDEFINE_EVENT( wxEVT_COMBOBOX_DROPDOWN, wxCommandEvent);
+wxDEFINE_EVENT( wxEVT_COMBOBOX_CLOSEUP, wxCommandEvent);
// Mouse event types
-DEFINE_EVENT_TYPE(wxEVT_LEFT_DOWN)
-DEFINE_EVENT_TYPE(wxEVT_LEFT_UP)
-DEFINE_EVENT_TYPE(wxEVT_MIDDLE_DOWN)
-DEFINE_EVENT_TYPE(wxEVT_MIDDLE_UP)
-DEFINE_EVENT_TYPE(wxEVT_RIGHT_DOWN)
-DEFINE_EVENT_TYPE(wxEVT_RIGHT_UP)
-DEFINE_EVENT_TYPE(wxEVT_MOTION)
-DEFINE_EVENT_TYPE(wxEVT_ENTER_WINDOW)
-DEFINE_EVENT_TYPE(wxEVT_LEAVE_WINDOW)
-DEFINE_EVENT_TYPE(wxEVT_LEFT_DCLICK)
-DEFINE_EVENT_TYPE(wxEVT_MIDDLE_DCLICK)
-DEFINE_EVENT_TYPE(wxEVT_RIGHT_DCLICK)
-DEFINE_EVENT_TYPE(wxEVT_SET_FOCUS)
-DEFINE_EVENT_TYPE(wxEVT_KILL_FOCUS)
-DEFINE_EVENT_TYPE(wxEVT_CHILD_FOCUS)
-DEFINE_EVENT_TYPE(wxEVT_MOUSEWHEEL)
-DEFINE_EVENT_TYPE(wxEVT_AUX1_DOWN)
-DEFINE_EVENT_TYPE(wxEVT_AUX1_UP)
-DEFINE_EVENT_TYPE(wxEVT_AUX1_DCLICK)
-DEFINE_EVENT_TYPE(wxEVT_AUX2_DOWN)
-DEFINE_EVENT_TYPE(wxEVT_AUX2_UP)
-DEFINE_EVENT_TYPE(wxEVT_AUX2_DCLICK)
-
-// Non-client mouse events
-DEFINE_EVENT_TYPE(wxEVT_NC_LEFT_DOWN)
-DEFINE_EVENT_TYPE(wxEVT_NC_LEFT_UP)
-DEFINE_EVENT_TYPE(wxEVT_NC_MIDDLE_DOWN)
-DEFINE_EVENT_TYPE(wxEVT_NC_MIDDLE_UP)
-DEFINE_EVENT_TYPE(wxEVT_NC_RIGHT_DOWN)
-DEFINE_EVENT_TYPE(wxEVT_NC_RIGHT_UP)
-DEFINE_EVENT_TYPE(wxEVT_NC_MOTION)
-DEFINE_EVENT_TYPE(wxEVT_NC_ENTER_WINDOW)
-DEFINE_EVENT_TYPE(wxEVT_NC_LEAVE_WINDOW)
-DEFINE_EVENT_TYPE(wxEVT_NC_LEFT_DCLICK)
-DEFINE_EVENT_TYPE(wxEVT_NC_MIDDLE_DCLICK)
-DEFINE_EVENT_TYPE(wxEVT_NC_RIGHT_DCLICK)
+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
-DEFINE_EVENT_TYPE(wxEVT_CHAR)
-DEFINE_EVENT_TYPE(wxEVT_CHAR_HOOK)
-DEFINE_EVENT_TYPE(wxEVT_NAVIGATION_KEY)
-DEFINE_EVENT_TYPE(wxEVT_KEY_DOWN)
-DEFINE_EVENT_TYPE(wxEVT_KEY_UP)
+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
-DEFINE_EVENT_TYPE(wxEVT_HOTKEY)
+wxDEFINE_EVENT( wxEVT_HOTKEY, wxKeyEvent );
#endif
// Set cursor event
-DEFINE_EVENT_TYPE(wxEVT_SET_CURSOR)
+wxDEFINE_EVENT( wxEVT_SET_CURSOR, wxSetCursorEvent );
// wxScrollbar and wxSlider event identifiers
-DEFINE_EVENT_TYPE(wxEVT_SCROLL_TOP)
-DEFINE_EVENT_TYPE(wxEVT_SCROLL_BOTTOM)
-DEFINE_EVENT_TYPE(wxEVT_SCROLL_LINEUP)
-DEFINE_EVENT_TYPE(wxEVT_SCROLL_LINEDOWN)
-DEFINE_EVENT_TYPE(wxEVT_SCROLL_PAGEUP)
-DEFINE_EVENT_TYPE(wxEVT_SCROLL_PAGEDOWN)
-DEFINE_EVENT_TYPE(wxEVT_SCROLL_THUMBTRACK)
-DEFINE_EVENT_TYPE(wxEVT_SCROLL_THUMBRELEASE)
-DEFINE_EVENT_TYPE(wxEVT_SCROLL_CHANGED)
+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
-DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_TOP)
-DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_BOTTOM)
-DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_LINEUP)
-DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_LINEDOWN)
-DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_PAGEUP)
-DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_PAGEDOWN)
-DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_THUMBTRACK)
-DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_THUMBRELEASE)
+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
-DEFINE_EVENT_TYPE(wxEVT_SIZE)
-DEFINE_EVENT_TYPE(wxEVT_SIZING)
-DEFINE_EVENT_TYPE(wxEVT_MOVE)
-DEFINE_EVENT_TYPE(wxEVT_MOVING)
-DEFINE_EVENT_TYPE(wxEVT_MOVE_START)
-DEFINE_EVENT_TYPE(wxEVT_MOVE_END)
-DEFINE_EVENT_TYPE(wxEVT_CLOSE_WINDOW)
-DEFINE_EVENT_TYPE(wxEVT_END_SESSION)
-DEFINE_EVENT_TYPE(wxEVT_QUERY_END_SESSION)
-DEFINE_EVENT_TYPE(wxEVT_HIBERNATE)
-DEFINE_EVENT_TYPE(wxEVT_ACTIVATE_APP)
-DEFINE_EVENT_TYPE(wxEVT_ACTIVATE)
-DEFINE_EVENT_TYPE(wxEVT_CREATE)
-DEFINE_EVENT_TYPE(wxEVT_DESTROY)
-DEFINE_EVENT_TYPE(wxEVT_SHOW)
-DEFINE_EVENT_TYPE(wxEVT_ICONIZE)
-DEFINE_EVENT_TYPE(wxEVT_MAXIMIZE)
-DEFINE_EVENT_TYPE(wxEVT_MOUSE_CAPTURE_CHANGED)
-DEFINE_EVENT_TYPE(wxEVT_MOUSE_CAPTURE_LOST)
-DEFINE_EVENT_TYPE(wxEVT_PAINT)
-DEFINE_EVENT_TYPE(wxEVT_ERASE_BACKGROUND)
-DEFINE_EVENT_TYPE(wxEVT_NC_PAINT)
-DEFINE_EVENT_TYPE(wxEVT_PAINT_ICON)
-DEFINE_EVENT_TYPE(wxEVT_MENU_OPEN)
-DEFINE_EVENT_TYPE(wxEVT_MENU_CLOSE)
-DEFINE_EVENT_TYPE(wxEVT_MENU_HIGHLIGHT)
-DEFINE_EVENT_TYPE(wxEVT_CONTEXT_MENU)
-DEFINE_EVENT_TYPE(wxEVT_SYS_COLOUR_CHANGED)
-DEFINE_EVENT_TYPE(wxEVT_DISPLAY_CHANGED)
-DEFINE_EVENT_TYPE(wxEVT_SETTING_CHANGED)
-DEFINE_EVENT_TYPE(wxEVT_QUERY_NEW_PALETTE)
-DEFINE_EVENT_TYPE(wxEVT_PALETTE_CHANGED)
-DEFINE_EVENT_TYPE(wxEVT_JOY_BUTTON_DOWN)
-DEFINE_EVENT_TYPE(wxEVT_JOY_BUTTON_UP)
-DEFINE_EVENT_TYPE(wxEVT_JOY_MOVE)
-DEFINE_EVENT_TYPE(wxEVT_JOY_ZMOVE)
-DEFINE_EVENT_TYPE(wxEVT_DROP_FILES)
-DEFINE_EVENT_TYPE(wxEVT_DRAW_ITEM)
-DEFINE_EVENT_TYPE(wxEVT_MEASURE_ITEM)
-DEFINE_EVENT_TYPE(wxEVT_COMPARE_ITEM)
-DEFINE_EVENT_TYPE(wxEVT_INIT_DIALOG)
-DEFINE_EVENT_TYPE(wxEVT_UPDATE_UI)
+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
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_COPY)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_CUT)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_PASTE)
+wxDEFINE_EVENT( wxEVT_TEXT_COPY, wxClipboardTextEvent );
+wxDEFINE_EVENT( wxEVT_TEXT_CUT, wxClipboardTextEvent );
+wxDEFINE_EVENT( wxEVT_TEXT_PASTE, wxClipboardTextEvent );
// Generic command events
// Note: a click is a higher-level event than button down/up
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LEFT_CLICK)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LEFT_DCLICK)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_RIGHT_CLICK)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_RIGHT_DCLICK)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_SET_FOCUS)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_KILL_FOCUS)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_ENTER)
+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
-DEFINE_EVENT_TYPE(wxEVT_HELP)
-DEFINE_EVENT_TYPE(wxEVT_DETAILED_HELP)
+wxDEFINE_EVENT( wxEVT_HELP, wxHelpEvent );
+wxDEFINE_EVENT( wxEVT_DETAILED_HELP, wxHelpEvent );
#endif // wxUSE_GUI
return s_lastUsedEventType++;
}
+// ----------------------------------------------------------------------------
+// wxEventFunctor
+// ----------------------------------------------------------------------------
+
+wxEventFunctor::~wxEventFunctor()
+{
+}
// ----------------------------------------------------------------------------
// wxEvent
// ----------------------------------------------------------------------------
/*
- * 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 = (wxObject *) NULL;
+ m_eventObject = NULL;
m_timeStamp = 0;
m_id = theId;
m_skipped = false;
- m_callbackUserData = (wxObject *) NULL;
+ m_callbackUserData = NULL;
+ m_handlerToProcessOnlyIn = NULL;
m_isCommandEvent = false;
m_propagationLevel = wxEVENT_PROPAGATE_NONE;
+ m_propagatedFrom = NULL;
+ m_wasProcessed = false;
+ m_willBeProcessedAgain = false;
}
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_propagatedFrom(NULL)
, m_skipped(src.m_skipped)
, m_isCommandEvent(src.m_isCommandEvent)
+ , m_wasProcessed(false)
+ , m_willBeProcessedAgain(false)
{
}
m_timeStamp = src.m_timeStamp;
m_id = src.m_id;
m_callbackUserData = src.m_callbackUserData;
+ m_handlerToProcessOnlyIn = NULL;
m_propagationLevel = src.m_propagationLevel;
+ m_propagatedFrom = NULL;
m_skipped = src.m_skipped;
m_isCommandEvent = src.m_isCommandEvent;
+ // don't change m_wasProcessed
+
+ // While the original again could be passed to another handler, this one
+ // isn't going to be processed anywhere else by default.
+ m_willBeProcessedAgain = false;
+
return *this;
}
#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 = (char *) NULL;
- m_clientObject = (wxClientData *) NULL;
- m_extraLong = 0;
- m_commandInt = 0;
+ m_clientData = NULL;
+ m_clientObject = NULL;
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)
+ if (m_eventType != wxEVT_TEXT || !m_eventObject)
{
return m_cmdString;
}
}
}
-/*
- * UI update events
- */
+// ----------------------------------------------------------------------------
+// wxUpdateUIEvent
+// ----------------------------------------------------------------------------
#if wxUSE_LONGLONG
wxLongLong wxUpdateUIEvent::sm_lastUpdate = 0;
((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;
#endif
}
-/*
- * Scroll events
- */
+// ----------------------------------------------------------------------------
+// wxScrollEvent
+// ----------------------------------------------------------------------------
wxScrollEvent::wxScrollEvent(wxEventType commandType,
int id,
m_commandInt = pos;
}
-/*
- * ScrollWin events
- */
+// ----------------------------------------------------------------------------
+// wxScrollWinEvent
+// ----------------------------------------------------------------------------
wxScrollWinEvent::wxScrollWinEvent(wxEventType commandType,
int pos,
m_commandInt = pos;
}
-/*
- * Mouse events
- *
- */
+// ----------------------------------------------------------------------------
+// wxMouseEvent
+// ----------------------------------------------------------------------------
wxMouseEvent::wxMouseEvent(wxEventType commandType)
{
m_clickCount = -1;
+ m_wheelAxis = wxMOUSE_WHEEL_VERTICAL;
m_wheelRotation = 0;
m_wheelDelta = 0;
m_linesPerAction = 0;
- m_wheelAxis = 0;
+ m_columnsPerAction = 0;
}
void wxMouseEvent::Assign(const wxMouseEvent& event)
m_wheelRotation = event.m_wheelRotation;
m_wheelDelta = event.m_wheelDelta;
m_linesPerAction = event.m_linesPerAction;
+ m_columnsPerAction = event.m_columnsPerAction;
m_wheelAxis = event.m_wheelAxis;
}
}
}
-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++ )
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);
+
+ InitPropagation();
+}
+
+wxKeyEvent::wxKeyEvent(wxEventType eventType, const wxKeyEvent& evt)
+ : wxEvent(evt),
+ wxKeyboardState(evt)
+{
+ DoAssignMembers(evt);
- m_keyCode = evt.m_keyCode;
+ m_eventType = eventType;
- m_scanCode = evt.m_scanCode;
- m_rawCode = evt.m_rawCode;
- m_rawFlags = evt.m_rawFlags;
+ InitPropagation();
+}
-#if wxUSE_UNICODE
- m_uniChar = evt.m_uniChar;
-#endif
+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)
{
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()
}
}
-#endif // __WXDEBUG__ && wxUSE_MEMORY_TRACING
+#endif // wxUSE_MEMORY_TRACING
bool wxEventHashTable::HandleEvent(wxEvent &event, wxEvtHandler *self)
{
const size_t count = eventEntryTable.GetCount();
for (size_t n = 0; n < count; n++)
{
- if ( wxEvtHandler::
- ProcessEventIfMatches(*eventEntryTable[n], self, event) )
- {
+ const wxEventTableEntry& entry = *eventEntryTable[n];
+ if ( wxEvtHandler::ProcessEventIfMatchesId(entry, self, event) )
return true;
- }
}
}
table = table->baseTable;
}
- // Lets free some memory.
+ // Let's free some memory.
size_t i;
for(i = 0; i < m_size; i++)
{
// wxEvtHandler
// ----------------------------------------------------------------------------
-/*
- * Event handler
- */
-
wxEvtHandler::wxEvtHandler()
{
- m_nextHandler = (wxEvtHandler *) NULL;
- m_previousHandler = (wxEvtHandler *) NULL;
+ m_nextHandler = NULL;
+ m_previousHandler = NULL;
m_enabled = true;
- m_dynamicEvents = (wxList *) NULL;
- m_pendingEvents = (wxList *) NULL;
+ m_dynamicEvents = NULL;
+ m_pendingEvents = NULL;
// no client data (yet)
m_clientData = NULL;
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)
{
wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)*it;
// Remove ourselves from sink destructor notifications
- // (this has usually been been done, in wxTrackable destructor)
- wxEvtHandler *eventSink = entry->m_eventSink;
+ // (this has usually been done, in wxTrackable destructor)
+ wxEvtHandler *eventSink = entry->m_fn->GetEvtHandler();
if ( eventSink )
{
wxEventConnectionRef * const
}
}
- if (entry->m_callbackUserData)
- delete entry->m_callbackUserData;
+ delete entry->m_callbackUserData;
delete entry;
}
delete m_dynamicEvents;
- };
+ }
- if (m_pendingEvents)
- m_pendingEvents->DeleteContents(true);
- delete m_pendingEvents;
+ // Remove us from the list of the pending events if necessary.
+ if (wxTheApp)
+ wxTheApp->RemovePendingEventHandler(this);
- // Remove us from wxPendingEvents if necessary.
- if ( wxPendingEvents )
- {
-#if wxUSE_THREADS
- if (wxPendingEventsLocker)
- wxENTER_CRIT_SECT(*wxPendingEventsLocker);
-#endif
+ DeletePendingEvents();
+
+ // we only delete object data, not untyped
+ if ( m_clientDataType == wxClientData_Object )
+ 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 ( wxPendingEvents->DeleteObject(this) )
+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 )
{
- // check that we were present only once in the list
- wxASSERT_MSG( !wxPendingEvents->Find(this),
- "Handler occurs twice in wxPendingEvents list" );
+ // 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;
}
- //else: we weren't in this list at all, it's ok
-#if wxUSE_THREADS
- if (wxPendingEventsLocker)
- wxLEAVE_CRIT_SECT(*wxPendingEventsLocker);
-#endif
+ prev = f;
}
- // we only delete object data, not untyped
- if ( m_clientDataType == wxClientData_Object )
- delete m_clientObject;
+ wxFAIL_MSG( "Filter not found" );
}
#if wxUSE_THREADS
{
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);
- wxLEAVE_CRIT_SECT( m_pendingEventsLock );
-
// 2) Add this event handler to list of event handlers that
// have pending events.
- wxENTER_CRIT_SECT(*wxPendingEventsLocker);
+ wxTheApp->AppendPendingEventHandler(this);
- if ( !wxPendingEvents )
- wxPendingEvents = new wxList;
- if ( !wxPendingEvents->Find(this) )
- wxPendingEvents->Append(this);
-
- wxLEAVE_CRIT_SECT(*wxPendingEventsLocker);
+ // only release m_pendingEventsLock now because otherwise there is a race
+ // condition as described in the ticket #9093: we could process the event
+ // just added to m_pendingEvents in our ProcessPendingEvents() below before
+ // we had time to append this pointer to wxHandlersWithPendingEvents list; thus
+ // breaking the invariant that a handler should be in the list iff it has
+ // any pending events to process
+ wxLEAVE_CRIT_SECT( m_pendingEventsLock );
// 3) Inform the system that new pending events are somewhere,
// and that these should be processed in idle time.
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
"should have pending events if called" );
wxList::compatibility_iterator node = m_pendingEvents->GetFirst();
- wxEventPtr event(wx_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 (wxPendingEventsLocker)
- wxENTER_CRIT_SECT(*wxPendingEventsLocker);
-#endif
- wxPendingEvents->DeleteObject(this);
-#if wxUSE_THREADS
- if (wxPendingEventsLocker)
- wxLEAVE_CRIT_SECT(*wxPendingEventsLocker);
-#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 );
// of this object any more
}
-/*
- * Event table stuff
- */
-/* static */ bool
-wxEvtHandler::ProcessEventIfMatches(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;
// call the handler via wxApp method which allows the user to catch
// any exceptions which may be thrown by any handler in the program
// in one place
- wxTheApp->HandleEvent(handler, (wxEventFunction)entry.m_fn, event);
+ wxTheApp->CallEventHandler(handler, *entry.m_fn, event);
}
else
#endif // wxUSE_EXCEPTIONS
{
- // no need for an extra virtual function call
- (handler->*((wxEventFunction) (entry.m_fn)))(event);
+ (*entry.m_fn)(handler, event);
}
if (!event.GetSkipped())
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
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 this event is going to be processed in another handler next, don't
+ // pass it to wxTheApp now, it will be done from TryAfter() of this other
+ // handler.
+ if ( event.WillBeProcessedAgain() )
+ return false;
+
+#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
- if ( wxTheApp )
+ // 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
+ // to avoid calling FilterEvent() multiple times as the event goes through
+ // the event handler chain and possibly upwards the window hierarchy.
+ if ( !event.WasProcessed() )
{
- int rc = wxTheApp->FilterEvent(event);
- if ( rc != -1 )
+ for ( wxEventFilter* f = ms_filterList; f; f = f->m_next )
{
- wxASSERT_MSG( rc == 1 || rc == 0,
- _T("unexpected wxApp::FilterEvent return value") );
+ int rc = f->FilterEvent(event);
+ if ( rc != wxEventFilter::Event_Skip )
+ {
+ 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
}
- //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;
- // 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::ProcessEventHere(wxEvent& event)
+bool wxEvtHandler::DoTryChain(wxEvent& event)
{
- // An event handler can be enabled or disabled
- if ( GetEvtHandlerEnabled() )
+ for ( wxEvtHandler *h = GetNextHandler(); h; h = h->GetNextHandler() )
{
- // if we have a validator, it has higher priority than our own event
- // table
- if ( TryValidator(event) )
- return true;
+ // 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);
- // Handle per-instance dynamic event tables first
- if ( m_dynamicEvents && SearchDynamicEventTable(event) )
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();
- // Then static per-class event tables
- if ( GetEventHashTable().HandleEvent(event, this) )
return true;
+ }
}
- // Try going down the event handler chain
- if ( GetNextHandler() && GetNextHandler()->ProcessEventHere(event) )
+ return false;
+}
+
+bool wxEvtHandler::TryHereOnly(wxEvent& event)
+{
+ // If the event handler is disabled it doesn't process any events
+ if ( !GetEvtHandlerEnabled() )
+ return false;
+
+ // Handle per-instance dynamic event tables first
+ if ( m_dynamicEvents && SearchDynamicEventTable(event) )
+ return true;
+
+ // Then static per-class event tables
+ 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;
}
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 )
#endif // wxUSE_EXCEPTIONS
}
-
bool wxEvtHandler::SearchEventTable(wxEventTable& table, wxEvent& event)
{
const wxEventType eventType = event.GetEventType();
const wxEventTableEntry& entry = table.entries[i];
if ( eventType == entry.m_eventType )
{
- if ( ProcessEventIfMatches(entry, this, event) )
+ if ( ProcessEventIfMatchesId(entry, this, event) )
return true;
}
}
return false;
}
-void wxEvtHandler::Connect( int id, int lastId,
- int eventType,
- wxObjectEventFunction func,
- wxObject *userData,
- wxEvtHandler* eventSink )
+void wxEvtHandler::DoBind(int id,
+ int lastId,
+ wxEventType eventType,
+ wxEventFunctor *func,
+ wxObject *userData)
{
wxDynamicEventTableEntry *entry =
- new wxDynamicEventTableEntry(eventType, id, lastId, func, userData, eventSink);
+ new wxDynamicEventTableEntry(eventType, id, lastId, func, userData);
if (!m_dynamicEvents)
m_dynamicEvents = new wxList;
m_dynamicEvents->Insert( (wxObject*) entry );
// Make sure we get to know when a sink is destroyed
+ wxEvtHandler *eventSink = func->GetEvtHandler();
if ( eventSink && eventSink != this )
{
wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink);
}
}
-bool wxEvtHandler::Disconnect( int id, int lastId, wxEventType eventType,
- wxObjectEventFunction func,
- wxObject *userData,
- wxEvtHandler* eventSink )
+bool
+wxEvtHandler::DoUnbind(int id,
+ int lastId,
+ wxEventType eventType,
+ const wxEventFunctor& func,
+ wxObject *userData)
{
if (!m_dynamicEvents)
return false;
- // Remove connection from tracker node (wxEventConnectionRef)
- if ( eventSink && eventSink != this )
- {
- wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink);
- if ( evtConnRef )
- evtConnRef->DecRef();
- }
-
wxList::compatibility_iterator node = m_dynamicEvents->GetFirst();
while (node)
{
if ((entry->m_id == id) &&
((entry->m_lastId == lastId) || (lastId == wxID_ANY)) &&
((entry->m_eventType == eventType) || (eventType == wxEVT_NULL)) &&
- ((entry->m_fn == func) || (func == (wxObjectEventFunction)NULL)) &&
- ((entry->m_eventSink == eventSink) || (eventSink == (wxEvtHandler*)NULL)) &&
- ((entry->m_callbackUserData == userData) || (userData == (wxObject*)NULL)))
+ entry->m_fn->IsMatching(func) &&
+ ((entry->m_callbackUserData == userData) || !userData))
{
- if (entry->m_callbackUserData)
- delete entry->m_callbackUserData;
+ // 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;
return true;
// call Disconnect() invalidating the current node
node = node->GetNext();
- if ((event.GetEventType() == entry->m_eventType) && (entry->m_fn != 0))
+ if ( event.GetEventType() == entry->m_eventType )
{
- wxEvtHandler *handler = entry->m_eventSink ? entry->m_eventSink
- : this;
- if ( ProcessEventIfMatches(*entry, handler, event) )
+ wxEvtHandler *handler = entry->m_fn->GetEvtHandler();
+ if ( !handler )
+ handler = this;
+ if ( ProcessEventIfMatchesId(*entry, handler, event) )
return true;
}
}
wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData();
node_nxt = node->GetNext();
- if ( entry->m_eventSink==sink )
+ if ( entry->m_fn->GetEvtHandler() == sink )
{
- if (entry->m_callbackUserData)
- delete entry->m_callbackUserData;
+ delete entry->m_callbackUserData;
m_dynamicEvents->Erase( node );
delete entry;
}
else
win = win->GetParent();
}
- if (win == (wxWindow*) NULL)
- focusWin = (wxWindow*) NULL;
+ if (win == NULL)
+ focusWin = NULL;
return focusWin;
}
}
#endif // wxUSE_GUI
+