1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/event.cpp
3 // Purpose:     Event classes
4 // Author:      Julian Smart
5 // Modified by:
6 // Created:     01/02/97
7 // Copyright:   (c) Julian Smart
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // ============================================================================
12 // declarations
13 // ============================================================================
14 
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18 
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21 
22 
23 #include "wx/event.h"
24 #include "wx/eventfilter.h"
25 #include "wx/evtloop.h"
26 
27 #ifndef WX_PRECOMP
28     #include "wx/list.h"
29     #include "wx/log.h"
30     #include "wx/app.h"
31     #include "wx/utils.h"
32     #include "wx/stopwatch.h"
33     #include "wx/module.h"
34 
35     #if wxUSE_GUI
36         #include "wx/window.h"
37         #include "wx/control.h"
38         #include "wx/dc.h"
39         #include "wx/spinbutt.h"
40         #include "wx/textentry.h"
41         #include "wx/validate.h"
42     #endif // wxUSE_GUI
43 #endif
44 
45 #include "wx/thread.h"
46 
47 #if wxUSE_BASE
48     #include "wx/scopedptr.h"
49 
50     wxDECLARE_SCOPED_PTR(wxEvent, wxEventPtr)
51     wxDEFINE_SCOPED_PTR(wxEvent, wxEventPtr)
52 #endif // wxUSE_BASE
53 
54 // ----------------------------------------------------------------------------
55 // wxWin macros
56 // ----------------------------------------------------------------------------
57 
58 #if wxUSE_BASE
59     wxIMPLEMENT_DYNAMIC_CLASS(wxEvtHandler, wxObject);
60     wxIMPLEMENT_ABSTRACT_CLASS(wxEvent, wxObject);
61     wxIMPLEMENT_DYNAMIC_CLASS(wxIdleEvent, wxEvent);
62     wxIMPLEMENT_DYNAMIC_CLASS(wxThreadEvent, wxEvent);
63 #endif // wxUSE_BASE
64 
65 #if wxUSE_GUI
66     wxIMPLEMENT_DYNAMIC_CLASS(wxCommandEvent, wxEvent);
67     wxIMPLEMENT_DYNAMIC_CLASS(wxNotifyEvent, wxCommandEvent);
68     wxIMPLEMENT_DYNAMIC_CLASS(wxScrollEvent, wxCommandEvent);
69     wxIMPLEMENT_DYNAMIC_CLASS(wxScrollWinEvent, wxEvent);
70     wxIMPLEMENT_DYNAMIC_CLASS(wxMouseEvent, wxEvent);
71     wxIMPLEMENT_DYNAMIC_CLASS(wxKeyEvent, wxEvent);
72     wxIMPLEMENT_DYNAMIC_CLASS(wxSizeEvent, wxEvent);
73     wxIMPLEMENT_DYNAMIC_CLASS(wxPaintEvent, wxEvent);
74     wxIMPLEMENT_DYNAMIC_CLASS(wxNcPaintEvent, wxEvent);
75     wxIMPLEMENT_DYNAMIC_CLASS(wxEraseEvent, wxEvent);
76     wxIMPLEMENT_DYNAMIC_CLASS(wxMoveEvent, wxEvent);
77     wxIMPLEMENT_DYNAMIC_CLASS(wxFocusEvent, wxEvent);
78     wxIMPLEMENT_DYNAMIC_CLASS(wxChildFocusEvent, wxCommandEvent);
79     wxIMPLEMENT_DYNAMIC_CLASS(wxCloseEvent, wxEvent);
80     wxIMPLEMENT_DYNAMIC_CLASS(wxShowEvent, wxEvent);
81     wxIMPLEMENT_DYNAMIC_CLASS(wxMaximizeEvent, wxEvent);
82     wxIMPLEMENT_DYNAMIC_CLASS(wxIconizeEvent, wxEvent);
83     wxIMPLEMENT_DYNAMIC_CLASS(wxFullScreenEvent, wxEvent);
84     wxIMPLEMENT_DYNAMIC_CLASS(wxMenuEvent, wxEvent);
85     wxIMPLEMENT_DYNAMIC_CLASS(wxJoystickEvent, wxEvent);
86     wxIMPLEMENT_DYNAMIC_CLASS(wxDropFilesEvent, wxEvent);
87     wxIMPLEMENT_DYNAMIC_CLASS(wxActivateEvent, wxEvent);
88     wxIMPLEMENT_DYNAMIC_CLASS(wxInitDialogEvent, wxEvent);
89     wxIMPLEMENT_DYNAMIC_CLASS(wxSetCursorEvent, wxEvent);
90     wxIMPLEMENT_DYNAMIC_CLASS(wxSysColourChangedEvent, wxEvent);
91     wxIMPLEMENT_DYNAMIC_CLASS(wxDisplayChangedEvent, wxEvent);
92     wxIMPLEMENT_DYNAMIC_CLASS(wxDPIChangedEvent, wxEvent);
93     wxIMPLEMENT_DYNAMIC_CLASS(wxUpdateUIEvent, wxCommandEvent);
94     wxIMPLEMENT_DYNAMIC_CLASS(wxNavigationKeyEvent, wxEvent);
95     wxIMPLEMENT_DYNAMIC_CLASS(wxPaletteChangedEvent, wxEvent);
96     wxIMPLEMENT_DYNAMIC_CLASS(wxQueryNewPaletteEvent, wxEvent);
97     wxIMPLEMENT_DYNAMIC_CLASS(wxWindowCreateEvent, wxEvent);
98     wxIMPLEMENT_DYNAMIC_CLASS(wxWindowDestroyEvent, wxEvent);
99     wxIMPLEMENT_DYNAMIC_CLASS(wxHelpEvent, wxCommandEvent);
100     wxIMPLEMENT_DYNAMIC_CLASS(wxContextMenuEvent, wxCommandEvent);
101     wxIMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureChangedEvent, wxEvent);
102     wxIMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureLostEvent, wxEvent);
103     wxIMPLEMENT_DYNAMIC_CLASS(wxClipboardTextEvent, wxCommandEvent);
104     wxIMPLEMENT_DYNAMIC_CLASS(wxGestureEvent, wxEvent);
105     wxIMPLEMENT_DYNAMIC_CLASS(wxPanGestureEvent, wxGestureEvent);
106     wxIMPLEMENT_DYNAMIC_CLASS(wxZoomGestureEvent, wxGestureEvent);
107     wxIMPLEMENT_DYNAMIC_CLASS(wxRotateGestureEvent, wxGestureEvent);
108     wxIMPLEMENT_DYNAMIC_CLASS(wxTwoFingerTapEvent, wxGestureEvent);
109     wxIMPLEMENT_DYNAMIC_CLASS(wxLongPressEvent, wxGestureEvent);
110     wxIMPLEMENT_DYNAMIC_CLASS(wxPressAndTapEvent, wxGestureEvent);
111 #endif // wxUSE_GUI
112 
113 #if wxUSE_BASE
114 
GetEventTable() const115 const wxEventTable *wxEvtHandler::GetEventTable() const
116     { return &wxEvtHandler::sm_eventTable; }
117 
118 const wxEventTable wxEvtHandler::sm_eventTable =
119     { (const wxEventTable *)NULL, &wxEvtHandler::sm_eventTableEntries[0] };
120 
GetEventHashTable() const121 wxEventHashTable &wxEvtHandler::GetEventHashTable() const
122     { return wxEvtHandler::sm_eventHashTable; }
123 
124 wxEventHashTable wxEvtHandler::sm_eventHashTable(wxEvtHandler::sm_eventTable);
125 
126 const wxEventTableEntry wxEvtHandler::sm_eventTableEntries[] =
127     { wxDECLARE_EVENT_TABLE_TERMINATOR() };
128 
129 
130 // wxUSE_MEMORY_TRACING considers memory freed from the static objects dtors
131 // leaked, so we need to manually clean up all event tables before checking for
132 // the memory leaks when using it, however this breaks re-initializing the
133 // library (i.e. repeated calls to wxInitialize/wxUninitialize) because the
134 // event tables won't be rebuilt the next time, so disable this by default
135 #if wxUSE_MEMORY_TRACING
136 
137 class wxEventTableEntryModule: public wxModule
138 {
139 public:
wxEventTableEntryModule()140     wxEventTableEntryModule() { }
OnInit()141     virtual bool OnInit() wxOVERRIDE { return true; }
OnExit()142     virtual void OnExit() wxOVERRIDE { wxEventHashTable::ClearAll(); }
143 
144     wxDECLARE_DYNAMIC_CLASS(wxEventTableEntryModule);
145 };
146 
147 wxIMPLEMENT_DYNAMIC_CLASS(wxEventTableEntryModule, wxModule);
148 
149 #endif // wxUSE_MEMORY_TRACING
150 
151 // ----------------------------------------------------------------------------
152 // global variables
153 // ----------------------------------------------------------------------------
154 
155 // common event types are defined here, other event types are defined by the
156 // components which use them
157 
158 const wxEventType wxEVT_FIRST = 10000;
159 const wxEventType wxEVT_USER_FIRST = wxEVT_FIRST + 2000;
160 const wxEventType wxEVT_NULL = wxNewEventType();
161 
162 wxDEFINE_EVENT( wxEVT_IDLE, wxIdleEvent );
163 
164 // Thread and asynchronous call events
165 wxDEFINE_EVENT( wxEVT_THREAD, wxThreadEvent );
166 wxDEFINE_EVENT( wxEVT_ASYNC_METHOD_CALL, wxAsyncMethodCallEvent );
167 
168 #endif // wxUSE_BASE
169 
170 #if wxUSE_GUI
171 
172 wxDEFINE_EVENT( wxEVT_BUTTON, wxCommandEvent );
173 wxDEFINE_EVENT( wxEVT_CHECKBOX, wxCommandEvent );
174 wxDEFINE_EVENT( wxEVT_CHOICE, wxCommandEvent );
175 wxDEFINE_EVENT( wxEVT_LISTBOX, wxCommandEvent );
176 wxDEFINE_EVENT( wxEVT_LISTBOX_DCLICK, wxCommandEvent );
177 wxDEFINE_EVENT( wxEVT_CHECKLISTBOX, wxCommandEvent );
178 wxDEFINE_EVENT( wxEVT_MENU, wxCommandEvent );
179 wxDEFINE_EVENT( wxEVT_SLIDER, wxCommandEvent );
180 wxDEFINE_EVENT( wxEVT_RADIOBOX, wxCommandEvent );
181 wxDEFINE_EVENT( wxEVT_RADIOBUTTON, wxCommandEvent );
182 wxDEFINE_EVENT( wxEVT_SCROLLBAR, wxCommandEvent );
183 wxDEFINE_EVENT( wxEVT_VLBOX, wxCommandEvent );
184 wxDEFINE_EVENT( wxEVT_COMBOBOX, wxCommandEvent );
185 wxDEFINE_EVENT( wxEVT_TOOL_RCLICKED, wxCommandEvent );
186 wxDEFINE_EVENT( wxEVT_TOOL_ENTER, wxCommandEvent );
187 wxDEFINE_EVENT( wxEVT_TOOL_DROPDOWN, wxCommandEvent );
188 wxDEFINE_EVENT( wxEVT_COMBOBOX_DROPDOWN, wxCommandEvent);
189 wxDEFINE_EVENT( wxEVT_COMBOBOX_CLOSEUP, wxCommandEvent);
190 
191 // Mouse event types
192 wxDEFINE_EVENT( wxEVT_LEFT_DOWN, wxMouseEvent );
193 wxDEFINE_EVENT( wxEVT_LEFT_UP, wxMouseEvent );
194 wxDEFINE_EVENT( wxEVT_MIDDLE_DOWN, wxMouseEvent );
195 wxDEFINE_EVENT( wxEVT_MIDDLE_UP, wxMouseEvent );
196 wxDEFINE_EVENT( wxEVT_RIGHT_DOWN, wxMouseEvent );
197 wxDEFINE_EVENT( wxEVT_RIGHT_UP, wxMouseEvent );
198 wxDEFINE_EVENT( wxEVT_MOTION, wxMouseEvent );
199 wxDEFINE_EVENT( wxEVT_ENTER_WINDOW, wxMouseEvent );
200 wxDEFINE_EVENT( wxEVT_LEAVE_WINDOW, wxMouseEvent );
201 wxDEFINE_EVENT( wxEVT_LEFT_DCLICK, wxMouseEvent );
202 wxDEFINE_EVENT( wxEVT_MIDDLE_DCLICK, wxMouseEvent );
203 wxDEFINE_EVENT( wxEVT_RIGHT_DCLICK, wxMouseEvent );
204 wxDEFINE_EVENT( wxEVT_SET_FOCUS, wxFocusEvent );
205 wxDEFINE_EVENT( wxEVT_KILL_FOCUS, wxFocusEvent );
206 wxDEFINE_EVENT( wxEVT_CHILD_FOCUS, wxChildFocusEvent );
207 wxDEFINE_EVENT( wxEVT_MOUSEWHEEL, wxMouseEvent );
208 wxDEFINE_EVENT( wxEVT_AUX1_DOWN, wxMouseEvent );
209 wxDEFINE_EVENT( wxEVT_AUX1_UP, wxMouseEvent );
210 wxDEFINE_EVENT( wxEVT_AUX1_DCLICK, wxMouseEvent );
211 wxDEFINE_EVENT( wxEVT_AUX2_DOWN, wxMouseEvent );
212 wxDEFINE_EVENT( wxEVT_AUX2_UP, wxMouseEvent );
213 wxDEFINE_EVENT( wxEVT_AUX2_DCLICK, wxMouseEvent );
214 wxDEFINE_EVENT( wxEVT_MAGNIFY, wxMouseEvent );
215 
216 // Character input event type
217 wxDEFINE_EVENT( wxEVT_CHAR, wxKeyEvent );
218 wxDEFINE_EVENT( wxEVT_AFTER_CHAR, wxKeyEvent );
219 wxDEFINE_EVENT( wxEVT_CHAR_HOOK, wxKeyEvent );
220 wxDEFINE_EVENT( wxEVT_NAVIGATION_KEY, wxNavigationKeyEvent );
221 wxDEFINE_EVENT( wxEVT_KEY_DOWN, wxKeyEvent );
222 wxDEFINE_EVENT( wxEVT_KEY_UP, wxKeyEvent );
223 #if wxUSE_HOTKEY
224 wxDEFINE_EVENT( wxEVT_HOTKEY, wxKeyEvent );
225 #endif
226 
227 // Set cursor event
228 wxDEFINE_EVENT( wxEVT_SET_CURSOR, wxSetCursorEvent );
229 
230 // wxScrollbar and wxSlider event identifiers
231 wxDEFINE_EVENT( wxEVT_SCROLL_TOP, wxScrollEvent );
232 wxDEFINE_EVENT( wxEVT_SCROLL_BOTTOM, wxScrollEvent );
233 wxDEFINE_EVENT( wxEVT_SCROLL_LINEUP, wxScrollEvent );
234 wxDEFINE_EVENT( wxEVT_SCROLL_LINEDOWN, wxScrollEvent );
235 wxDEFINE_EVENT( wxEVT_SCROLL_PAGEUP, wxScrollEvent );
236 wxDEFINE_EVENT( wxEVT_SCROLL_PAGEDOWN, wxScrollEvent );
237 wxDEFINE_EVENT( wxEVT_SCROLL_THUMBTRACK, wxScrollEvent );
238 wxDEFINE_EVENT( wxEVT_SCROLL_THUMBRELEASE, wxScrollEvent );
239 wxDEFINE_EVENT( wxEVT_SCROLL_CHANGED, wxScrollEvent );
240 
241 // Due to a bug in older wx versions, wxSpinEvents were being sent with type of
242 // wxEVT_SCROLL_LINEUP, wxEVT_SCROLL_LINEDOWN and wxEVT_SCROLL_THUMBTRACK. But
243 // with the type-safe events in place, these event types are associated with
244 // wxScrollEvent. To allow handling of spin events, new event types have been
245 // defined in spinbutt.h/spinnbuttcmn.cpp. To maintain backward compatibility
246 // the spin event types are being initialized with the scroll event types.
247 
248 #if wxUSE_SPINBTN
249 
250 wxDEFINE_EVENT_ALIAS( wxEVT_SPIN_UP,   wxSpinEvent, wxEVT_SCROLL_LINEUP );
251 wxDEFINE_EVENT_ALIAS( wxEVT_SPIN_DOWN, wxSpinEvent, wxEVT_SCROLL_LINEDOWN );
252 wxDEFINE_EVENT_ALIAS( wxEVT_SPIN,      wxSpinEvent, wxEVT_SCROLL_THUMBTRACK );
253 
254 #endif // wxUSE_SPINBTN
255 
256 // Scroll events from wxWindow
257 wxDEFINE_EVENT( wxEVT_SCROLLWIN_TOP, wxScrollWinEvent );
258 wxDEFINE_EVENT( wxEVT_SCROLLWIN_BOTTOM, wxScrollWinEvent );
259 wxDEFINE_EVENT( wxEVT_SCROLLWIN_LINEUP, wxScrollWinEvent );
260 wxDEFINE_EVENT( wxEVT_SCROLLWIN_LINEDOWN, wxScrollWinEvent );
261 wxDEFINE_EVENT( wxEVT_SCROLLWIN_PAGEUP, wxScrollWinEvent );
262 wxDEFINE_EVENT( wxEVT_SCROLLWIN_PAGEDOWN, wxScrollWinEvent );
263 wxDEFINE_EVENT( wxEVT_SCROLLWIN_THUMBTRACK, wxScrollWinEvent );
264 wxDEFINE_EVENT( wxEVT_SCROLLWIN_THUMBRELEASE, wxScrollWinEvent );
265 
266 // Gesture events
267 wxDEFINE_EVENT( wxEVT_GESTURE_PAN, wxPanGestureEvent );
268 wxDEFINE_EVENT( wxEVT_GESTURE_ZOOM, wxZoomGestureEvent );
269 wxDEFINE_EVENT( wxEVT_GESTURE_ROTATE, wxRotateGestureEvent );
270 wxDEFINE_EVENT( wxEVT_TWO_FINGER_TAP, wxTwoFingerTapEvent );
271 wxDEFINE_EVENT( wxEVT_LONG_PRESS, wxLongPressEvent );
272 wxDEFINE_EVENT( wxEVT_PRESS_AND_TAP, wxPressAndTapEvent );
273 
274 // System events
275 wxDEFINE_EVENT( wxEVT_SIZE, wxSizeEvent );
276 wxDEFINE_EVENT( wxEVT_SIZING, wxSizeEvent );
277 wxDEFINE_EVENT( wxEVT_MOVE, wxMoveEvent );
278 wxDEFINE_EVENT( wxEVT_MOVING, wxMoveEvent );
279 wxDEFINE_EVENT( wxEVT_MOVE_START, wxMoveEvent );
280 wxDEFINE_EVENT( wxEVT_MOVE_END, wxMoveEvent );
281 wxDEFINE_EVENT( wxEVT_CLOSE_WINDOW, wxCloseEvent );
282 wxDEFINE_EVENT( wxEVT_END_SESSION, wxCloseEvent );
283 wxDEFINE_EVENT( wxEVT_QUERY_END_SESSION, wxCloseEvent );
284 wxDEFINE_EVENT( wxEVT_HIBERNATE, wxActivateEvent );
285 wxDEFINE_EVENT( wxEVT_ACTIVATE_APP, wxActivateEvent );
286 wxDEFINE_EVENT( wxEVT_ACTIVATE, wxActivateEvent );
287 wxDEFINE_EVENT( wxEVT_CREATE, wxWindowCreateEvent );
288 wxDEFINE_EVENT( wxEVT_DESTROY, wxWindowDestroyEvent );
289 wxDEFINE_EVENT( wxEVT_SHOW, wxShowEvent );
290 wxDEFINE_EVENT( wxEVT_ICONIZE, wxIconizeEvent );
291 wxDEFINE_EVENT( wxEVT_MAXIMIZE, wxMaximizeEvent );
292 wxDEFINE_EVENT( wxEVT_FULLSCREEN, wxFullScreenEvent );
293 wxDEFINE_EVENT( wxEVT_MOUSE_CAPTURE_CHANGED, wxMouseCaptureChangedEvent );
294 wxDEFINE_EVENT( wxEVT_MOUSE_CAPTURE_LOST, wxMouseCaptureLostEvent );
295 wxDEFINE_EVENT( wxEVT_PAINT, wxPaintEvent );
296 wxDEFINE_EVENT( wxEVT_ERASE_BACKGROUND, wxEraseEvent );
297 wxDEFINE_EVENT( wxEVT_NC_PAINT, wxNcPaintEvent );
298 wxDEFINE_EVENT( wxEVT_MENU_OPEN, wxMenuEvent );
299 wxDEFINE_EVENT( wxEVT_MENU_CLOSE, wxMenuEvent );
300 wxDEFINE_EVENT( wxEVT_MENU_HIGHLIGHT, wxMenuEvent );
301 wxDEFINE_EVENT( wxEVT_CONTEXT_MENU, wxContextMenuEvent );
302 wxDEFINE_EVENT( wxEVT_SYS_COLOUR_CHANGED, wxSysColourChangedEvent );
303 wxDEFINE_EVENT( wxEVT_DISPLAY_CHANGED, wxDisplayChangedEvent );
304 wxDEFINE_EVENT( wxEVT_DPI_CHANGED, wxDPIChangedEvent );
305 wxDEFINE_EVENT( wxEVT_QUERY_NEW_PALETTE, wxQueryNewPaletteEvent );
306 wxDEFINE_EVENT( wxEVT_PALETTE_CHANGED, wxPaletteChangedEvent );
307 wxDEFINE_EVENT( wxEVT_JOY_BUTTON_DOWN, wxJoystickEvent );
308 wxDEFINE_EVENT( wxEVT_JOY_BUTTON_UP, wxJoystickEvent );
309 wxDEFINE_EVENT( wxEVT_JOY_MOVE, wxJoystickEvent );
310 wxDEFINE_EVENT( wxEVT_JOY_ZMOVE, wxJoystickEvent );
311 wxDEFINE_EVENT( wxEVT_DROP_FILES, wxDropFilesEvent );
312 wxDEFINE_EVENT( wxEVT_INIT_DIALOG, wxInitDialogEvent );
313 wxDEFINE_EVENT( wxEVT_UPDATE_UI, wxUpdateUIEvent );
314 
315 // Clipboard events
316 wxDEFINE_EVENT( wxEVT_TEXT_COPY, wxClipboardTextEvent );
317 wxDEFINE_EVENT( wxEVT_TEXT_CUT, wxClipboardTextEvent );
318 wxDEFINE_EVENT( wxEVT_TEXT_PASTE, wxClipboardTextEvent );
319 
320 // Generic command events
321 // Note: a click is a higher-level event than button down/up
322 wxDEFINE_EVENT( wxEVT_COMMAND_LEFT_CLICK, wxCommandEvent );
323 wxDEFINE_EVENT( wxEVT_COMMAND_LEFT_DCLICK, wxCommandEvent );
324 wxDEFINE_EVENT( wxEVT_COMMAND_RIGHT_CLICK, wxCommandEvent );
325 wxDEFINE_EVENT( wxEVT_COMMAND_RIGHT_DCLICK, wxCommandEvent );
326 wxDEFINE_EVENT( wxEVT_COMMAND_SET_FOCUS, wxCommandEvent );
327 wxDEFINE_EVENT( wxEVT_COMMAND_KILL_FOCUS, wxCommandEvent );
328 wxDEFINE_EVENT( wxEVT_COMMAND_ENTER, wxCommandEvent );
329 
330 // Help events
331 wxDEFINE_EVENT( wxEVT_HELP, wxHelpEvent );
332 wxDEFINE_EVENT( wxEVT_DETAILED_HELP, wxHelpEvent );
333 
334 #endif // wxUSE_GUI
335 
336 #if wxUSE_BASE
337 
338 wxIdleMode wxIdleEvent::sm_idleMode = wxIDLE_PROCESS_ALL;
339 
340 // ============================================================================
341 // implementation
342 // ============================================================================
343 
344 // ----------------------------------------------------------------------------
345 // event initialization
346 // ----------------------------------------------------------------------------
347 
wxNewEventType()348 int wxNewEventType()
349 {
350     // MT-FIXME
351     static int s_lastUsedEventType = wxEVT_FIRST;
352 
353     return s_lastUsedEventType++;
354 }
355 // ----------------------------------------------------------------------------
356 // wxEventFunctor
357 // ----------------------------------------------------------------------------
358 
~wxEventFunctor()359 wxEventFunctor::~wxEventFunctor()
360 {
361 }
362 
363 // ----------------------------------------------------------------------------
364 // wxEvent
365 // ----------------------------------------------------------------------------
366 
367 /*
368  * General wxWidgets events, covering all interesting things that might happen
369  * (button clicking, resizing, setting text in widgets, etc.).
370  *
371  * For each completely new event type, derive a new event class.
372  *
373  */
374 
wxEvent(int theId,wxEventType commandType)375 wxEvent::wxEvent(int theId, wxEventType commandType)
376     : m_eventType(commandType)
377 {
378     m_eventObject = NULL;
379     m_timeStamp = 0;
380     m_id = theId;
381     m_skipped = false;
382     m_callbackUserData = NULL;
383     m_handlerToProcessOnlyIn = NULL;
384     m_isCommandEvent = false;
385     m_propagationLevel = wxEVENT_PROPAGATE_NONE;
386     m_propagatedFrom = NULL;
387     m_wasProcessed = false;
388     m_willBeProcessedAgain = false;
389 }
390 
wxEvent(const wxEvent & src)391 wxEvent::wxEvent(const wxEvent& src)
392     : wxObject(src)
393     , m_eventObject(src.m_eventObject)
394     , m_eventType(src.m_eventType)
395     , m_timeStamp(src.m_timeStamp)
396     , m_id(src.m_id)
397     , m_callbackUserData(src.m_callbackUserData)
398     , m_handlerToProcessOnlyIn(NULL)
399     , m_propagationLevel(src.m_propagationLevel)
400     , m_propagatedFrom(NULL)
401     , m_skipped(src.m_skipped)
402     , m_isCommandEvent(src.m_isCommandEvent)
403     , m_wasProcessed(false)
404     , m_willBeProcessedAgain(false)
405 {
406 }
407 
operator =(const wxEvent & src)408 wxEvent& wxEvent::operator=(const wxEvent& src)
409 {
410     wxObject::operator=(src);
411 
412     m_eventObject = src.m_eventObject;
413     m_eventType = src.m_eventType;
414     m_timeStamp = src.m_timeStamp;
415     m_id = src.m_id;
416     m_callbackUserData = src.m_callbackUserData;
417     m_handlerToProcessOnlyIn = NULL;
418     m_propagationLevel = src.m_propagationLevel;
419     m_propagatedFrom = NULL;
420     m_skipped = src.m_skipped;
421     m_isCommandEvent = src.m_isCommandEvent;
422 
423     // don't change m_wasProcessed
424 
425     // While the original again could be passed to another handler, this one
426     // isn't going to be processed anywhere else by default.
427     m_willBeProcessedAgain = false;
428 
429     return *this;
430 }
431 
432 #endif // wxUSE_BASE
433 
434 #if wxUSE_GUI
435 
436 // ----------------------------------------------------------------------------
437 // wxCommandEvent
438 // ----------------------------------------------------------------------------
439 
GetString() const440 wxString wxCommandEvent::GetString() const
441 {
442     // This is part of the hack retrieving the event string from the control
443     // itself only when/if it's really needed to avoid copying potentially huge
444     // strings coming from multiline text controls.
445     if (m_eventType == wxEVT_TEXT && m_eventObject)
446     {
447         // Only windows generate wxEVT_TEXT events, so this cast should really
448         // succeed, but err on the side of caution just in case somebody
449         // created a bogus event of this type.
450         if ( wxWindow* const w = wxDynamicCast(m_eventObject, wxWindow) )
451         {
452             if ( const wxTextEntry* const entry = w->WXGetTextEntry() )
453                 return entry->GetValue();
454         }
455     }
456 
457     return m_cmdString;
458 }
459 
460 // ----------------------------------------------------------------------------
461 // wxPaintEvent and wxNcPaintEvent
462 // ----------------------------------------------------------------------------
463 
wxPaintEvent(wxWindowBase * window)464 wxPaintEvent::wxPaintEvent(wxWindowBase* window)
465     : wxEvent(window ? window->GetId() : 0, wxEVT_PAINT)
466 {
467     SetEventObject(window);
468 }
469 
wxNcPaintEvent(wxWindowBase * window)470 wxNcPaintEvent::wxNcPaintEvent(wxWindowBase* window)
471     : wxEvent(window ? window->GetId() : 0, wxEVT_NC_PAINT)
472 {
473     SetEventObject(window);
474 }
475 
476 // ----------------------------------------------------------------------------
477 // wxUpdateUIEvent
478 // ----------------------------------------------------------------------------
479 
480 #if wxUSE_LONGLONG
481 wxLongLong wxUpdateUIEvent::sm_lastUpdate = 0;
482 #endif
483 
484 long wxUpdateUIEvent::sm_updateInterval = 0;
485 
486 wxUpdateUIMode wxUpdateUIEvent::sm_updateMode = wxUPDATE_UI_PROCESS_ALL;
487 
488 // Can we update?
CanUpdate(wxWindowBase * win)489 bool wxUpdateUIEvent::CanUpdate(wxWindowBase *win)
490 {
491     // Don't update if we've switched global updating off
492     // and this window doesn't support updates.
493     if (win &&
494        (GetMode() == wxUPDATE_UI_PROCESS_SPECIFIED &&
495        ((win->GetExtraStyle() & wxWS_EX_PROCESS_UI_UPDATES) == 0)))
496         return false;
497 
498     // Don't update children of the hidden windows: this is useless as any
499     // change to their state won't be seen by the user anyhow. Notice that this
500     // argument doesn't apply to the hidden windows (with visible parent)
501     // themselves as they could be shown by their EVT_UPDATE_UI handler.
502     if ( win->GetParent() && !win->GetParent()->IsShownOnScreen() )
503         return false;
504 
505     if (sm_updateInterval == -1)
506         return false;
507 
508     if (sm_updateInterval == 0)
509         return true;
510 
511 #if wxUSE_STOPWATCH && wxUSE_LONGLONG
512     wxLongLong now = wxGetLocalTimeMillis();
513     if (now > (sm_lastUpdate + sm_updateInterval))
514     {
515         return true;
516     }
517 
518     return false;
519 #else
520     // If we don't have wxStopWatch or wxLongLong, we
521     // should err on the safe side and update now anyway.
522     return true;
523 #endif
524 }
525 
526 // Reset the update time to provide a delay until the next
527 // time we should update
ResetUpdateTime()528 void wxUpdateUIEvent::ResetUpdateTime()
529 {
530 #if wxUSE_STOPWATCH && wxUSE_LONGLONG
531     if (sm_updateInterval > 0)
532     {
533         wxLongLong now = wxGetLocalTimeMillis();
534         if (now > (sm_lastUpdate + sm_updateInterval))
535         {
536             sm_lastUpdate = now;
537         }
538     }
539 #endif
540 }
541 
542 // ----------------------------------------------------------------------------
543 // wxScrollEvent
544 // ----------------------------------------------------------------------------
545 
wxScrollEvent(wxEventType commandType,int id,int pos,int orient)546 wxScrollEvent::wxScrollEvent(wxEventType commandType,
547                              int id,
548                              int pos,
549                              int orient)
550     : wxCommandEvent(commandType, id)
551 {
552     m_extraLong = orient;
553     m_commandInt = pos;
554 }
555 
556 // ----------------------------------------------------------------------------
557 // wxScrollWinEvent
558 // ----------------------------------------------------------------------------
559 
wxScrollWinEvent(wxEventType commandType,int pos,int orient)560 wxScrollWinEvent::wxScrollWinEvent(wxEventType commandType,
561                                    int pos,
562                                    int orient)
563 {
564     m_eventType = commandType;
565     m_extraLong = orient;
566     m_commandInt = pos;
567 }
568 
569 // ----------------------------------------------------------------------------
570 // wxMouseEvent
571 // ----------------------------------------------------------------------------
572 
wxMouseEvent(wxEventType commandType)573 wxMouseEvent::wxMouseEvent(wxEventType commandType)
574 {
575     m_eventType = commandType;
576 
577     m_x = 0;
578     m_y = 0;
579 
580     m_leftDown = false;
581     m_middleDown = false;
582     m_rightDown = false;
583     m_aux1Down = false;
584     m_aux2Down = false;
585 
586     m_clickCount = -1;
587 
588     m_wheelAxis = wxMOUSE_WHEEL_VERTICAL;
589     m_wheelRotation = 0;
590     m_wheelDelta = 0;
591     m_wheelInverted = false;
592     m_linesPerAction = 0;
593     m_columnsPerAction = 0;
594     m_magnification = 0.0f;
595 }
596 
Assign(const wxMouseEvent & event)597 void wxMouseEvent::Assign(const wxMouseEvent& event)
598 {
599     wxEvent::operator=(event);
600     wxMouseState::operator=(event);
601 
602     m_x = event.m_x;
603     m_y = event.m_y;
604 
605     m_leftDown = event.m_leftDown;
606     m_middleDown = event.m_middleDown;
607     m_rightDown = event.m_rightDown;
608     m_aux1Down = event.m_aux1Down;
609     m_aux2Down = event.m_aux2Down;
610 
611     m_wheelRotation = event.m_wheelRotation;
612     m_wheelDelta = event.m_wheelDelta;
613     m_wheelInverted = event.m_wheelInverted;
614     m_linesPerAction = event.m_linesPerAction;
615     m_columnsPerAction = event.m_columnsPerAction;
616     m_wheelAxis = event.m_wheelAxis;
617 
618     m_magnification = event.m_magnification;
619 }
620 
621 // return true if was a button dclick event
ButtonDClick(int but) const622 bool wxMouseEvent::ButtonDClick(int but) const
623 {
624     switch (but)
625     {
626         default:
627             wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonDClick"));
628             wxFALLTHROUGH;
629 
630         case wxMOUSE_BTN_ANY:
631             return (LeftDClick() || MiddleDClick() || RightDClick() ||
632                     Aux1DClick() || Aux2DClick());
633 
634         case wxMOUSE_BTN_LEFT:
635             return LeftDClick();
636 
637         case wxMOUSE_BTN_MIDDLE:
638             return MiddleDClick();
639 
640         case wxMOUSE_BTN_RIGHT:
641             return RightDClick();
642 
643         case wxMOUSE_BTN_AUX1:
644             return Aux1DClick();
645 
646         case wxMOUSE_BTN_AUX2:
647             return Aux2DClick();
648     }
649 }
650 
651 // return true if was a button down event
ButtonDown(int but) const652 bool wxMouseEvent::ButtonDown(int but) const
653 {
654     switch (but)
655     {
656         default:
657             wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonDown"));
658             wxFALLTHROUGH;
659 
660         case wxMOUSE_BTN_ANY:
661             return (LeftDown() || MiddleDown() || RightDown() ||
662                     Aux1Down() || Aux2Down());
663 
664         case wxMOUSE_BTN_LEFT:
665             return LeftDown();
666 
667         case wxMOUSE_BTN_MIDDLE:
668             return MiddleDown();
669 
670         case wxMOUSE_BTN_RIGHT:
671             return RightDown();
672 
673         case wxMOUSE_BTN_AUX1:
674             return Aux1Down();
675 
676         case wxMOUSE_BTN_AUX2:
677             return Aux2Down();
678     }
679 }
680 
681 // return true if was a button up event
ButtonUp(int but) const682 bool wxMouseEvent::ButtonUp(int but) const
683 {
684     switch (but)
685     {
686         default:
687             wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonUp"));
688             wxFALLTHROUGH;
689 
690         case wxMOUSE_BTN_ANY:
691             return (LeftUp() || MiddleUp() || RightUp() ||
692                     Aux1Up() || Aux2Up());
693 
694         case wxMOUSE_BTN_LEFT:
695             return LeftUp();
696 
697         case wxMOUSE_BTN_MIDDLE:
698             return MiddleUp();
699 
700         case wxMOUSE_BTN_RIGHT:
701             return RightUp();
702 
703         case wxMOUSE_BTN_AUX1:
704             return Aux1Up();
705 
706         case wxMOUSE_BTN_AUX2:
707             return Aux2Up();
708     }
709 }
710 
711 // return true if the given button is currently changing state
Button(int but) const712 bool wxMouseEvent::Button(int but) const
713 {
714     switch (but)
715     {
716         default:
717             wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::Button"));
718             wxFALLTHROUGH;
719 
720         case wxMOUSE_BTN_ANY:
721             return ButtonUp(wxMOUSE_BTN_ANY) ||
722                     ButtonDown(wxMOUSE_BTN_ANY) ||
723                         ButtonDClick(wxMOUSE_BTN_ANY);
724 
725         case wxMOUSE_BTN_LEFT:
726             return LeftDown() || LeftUp() || LeftDClick();
727 
728         case wxMOUSE_BTN_MIDDLE:
729             return MiddleDown() || MiddleUp() || MiddleDClick();
730 
731         case wxMOUSE_BTN_RIGHT:
732             return RightDown() || RightUp() || RightDClick();
733 
734         case wxMOUSE_BTN_AUX1:
735            return Aux1Down() || Aux1Up() || Aux1DClick();
736 
737         case wxMOUSE_BTN_AUX2:
738            return Aux2Down() || Aux2Up() || Aux2DClick();
739     }
740 }
741 
GetButton() const742 int wxMouseEvent::GetButton() const
743 {
744     for ( int i = 1; i < wxMOUSE_BTN_MAX; i++ )
745     {
746         if ( Button(i) )
747         {
748             return i;
749         }
750     }
751 
752     return wxMOUSE_BTN_NONE;
753 }
754 
755 // Find the logical position of the event given the DC
GetLogicalPosition(const wxDC & dc) const756 wxPoint wxMouseEvent::GetLogicalPosition(const wxDC& dc) const
757 {
758     wxPoint pt(dc.DeviceToLogicalX(m_x), dc.DeviceToLogicalY(m_y));
759     return pt;
760 }
761 
762 // ----------------------------------------------------------------------------
763 // wxKeyEvent
764 // ----------------------------------------------------------------------------
765 
wxKeyEvent(wxEventType type)766 wxKeyEvent::wxKeyEvent(wxEventType type)
767 #if wxUSE_UNICODE
768     : m_uniChar(WXK_NONE)
769 #endif
770 {
771     m_eventType = type;
772     m_keyCode = WXK_NONE;
773 
774     m_x =
775     m_y = wxDefaultCoord;
776     m_hasPosition = false;
777 
778     InitPropagation();
779 }
780 
wxKeyEvent(const wxKeyEvent & evt)781 wxKeyEvent::wxKeyEvent(const wxKeyEvent& evt)
782           : wxEvent(evt),
783             wxKeyboardState(evt)
784 {
785     DoAssignMembers(evt);
786 
787     InitPropagation();
788 }
789 
wxKeyEvent(wxEventType eventType,const wxKeyEvent & evt)790 wxKeyEvent::wxKeyEvent(wxEventType eventType, const wxKeyEvent& evt)
791           : wxEvent(evt),
792             wxKeyboardState(evt)
793 {
794     DoAssignMembers(evt);
795 
796     m_eventType = eventType;
797 
798     InitPropagation();
799 }
800 
operator =(const wxKeyEvent & evt)801 wxKeyEvent& wxKeyEvent::operator=(const wxKeyEvent& evt)
802 {
803     if ( &evt != this )
804     {
805         wxEvent::operator=(evt);
806         wxKeyboardState::operator=(evt);
807 
808         DoAssignMembers(evt);
809     }
810     return *this;
811 }
812 
InitPositionIfNecessary() const813 void wxKeyEvent::InitPositionIfNecessary() const
814 {
815     if ( m_hasPosition )
816         return;
817 
818     // We're const because we're called from const Get[XY]() methods but we
819     // need to update the "cached" values.
820     wxKeyEvent& self = const_cast<wxKeyEvent&>(*this);
821     self.m_hasPosition = true;
822 
823     // The only position we can possibly associate with the keyboard event on
824     // the platforms where it doesn't carry it already is the mouse position.
825     wxGetMousePosition(&self.m_x, &self.m_y);
826 
827     // If this event is associated with a window, the position should be in its
828     // client coordinates, but otherwise leave it in screen coordinates as what
829     // else can we use?
830     wxWindow* const win = wxDynamicCast(GetEventObject(), wxWindow);
831     if ( win )
832         win->ScreenToClient(&self.m_x, &self.m_y);
833 }
834 
GetX() const835 wxCoord wxKeyEvent::GetX() const
836 {
837     InitPositionIfNecessary();
838 
839     return m_x;
840 }
841 
GetY() const842 wxCoord wxKeyEvent::GetY() const
843 {
844     InitPositionIfNecessary();
845 
846     return m_y;
847 }
848 
IsKeyInCategory(int category) const849 bool wxKeyEvent::IsKeyInCategory(int category) const
850 {
851     switch ( GetKeyCode() )
852     {
853         case WXK_LEFT:
854         case WXK_RIGHT:
855         case WXK_UP:
856         case WXK_DOWN:
857         case WXK_NUMPAD_LEFT:
858         case WXK_NUMPAD_RIGHT:
859         case WXK_NUMPAD_UP:
860         case WXK_NUMPAD_DOWN:
861             return (category & WXK_CATEGORY_ARROW) != 0;
862 
863         case WXK_PAGEDOWN:
864         case WXK_PAGEUP:
865         case WXK_NUMPAD_PAGEUP:
866         case WXK_NUMPAD_PAGEDOWN:
867             return (category & WXK_CATEGORY_PAGING) != 0;
868 
869         case WXK_HOME:
870         case WXK_END:
871         case WXK_NUMPAD_HOME:
872         case WXK_NUMPAD_END:
873             return (category & WXK_CATEGORY_JUMP) != 0;
874 
875         case WXK_TAB:
876         case WXK_NUMPAD_TAB:
877             return (category & WXK_CATEGORY_TAB) != 0;
878 
879         case WXK_BACK:
880         case WXK_DELETE:
881         case WXK_NUMPAD_DELETE:
882             return (category & WXK_CATEGORY_CUT) != 0;
883 
884         default:
885             return false;
886     }
887 }
888 
889 // ----------------------------------------------------------------------------
890 // wxWindowCreateEvent
891 // ----------------------------------------------------------------------------
892 
wxWindowCreateEvent(wxWindow * win)893 wxWindowCreateEvent::wxWindowCreateEvent(wxWindow *win)
894 {
895     SetEventType(wxEVT_CREATE);
896     SetEventObject(win);
897 }
898 
899 // ----------------------------------------------------------------------------
900 // wxWindowDestroyEvent
901 // ----------------------------------------------------------------------------
902 
wxWindowDestroyEvent(wxWindow * win)903 wxWindowDestroyEvent::wxWindowDestroyEvent(wxWindow *win)
904 {
905     SetEventType(wxEVT_DESTROY);
906     SetEventObject(win);
907 }
908 
909 // ----------------------------------------------------------------------------
910 // wxChildFocusEvent
911 // ----------------------------------------------------------------------------
912 
wxChildFocusEvent(wxWindow * win)913 wxChildFocusEvent::wxChildFocusEvent(wxWindow *win)
914                  : wxCommandEvent(wxEVT_CHILD_FOCUS)
915 {
916     SetEventObject(win);
917 }
918 
919 // ----------------------------------------------------------------------------
920 // wxHelpEvent
921 // ----------------------------------------------------------------------------
922 
923 /* static */
GuessOrigin(Origin origin)924 wxHelpEvent::Origin wxHelpEvent::GuessOrigin(Origin origin)
925 {
926     if ( origin == Origin_Unknown )
927     {
928         // assume that the event comes from the help button if it's not from
929         // keyboard and that pressing F1 always results in the help event
930         origin = wxGetKeyState(WXK_F1) ? Origin_Keyboard : Origin_HelpButton;
931     }
932 
933     return origin;
934 }
935 
936 #endif // wxUSE_GUI
937 
938 
939 #if wxUSE_BASE
940 
941 // ----------------------------------------------------------------------------
942 // wxEventHashTable
943 // ----------------------------------------------------------------------------
944 
945 static const int EVENT_TYPE_TABLE_INIT_SIZE = 31; // Not too big not too small...
946 
947 wxEventHashTable* wxEventHashTable::sm_first = NULL;
948 
wxEventHashTable(const wxEventTable & table)949 wxEventHashTable::wxEventHashTable(const wxEventTable &table)
950                 : m_table(table),
951                   m_rebuildHash(true)
952 {
953     AllocEventTypeTable(EVENT_TYPE_TABLE_INIT_SIZE);
954 
955     m_next = sm_first;
956     if (m_next)
957         m_next->m_previous = this;
958     sm_first = this;
959 }
960 
~wxEventHashTable()961 wxEventHashTable::~wxEventHashTable()
962 {
963     if (m_next)
964         m_next->m_previous = m_previous;
965     if (m_previous)
966         m_previous->m_next = m_next;
967     if (sm_first == this)
968         sm_first = m_next;
969 
970     Clear();
971 }
972 
Clear()973 void wxEventHashTable::Clear()
974 {
975     for ( size_t i = 0; i < m_size; i++ )
976     {
977         EventTypeTablePointer  eTTnode = m_eventTypeTable[i];
978         delete eTTnode;
979     }
980 
981     wxDELETEA(m_eventTypeTable);
982 
983     m_size = 0;
984 }
985 
986 #if wxUSE_MEMORY_TRACING
987 
988 // Clear all tables
ClearAll()989 void wxEventHashTable::ClearAll()
990 {
991     wxEventHashTable* table = sm_first;
992     while (table)
993     {
994         table->Clear();
995         table = table->m_next;
996     }
997 }
998 
999 #endif // wxUSE_MEMORY_TRACING
1000 
HandleEvent(wxEvent & event,wxEvtHandler * self)1001 bool wxEventHashTable::HandleEvent(wxEvent &event, wxEvtHandler *self)
1002 {
1003     if (m_rebuildHash)
1004     {
1005         InitHashTable();
1006         m_rebuildHash = false;
1007     }
1008 
1009     if (!m_eventTypeTable)
1010         return false;
1011 
1012     // Find all entries for the given event type.
1013     wxEventType eventType = event.GetEventType();
1014     const EventTypeTablePointer eTTnode = m_eventTypeTable[eventType % m_size];
1015     if (eTTnode && eTTnode->eventType == eventType)
1016     {
1017         // Now start the search for an event handler
1018         // that can handle an event with the given ID.
1019         const wxEventTableEntryPointerArray&
1020             eventEntryTable = eTTnode->eventEntryTable;
1021 
1022         const size_t count = eventEntryTable.GetCount();
1023         for (size_t n = 0; n < count; n++)
1024         {
1025             const wxEventTableEntry& entry = *eventEntryTable[n];
1026             if ( wxEvtHandler::ProcessEventIfMatchesId(entry, self, event) )
1027                 return true;
1028         }
1029     }
1030 
1031     return false;
1032 }
1033 
InitHashTable()1034 void wxEventHashTable::InitHashTable()
1035 {
1036     // Loop over the event tables and all its base tables.
1037     const wxEventTable *table = &m_table;
1038     while (table)
1039     {
1040         // Retrieve all valid event handler entries
1041         const wxEventTableEntry *entry = table->entries;
1042         while (entry->m_fn != 0)
1043         {
1044             // Add the event entry in the Hash.
1045             AddEntry(*entry);
1046 
1047             entry++;
1048         }
1049 
1050         table = table->baseTable;
1051     }
1052 
1053     // Let's free some memory.
1054     size_t i;
1055     for(i = 0; i < m_size; i++)
1056     {
1057         EventTypeTablePointer  eTTnode = m_eventTypeTable[i];
1058         if (eTTnode)
1059         {
1060             eTTnode->eventEntryTable.Shrink();
1061         }
1062     }
1063 }
1064 
AddEntry(const wxEventTableEntry & entry)1065 void wxEventHashTable::AddEntry(const wxEventTableEntry &entry)
1066 {
1067     // This might happen 'accidentally' as the app is exiting
1068     if (!m_eventTypeTable)
1069         return;
1070 
1071     EventTypeTablePointer *peTTnode = &m_eventTypeTable[entry.m_eventType % m_size];
1072     EventTypeTablePointer  eTTnode = *peTTnode;
1073 
1074     if (eTTnode)
1075     {
1076         if (eTTnode->eventType != entry.m_eventType)
1077         {
1078             // Resize the table!
1079             GrowEventTypeTable();
1080             // Try again to add it.
1081             AddEntry(entry);
1082             return;
1083         }
1084     }
1085     else
1086     {
1087         eTTnode = new EventTypeTable;
1088         eTTnode->eventType = entry.m_eventType;
1089         *peTTnode = eTTnode;
1090     }
1091 
1092     // Fill all hash entries between entry.m_id and entry.m_lastId...
1093     eTTnode->eventEntryTable.Add(&entry);
1094 }
1095 
AllocEventTypeTable(size_t size)1096 void wxEventHashTable::AllocEventTypeTable(size_t size)
1097 {
1098     m_eventTypeTable = new EventTypeTablePointer[size];
1099     memset((void *)m_eventTypeTable, 0, sizeof(EventTypeTablePointer)*size);
1100     m_size = size;
1101 }
1102 
GrowEventTypeTable()1103 void wxEventHashTable::GrowEventTypeTable()
1104 {
1105     size_t oldSize = m_size;
1106     EventTypeTablePointer *oldEventTypeTable = m_eventTypeTable;
1107 
1108     // TODO: Search the most optimal grow sequence
1109     AllocEventTypeTable(/* GetNextPrime(oldSize) */oldSize*2+1);
1110 
1111     for ( size_t i = 0; i < oldSize; /* */ )
1112     {
1113         EventTypeTablePointer  eTToldNode = oldEventTypeTable[i];
1114         if (eTToldNode)
1115         {
1116             EventTypeTablePointer *peTTnode = &m_eventTypeTable[eTToldNode->eventType % m_size];
1117             EventTypeTablePointer  eTTnode = *peTTnode;
1118 
1119             // Check for collision, we don't want any.
1120             if (eTTnode)
1121             {
1122                 GrowEventTypeTable();
1123                 continue; // Don't increment the counter,
1124                           // as we still need to add this element.
1125             }
1126             else
1127             {
1128                 // Get the old value and put it in the new table.
1129                 *peTTnode = oldEventTypeTable[i];
1130             }
1131         }
1132 
1133         i++;
1134     }
1135 
1136     delete[] oldEventTypeTable;
1137 }
1138 
1139 // ----------------------------------------------------------------------------
1140 // wxEvtHandler
1141 // ----------------------------------------------------------------------------
1142 
wxEvtHandler()1143 wxEvtHandler::wxEvtHandler()
1144 {
1145     m_nextHandler = NULL;
1146     m_previousHandler = NULL;
1147     m_enabled = true;
1148     m_dynamicEvents = NULL;
1149     m_pendingEvents = NULL;
1150 
1151     // no client data (yet)
1152     m_clientData = NULL;
1153     m_clientDataType = wxClientData_None;
1154 }
1155 
~wxEvtHandler()1156 wxEvtHandler::~wxEvtHandler()
1157 {
1158     Unlink();
1159 
1160     if (m_dynamicEvents)
1161     {
1162         size_t cookie;
1163         for ( wxDynamicEventTableEntry* entry = GetFirstDynamicEntry(cookie);
1164               entry;
1165               entry = GetNextDynamicEntry(cookie) )
1166         {
1167             // Remove ourselves from sink destructor notifications
1168             // (this has usually been done, in wxTrackable destructor)
1169             wxEvtHandler *eventSink = entry->m_fn->GetEvtHandler();
1170             if ( eventSink )
1171             {
1172                 wxEventConnectionRef * const
1173                     evtConnRef = FindRefInTrackerList(eventSink);
1174                 if ( evtConnRef )
1175                 {
1176                     eventSink->RemoveNode(evtConnRef);
1177                     delete evtConnRef;
1178                 }
1179             }
1180 
1181             delete entry->m_callbackUserData;
1182             delete entry;
1183         }
1184         delete m_dynamicEvents;
1185     }
1186 
1187     // Remove us from the list of the pending events if necessary.
1188     if (wxTheApp)
1189         wxTheApp->RemovePendingEventHandler(this);
1190 
1191     DeletePendingEvents();
1192 
1193     // we only delete object data, not untyped
1194     if ( m_clientDataType == wxClientData_Object )
1195         delete m_clientObject;
1196 }
1197 
Unlink()1198 void wxEvtHandler::Unlink()
1199 {
1200     // this event handler must take itself out of the chain of handlers:
1201 
1202     if (m_previousHandler)
1203         m_previousHandler->SetNextHandler(m_nextHandler);
1204 
1205     if (m_nextHandler)
1206         m_nextHandler->SetPreviousHandler(m_previousHandler);
1207 
1208     m_nextHandler = NULL;
1209     m_previousHandler = NULL;
1210 }
1211 
IsUnlinked() const1212 bool wxEvtHandler::IsUnlinked() const
1213 {
1214     return m_previousHandler == NULL &&
1215            m_nextHandler == NULL;
1216 }
1217 
1218 wxEventFilter* wxEvtHandler::ms_filterList = NULL;
1219 
AddFilter(wxEventFilter * filter)1220 /* static */ void wxEvtHandler::AddFilter(wxEventFilter* filter)
1221 {
1222     wxCHECK_RET( filter, "NULL filter" );
1223 
1224     filter->m_next = ms_filterList;
1225     ms_filterList = filter;
1226 }
1227 
RemoveFilter(wxEventFilter * filter)1228 /* static */ void wxEvtHandler::RemoveFilter(wxEventFilter* filter)
1229 {
1230     wxEventFilter* prev = NULL;
1231     for ( wxEventFilter* f = ms_filterList; f; f = f->m_next )
1232     {
1233         if ( f == filter )
1234         {
1235             // Set the previous list element or the list head to the next
1236             // element.
1237             if ( prev )
1238                 prev->m_next = f->m_next;
1239             else
1240                 ms_filterList = f->m_next;
1241 
1242             // Also reset the next pointer in the filter itself just to avoid
1243             // having possibly dangling pointers, even though it's not strictly
1244             // necessary.
1245             f->m_next = NULL;
1246 
1247             // Skip the assert below.
1248             return;
1249         }
1250 
1251         prev = f;
1252     }
1253 
1254     wxFAIL_MSG( "Filter not found" );
1255 }
1256 
1257 #if wxUSE_THREADS
1258 
ProcessThreadEvent(const wxEvent & event)1259 bool wxEvtHandler::ProcessThreadEvent(const wxEvent& event)
1260 {
1261     // check that we are really in a child thread
1262     wxASSERT_MSG( !wxThread::IsMain(),
1263                   wxT("use ProcessEvent() in main thread") );
1264 
1265     AddPendingEvent(event);
1266 
1267     return true;
1268 }
1269 
1270 #endif // wxUSE_THREADS
1271 
QueueEvent(wxEvent * event)1272 void wxEvtHandler::QueueEvent(wxEvent *event)
1273 {
1274     wxCHECK_RET( event, "NULL event can't be posted" );
1275 
1276     if (!wxTheApp)
1277     {
1278         // we need an event loop which manages the list of event handlers with
1279         // pending events... cannot proceed without it!
1280         wxLogDebug("No application object! Cannot queue this event!");
1281 
1282         // anyway delete the given event to avoid memory leaks
1283         delete event;
1284 
1285         return;
1286     }
1287 
1288     // 1) Add this event to our list of pending events
1289     wxENTER_CRIT_SECT( m_pendingEventsLock );
1290 
1291     if ( !m_pendingEvents )
1292         m_pendingEvents = new wxList;
1293 
1294     m_pendingEvents->Append(event);
1295 
1296     // 2) Add this event handler to list of event handlers that
1297     //    have pending events.
1298 
1299     wxTheApp->AppendPendingEventHandler(this);
1300 
1301     // only release m_pendingEventsLock now because otherwise there is a race
1302     // condition as described in the ticket #9093: we could process the event
1303     // just added to m_pendingEvents in our ProcessPendingEvents() below before
1304     // we had time to append this pointer to wxHandlersWithPendingEvents list; thus
1305     // breaking the invariant that a handler should be in the list iff it has
1306     // any pending events to process
1307     wxLEAVE_CRIT_SECT( m_pendingEventsLock );
1308 
1309     // 3) Inform the system that new pending events are somewhere,
1310     //    and that these should be processed in idle time.
1311     wxWakeUpIdle();
1312 }
1313 
DeletePendingEvents()1314 void wxEvtHandler::DeletePendingEvents()
1315 {
1316     if (m_pendingEvents)
1317         m_pendingEvents->DeleteContents(true);
1318     wxDELETE(m_pendingEvents);
1319 }
1320 
ProcessPendingEvents()1321 void wxEvtHandler::ProcessPendingEvents()
1322 {
1323     if (!wxTheApp)
1324     {
1325         // we need an event loop which manages the list of event handlers with
1326         // pending events... cannot proceed without it!
1327         wxLogDebug("No application object! Cannot process pending events!");
1328         return;
1329     }
1330 
1331     // we need to process only a single pending event in this call because
1332     // each call to ProcessEvent() could result in the destruction of this
1333     // same event handler (see the comment at the end of this function)
1334 
1335     wxENTER_CRIT_SECT( m_pendingEventsLock );
1336 
1337     // this method is only called by wxApp if this handler does have
1338     // pending events
1339     wxCHECK_RET( m_pendingEvents && !m_pendingEvents->IsEmpty(),
1340                  "should have pending events if called" );
1341 
1342     wxList::compatibility_iterator node = m_pendingEvents->GetFirst();
1343     wxEvent* pEvent = static_cast<wxEvent *>(node->GetData());
1344 
1345     // find the first event which can be processed now:
1346     wxEventLoopBase* evtLoop = wxEventLoopBase::GetActive();
1347     if (evtLoop && evtLoop->IsYielding())
1348     {
1349         while (node && pEvent && !evtLoop->IsEventAllowedInsideYield(pEvent->GetEventCategory()))
1350         {
1351             node = node->GetNext();
1352             pEvent = node ? static_cast<wxEvent *>(node->GetData()) : NULL;
1353         }
1354 
1355         if (!node)
1356         {
1357             // all our events are NOT processable now... signal this:
1358             wxTheApp->DelayPendingEventHandler(this);
1359 
1360             // see the comment at the beginning of evtloop.h header for the
1361             // logic behind YieldFor() and behind DelayPendingEventHandler()
1362 
1363             wxLEAVE_CRIT_SECT( m_pendingEventsLock );
1364 
1365             return;
1366         }
1367     }
1368 
1369     wxEventPtr event(pEvent);
1370 
1371     // it's important we remove event from list before processing it, else a
1372     // nested event loop, for example from a modal dialog, might process the
1373     // same event again.
1374     m_pendingEvents->Erase(node);
1375 
1376     if ( m_pendingEvents->IsEmpty() )
1377     {
1378         // if there are no more pending events left, we don't need to
1379         // stay in this list
1380         wxTheApp->RemovePendingEventHandler(this);
1381     }
1382 
1383     wxLEAVE_CRIT_SECT( m_pendingEventsLock );
1384 
1385     ProcessEvent(*event);
1386 
1387     // careful: this object could have been deleted by the event handler
1388     // executed by the above ProcessEvent() call, so we can't access any fields
1389     // of this object any more
1390 }
1391 
1392 /* static */
ProcessEventIfMatchesId(const wxEventTableEntryBase & entry,wxEvtHandler * handler,wxEvent & event)1393 bool wxEvtHandler::ProcessEventIfMatchesId(const wxEventTableEntryBase& entry,
1394                                            wxEvtHandler *handler,
1395                                            wxEvent& event)
1396 {
1397     int tableId1 = entry.m_id,
1398         tableId2 = entry.m_lastId;
1399 
1400     // match only if the event type is the same and the id is either -1 in
1401     // the event table (meaning "any") or the event id matches the id
1402     // specified in the event table either exactly or by falling into
1403     // range between first and last
1404     if ((tableId1 == wxID_ANY) ||
1405         (tableId2 == wxID_ANY && tableId1 == event.GetId()) ||
1406         (tableId2 != wxID_ANY &&
1407          (event.GetId() >= tableId1 && event.GetId() <= tableId2)))
1408     {
1409         event.Skip(false);
1410         event.m_callbackUserData = entry.m_callbackUserData;
1411 
1412 #if wxUSE_EXCEPTIONS
1413         if ( wxTheApp )
1414         {
1415             // call the handler via wxApp method which allows the user to catch
1416             // any exceptions which may be thrown by any handler in the program
1417             // in one place
1418             wxTheApp->CallEventHandler(handler, *entry.m_fn, event);
1419         }
1420         else
1421 #endif // wxUSE_EXCEPTIONS
1422         {
1423             (*entry.m_fn)(handler, event);
1424         }
1425 
1426         if (!event.GetSkipped())
1427             return true;
1428     }
1429 
1430     return false;
1431 }
1432 
DoTryApp(wxEvent & event)1433 bool wxEvtHandler::DoTryApp(wxEvent& event)
1434 {
1435     if ( wxTheApp && (this != wxTheApp) )
1436     {
1437         // Special case: don't pass wxEVT_IDLE to wxApp, since it'll always
1438         // swallow it. wxEVT_IDLE is sent explicitly to wxApp so it will be
1439         // processed appropriately via SearchEventTable.
1440         if ( event.GetEventType() != wxEVT_IDLE )
1441         {
1442             if ( wxTheApp->ProcessEvent(event) )
1443                 return true;
1444         }
1445     }
1446 
1447     return false;
1448 }
1449 
TryBefore(wxEvent & event)1450 bool wxEvtHandler::TryBefore(wxEvent& event)
1451 {
1452 #if WXWIN_COMPATIBILITY_2_8
1453     // call the old virtual function to keep the code overriding it working
1454     return TryValidator(event);
1455 #else
1456     wxUnusedVar(event);
1457     return false;
1458 #endif
1459 }
1460 
TryAfter(wxEvent & event)1461 bool wxEvtHandler::TryAfter(wxEvent& event)
1462 {
1463     // We only want to pass the window to the application object once even if
1464     // there are several chained handlers. Ensure that this is what happens by
1465     // only calling DoTryApp() if there is no next handler (which would do it).
1466     //
1467     // Notice that, unlike simply calling TryAfter() on the last handler in the
1468     // chain only from ProcessEvent(), this also works with wxWindow object in
1469     // the middle of the chain: its overridden TryAfter() will still be called
1470     // and propagate the event upwards the window hierarchy even if it's not
1471     // the last one in the chain (which, admittedly, shouldn't happen often).
1472     if ( GetNextHandler() )
1473         return GetNextHandler()->TryAfter(event);
1474 
1475     // If this event is going to be processed in another handler next, don't
1476     // pass it to wxTheApp now, it will be done from TryAfter() of this other
1477     // handler.
1478     if ( event.WillBeProcessedAgain() )
1479         return false;
1480 
1481 #if WXWIN_COMPATIBILITY_2_8
1482     // as above, call the old virtual function for compatibility
1483     return TryParent(event);
1484 #else
1485     return DoTryApp(event);
1486 #endif
1487 }
1488 
ProcessEvent(wxEvent & event)1489 bool wxEvtHandler::ProcessEvent(wxEvent& event)
1490 {
1491     // The very first thing we do is to allow any registered filters to hook
1492     // into event processing in order to globally pre-process all events.
1493     //
1494     // Note that we should only do it if we're the first event handler called
1495     // to avoid calling FilterEvent() multiple times as the event goes through
1496     // the event handler chain and possibly upwards the window hierarchy.
1497     if ( !event.WasProcessed() )
1498     {
1499         for ( wxEventFilter* f = ms_filterList; f; f = f->m_next )
1500         {
1501             int rc = f->FilterEvent(event);
1502             if ( rc != wxEventFilter::Event_Skip )
1503             {
1504                 wxASSERT_MSG( rc == wxEventFilter::Event_Ignore ||
1505                                 rc == wxEventFilter::Event_Processed,
1506                               "unexpected FilterEvent() return value" );
1507 
1508                 return rc != wxEventFilter::Event_Ignore;
1509             }
1510             //else: proceed normally
1511         }
1512     }
1513 
1514     // Short circuit the event processing logic if we're requested to process
1515     // this event in this handler only, see DoTryChain() for more details.
1516     if ( event.ShouldProcessOnlyIn(this) )
1517         return TryBeforeAndHere(event);
1518 
1519 
1520     // Try to process the event in this handler itself.
1521     if ( ProcessEventLocally(event) )
1522     {
1523         // It is possible that DoTryChain() called from ProcessEventLocally()
1524         // returned true but the event was not really processed: this happens
1525         // if a custom handler ignores the request to process the event in this
1526         // handler only and in this case we should skip the post processing
1527         // done in TryAfter() but still return the correct value ourselves to
1528         // indicate whether we did or did not find a handler for this event.
1529         return !event.GetSkipped();
1530     }
1531 
1532     // If we still didn't find a handler, propagate the event upwards the
1533     // window chain and/or to the application object.
1534     if ( TryAfter(event) )
1535         return true;
1536 
1537 
1538     // No handler found anywhere, bail out.
1539     return false;
1540 }
1541 
ProcessEventLocally(wxEvent & event)1542 bool wxEvtHandler::ProcessEventLocally(wxEvent& event)
1543 {
1544     // Try the hooks which should be called before our own handlers and this
1545     // handler itself first. Notice that we should not call ProcessEvent() on
1546     // this one as we're already called from it, which explains why we do it
1547     // here and not in DoTryChain()
1548     return TryBeforeAndHere(event) || DoTryChain(event);
1549 }
1550 
DoTryChain(wxEvent & event)1551 bool wxEvtHandler::DoTryChain(wxEvent& event)
1552 {
1553     for ( wxEvtHandler *h = GetNextHandler(); h; h = h->GetNextHandler() )
1554     {
1555         // We need to process this event at the level of this handler only
1556         // right now, the pre-/post-processing was either already done by
1557         // ProcessEvent() from which we were called or will be done by it when
1558         // we return.
1559         //
1560         // However we must call ProcessEvent() and not TryHereOnly() because the
1561         // existing code (including some in wxWidgets itself) expects the
1562         // overridden ProcessEvent() in its custom event handlers pushed on a
1563         // window to be called.
1564         //
1565         // So we must call ProcessEvent() but it must not do what it usually
1566         // does. To resolve this paradox we set up a special flag inside the
1567         // object itself to let ProcessEvent() know that it shouldn't do any
1568         // pre/post-processing for this event if it gets it. Note that this
1569         // only applies to this handler, if the event is passed to another one
1570         // by explicitly calling its ProcessEvent(), pre/post-processing should
1571         // be done as usual.
1572         //
1573         // Final complication is that if the implementation of ProcessEvent()
1574         // called wxEvent::DidntHonourProcessOnlyIn() (as the gross hack that
1575         // is wxScrollHelperEvtHandler::ProcessEvent() does) and ignored our
1576         // request to process event in this handler only, we have to compensate
1577         // for it by not processing the event further because this was already
1578         // done by that rogue event handler.
1579         wxEventProcessInHandlerOnly processInHandlerOnly(event, h);
1580         if ( h->ProcessEvent(event) )
1581         {
1582             // Make sure "skipped" flag is not set as the event was really
1583             // processed in this case. Normally it shouldn't be set anyhow but
1584             // make sure just in case the user code does something strange.
1585             event.Skip(false);
1586 
1587             return true;
1588         }
1589 
1590         if ( !event.ShouldProcessOnlyIn(h) )
1591         {
1592             // Still return true to indicate that no further processing should
1593             // be undertaken but ensure that "skipped" flag is set so that the
1594             // caller knows that the event was not really processed.
1595             event.Skip();
1596 
1597             return true;
1598         }
1599     }
1600 
1601     return false;
1602 }
1603 
TryHereOnly(wxEvent & event)1604 bool wxEvtHandler::TryHereOnly(wxEvent& event)
1605 {
1606     // If the event handler is disabled it doesn't process any events
1607     if ( !GetEvtHandlerEnabled() )
1608         return false;
1609 
1610     // Handle per-instance dynamic event tables first
1611     if ( m_dynamicEvents && SearchDynamicEventTable(event) )
1612         return true;
1613 
1614     // Then static per-class event tables
1615     if ( GetEventHashTable().HandleEvent(event, this) )
1616         return true;
1617 
1618 #ifdef wxHAS_CALL_AFTER
1619     // There is an implicit entry for async method calls processing in every
1620     // event handler:
1621     if ( event.GetEventType() == wxEVT_ASYNC_METHOD_CALL &&
1622             event.GetEventObject() == this )
1623     {
1624         static_cast<wxAsyncMethodCallEvent&>(event).Execute();
1625         return true;
1626     }
1627 #endif // wxHAS_CALL_AFTER
1628 
1629     // We don't have a handler for this event.
1630     return false;
1631 }
1632 
SafelyProcessEvent(wxEvent & event)1633 bool wxEvtHandler::SafelyProcessEvent(wxEvent& event)
1634 {
1635 #if wxUSE_EXCEPTIONS
1636     try
1637     {
1638 #endif
1639         return ProcessEvent(event);
1640 #if wxUSE_EXCEPTIONS
1641     }
1642     catch ( ... )
1643     {
1644         WXConsumeException();
1645 
1646         return false;
1647     }
1648 #endif // wxUSE_EXCEPTIONS
1649 }
1650 
1651 #if wxUSE_EXCEPTIONS
1652 /* static */
WXConsumeException()1653 void wxEvtHandler::WXConsumeException()
1654 {
1655     wxEventLoopBase * const loop = wxEventLoopBase::GetActive();
1656     try
1657     {
1658         if ( !wxTheApp || !wxTheApp->OnExceptionInMainLoop() )
1659         {
1660             // If OnExceptionInMainLoop() returns false, we're supposed to exit
1661             // the program and for this we need to exit the main loop, not the
1662             // possibly nested one we're running right now.
1663             if ( wxTheApp )
1664             {
1665                 wxTheApp->ExitMainLoop();
1666             }
1667             else
1668             {
1669                 // We must not continue running after an exception, unless
1670                 // explicitly requested, so if we can't ensure this in any
1671                 // other way, do it brutally like this.
1672                 wxAbort();
1673             }
1674 
1675         }
1676         //else: continue running current event loop
1677     }
1678     catch ( ... )
1679     {
1680         // OnExceptionInMainLoop() threw, possibly rethrowing the same
1681         // exception again. We have to deal with it here because we can't
1682         // allow the exception to escape from the handling code, this will
1683         // result in a crash at best (e.g. when using wxGTK as C++
1684         // exceptions can't propagate through the C GTK+ code and corrupt
1685         // the stack) and in something even more weird at worst (like
1686         // exceptions completely disappearing into the void under some
1687         // 64 bit versions of Windows).
1688         if ( loop && !loop->IsYielding() )
1689             loop->Exit();
1690 
1691         // Give the application one last possibility to store the exception
1692         // for rethrowing it later, when we get back to our code.
1693         bool stored = false;
1694         try
1695         {
1696             if ( wxTheApp )
1697                 stored = wxTheApp->StoreCurrentException();
1698         }
1699         catch ( ... )
1700         {
1701             // StoreCurrentException() really shouldn't throw, but if it
1702             // did, take it as an indication that it didn't store it.
1703         }
1704 
1705         // If it didn't take it, just abort, at least like this we behave
1706         // consistently everywhere.
1707         if ( !stored )
1708         {
1709             try
1710             {
1711                 if ( wxTheApp )
1712                     wxTheApp->OnUnhandledException();
1713             }
1714             catch ( ... )
1715             {
1716                 // And OnUnhandledException() absolutely shouldn't throw,
1717                 // but we still must account for the possibility that it
1718                 // did. At least show some information about the exception
1719                 // in this case.
1720                 wxTheApp->wxAppConsoleBase::OnUnhandledException();
1721             }
1722 
1723             wxAbort();
1724         }
1725     }
1726 }
1727 
1728 #endif // wxUSE_EXCEPTIONS
1729 
SearchEventTable(wxEventTable & table,wxEvent & event)1730 bool wxEvtHandler::SearchEventTable(wxEventTable& table, wxEvent& event)
1731 {
1732     const wxEventType eventType = event.GetEventType();
1733     for ( int i = 0; table.entries[i].m_fn != 0; i++ )
1734     {
1735         const wxEventTableEntry& entry = table.entries[i];
1736         if ( eventType == entry.m_eventType )
1737         {
1738             if ( ProcessEventIfMatchesId(entry, this, event) )
1739                 return true;
1740         }
1741     }
1742 
1743     return false;
1744 }
1745 
DoBind(int id,int lastId,wxEventType eventType,wxEventFunctor * func,wxObject * userData)1746 void wxEvtHandler::DoBind(int id,
1747                           int lastId,
1748                           wxEventType eventType,
1749                           wxEventFunctor *func,
1750                           wxObject *userData)
1751 {
1752     wxDynamicEventTableEntry *entry =
1753         new wxDynamicEventTableEntry(eventType, id, lastId, func, userData);
1754 
1755     // Check if the derived class allows binding such event handlers.
1756     if ( !OnDynamicBind(*entry) )
1757     {
1758         delete entry;
1759         return;
1760     }
1761 
1762     if (!m_dynamicEvents)
1763         m_dynamicEvents = new DynamicEvents;
1764 
1765     // We prefer to push back the entry here and then iterate over the vector
1766     // in reverse direction in GetNextDynamicEntry() as it's more efficient
1767     // than inserting the element at the front.
1768     m_dynamicEvents->push_back(entry);
1769 
1770     // Make sure we get to know when a sink is destroyed
1771     wxEvtHandler *eventSink = func->GetEvtHandler();
1772     if ( eventSink && eventSink != this )
1773     {
1774         wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink);
1775         if ( evtConnRef )
1776             evtConnRef->IncRef( );
1777         else
1778             new wxEventConnectionRef(this, eventSink);
1779     }
1780 }
1781 
1782 bool
DoUnbind(int id,int lastId,wxEventType eventType,const wxEventFunctor & func,wxObject * userData)1783 wxEvtHandler::DoUnbind(int id,
1784                        int lastId,
1785                        wxEventType eventType,
1786                        const wxEventFunctor& func,
1787                        wxObject *userData)
1788 {
1789     if (!m_dynamicEvents)
1790         return false;
1791 
1792     size_t cookie;
1793     for ( wxDynamicEventTableEntry* entry = GetFirstDynamicEntry(cookie);
1794           entry;
1795           entry = GetNextDynamicEntry(cookie) )
1796     {
1797         if ((entry->m_id == id) &&
1798             ((entry->m_lastId == lastId) || (lastId == wxID_ANY)) &&
1799             ((entry->m_eventType == eventType) || (eventType == wxEVT_NULL)) &&
1800             entry->m_fn->IsMatching(func) &&
1801             ((entry->m_callbackUserData == userData) || !userData))
1802         {
1803             // Remove connection from tracker node (wxEventConnectionRef)
1804             wxEvtHandler *eventSink = entry->m_fn->GetEvtHandler();
1805             if ( eventSink && eventSink != this )
1806             {
1807                 wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink);
1808                 if ( evtConnRef )
1809                     evtConnRef->DecRef();
1810             }
1811 
1812             delete entry->m_callbackUserData;
1813 
1814             // We can't delete the entry from the vector if we're currently
1815             // iterating over it. As we don't know whether we're or not, just
1816             // null it for now and we will really erase it when we do finish
1817             // iterating over it the next time.
1818             //
1819             // Notice that we rely on "cookie" being just the index into the
1820             // vector, which is not guaranteed by our API, but here we can use
1821             // this implementation detail.
1822             (*m_dynamicEvents)[cookie] = NULL;
1823 
1824             delete entry;
1825             return true;
1826         }
1827     }
1828     return false;
1829 }
1830 
1831 wxDynamicEventTableEntry*
GetFirstDynamicEntry(size_t & cookie) const1832 wxEvtHandler::GetFirstDynamicEntry(size_t& cookie) const
1833 {
1834     if ( !m_dynamicEvents )
1835         return NULL;
1836 
1837     // The handlers are in LIFO order, so we must start at the end.
1838     cookie = m_dynamicEvents->size();
1839     return GetNextDynamicEntry(cookie);
1840 }
1841 
1842 wxDynamicEventTableEntry*
GetNextDynamicEntry(size_t & cookie) const1843 wxEvtHandler::GetNextDynamicEntry(size_t& cookie) const
1844 {
1845     // On entry here cookie is one greater than the index of the entry to
1846     // return, so if it is 0, it means that there are no more entries.
1847     while ( cookie )
1848     {
1849         // Otherwise return the element at the previous index, skipping any
1850         // null elements which indicate removed entries.
1851         wxDynamicEventTableEntry* const entry = m_dynamicEvents->at(--cookie);
1852         if ( entry )
1853             return entry;
1854     }
1855 
1856     return NULL;
1857 }
1858 
SearchDynamicEventTable(wxEvent & event)1859 bool wxEvtHandler::SearchDynamicEventTable( wxEvent& event )
1860 {
1861     wxCHECK_MSG( m_dynamicEvents, false,
1862                  wxT("caller should check that we have dynamic events") );
1863 
1864     DynamicEvents& dynamicEvents = *m_dynamicEvents;
1865 
1866     bool needToPruneDeleted = false;
1867 
1868     // We can't use Get{First,Next}DynamicEntry() here as they hide the deleted
1869     // but not yet pruned entries from the caller, but here we do want to know
1870     // about them, so iterate directly. Remember to do it in the reverse order
1871     // to honour the order of handlers connection.
1872     for ( size_t n = dynamicEvents.size(); n; n-- )
1873     {
1874         wxDynamicEventTableEntry* const entry = dynamicEvents[n - 1];
1875 
1876         if ( !entry )
1877         {
1878             // This entry must have been unbound at some time in the past, so
1879             // skip it now and really remove it from the vector below, once we
1880             // finish iterating.
1881             needToPruneDeleted = true;
1882             continue;
1883         }
1884 
1885         if ( event.GetEventType() == entry->m_eventType )
1886         {
1887             wxEvtHandler *handler = entry->m_fn->GetEvtHandler();
1888             if ( !handler )
1889                handler = this;
1890             if ( ProcessEventIfMatchesId(*entry, handler, event) )
1891             {
1892                 // It's important to skip pruning of the unbound event entries
1893                 // below because this object itself could have been deleted by
1894                 // the event handler making m_dynamicEvents a dangling pointer
1895                 // which can't be accessed any longer in the code below.
1896                 //
1897                 // In practice, it hopefully shouldn't be a problem to wait
1898                 // until we get an event that we don't handle before pruning
1899                 // because this should happen soon enough and even if it
1900                 // doesn't the worst possible outcome is slightly increased
1901                 // memory consumption while not skipping pruning can result in
1902                 // hard to reproduce (because they require the disconnection
1903                 // and deletion happen at the same time which is not always the
1904                 // case) crashes.
1905                 return true;
1906             }
1907         }
1908     }
1909 
1910     if ( needToPruneDeleted )
1911     {
1912         size_t nNew = 0;
1913         for ( size_t n = 0; n != dynamicEvents.size(); n++ )
1914         {
1915             if ( dynamicEvents[n] )
1916                 dynamicEvents[nNew++] = dynamicEvents[n];
1917         }
1918 
1919         wxASSERT( nNew != dynamicEvents.size() );
1920         dynamicEvents.resize(nNew);
1921     }
1922 
1923     return false;
1924 }
1925 
DoSetClientObject(wxClientData * data)1926 void wxEvtHandler::DoSetClientObject( wxClientData *data )
1927 {
1928     wxASSERT_MSG( m_clientDataType != wxClientData_Void,
1929                   wxT("can't have both object and void client data") );
1930 
1931     delete m_clientObject;
1932 
1933     m_clientObject = data;
1934     m_clientDataType = wxClientData_Object;
1935 }
1936 
DoGetClientObject() const1937 wxClientData *wxEvtHandler::DoGetClientObject() const
1938 {
1939     // it's not an error to call GetClientObject() on a window which doesn't
1940     // have client data at all - NULL will be returned
1941     wxASSERT_MSG( m_clientDataType != wxClientData_Void,
1942                   wxT("this window doesn't have object client data") );
1943 
1944     return m_clientObject;
1945 }
1946 
DoSetClientData(void * data)1947 void wxEvtHandler::DoSetClientData( void *data )
1948 {
1949     wxASSERT_MSG( m_clientDataType != wxClientData_Object,
1950                   wxT("can't have both object and void client data") );
1951 
1952     m_clientData = data;
1953     m_clientDataType = wxClientData_Void;
1954 }
1955 
DoGetClientData() const1956 void *wxEvtHandler::DoGetClientData() const
1957 {
1958     // it's not an error to call GetClientData() on a window which doesn't have
1959     // client data at all - NULL will be returned
1960     wxASSERT_MSG( m_clientDataType != wxClientData_Object,
1961                   wxT("this window doesn't have void client data") );
1962 
1963     return m_clientData;
1964 }
1965 
1966 // A helper to find an wxEventConnectionRef object
1967 wxEventConnectionRef *
FindRefInTrackerList(wxEvtHandler * eventSink)1968 wxEvtHandler::FindRefInTrackerList(wxEvtHandler *eventSink)
1969 {
1970     for ( wxTrackerNode *node = eventSink->GetFirst(); node; node = node->m_nxt )
1971     {
1972         // we only want wxEventConnectionRef nodes here
1973         wxEventConnectionRef *evtConnRef = node->ToEventConnection();
1974         if ( evtConnRef && evtConnRef->m_src == this )
1975         {
1976             wxASSERT( evtConnRef->m_sink==eventSink );
1977             return evtConnRef;
1978         }
1979     }
1980 
1981     return NULL;
1982 }
1983 
OnSinkDestroyed(wxEvtHandler * sink)1984 void wxEvtHandler::OnSinkDestroyed( wxEvtHandler *sink )
1985 {
1986     wxASSERT(m_dynamicEvents);
1987 
1988     // remove all connections with this sink
1989     size_t cookie;
1990     for ( wxDynamicEventTableEntry* entry = GetFirstDynamicEntry(cookie);
1991           entry;
1992           entry = GetNextDynamicEntry(cookie) )
1993     {
1994         if ( entry->m_fn->GetEvtHandler() == sink )
1995         {
1996             delete entry->m_callbackUserData;
1997             delete entry;
1998 
1999             // Just as in DoUnbind(), we use our knowledge of
2000             // GetNextDynamicEntry() implementation here.
2001             (*m_dynamicEvents)[cookie] = NULL;
2002         }
2003     }
2004 }
2005 
2006 #endif // wxUSE_BASE
2007 
2008 #if wxUSE_GUI
2009 
2010 // Find a window with the focus, that is also a descendant of the given window.
2011 // This is used to determine the window to initially send commands to.
wxFindFocusDescendant(wxWindow * ancestor)2012 wxWindow* wxFindFocusDescendant(wxWindow* ancestor)
2013 {
2014     // Process events starting with the window with the focus, if any.
2015     wxWindow* focusWin = wxWindow::FindFocus();
2016     wxWindow* win = focusWin;
2017 
2018     // Check if this is a descendant of this frame.
2019     // If not, win will be set to NULL.
2020     while (win)
2021     {
2022         if (win == ancestor)
2023             break;
2024         else
2025             win = win->GetParent();
2026     }
2027     if (win == NULL)
2028         focusWin = NULL;
2029 
2030     return focusWin;
2031 }
2032 
2033 // ----------------------------------------------------------------------------
2034 // wxEventBlocker
2035 // ----------------------------------------------------------------------------
2036 
wxEventBlocker(wxWindow * win,wxEventType type)2037 wxEventBlocker::wxEventBlocker(wxWindow *win, wxEventType type)
2038 {
2039     wxCHECK_RET(win, wxT("Null window given to wxEventBlocker"));
2040 
2041     m_window = win;
2042 
2043     Block(type);
2044     m_window->PushEventHandler(this);
2045 }
2046 
~wxEventBlocker()2047 wxEventBlocker::~wxEventBlocker()
2048 {
2049     wxEvtHandler *popped = m_window->PopEventHandler(false);
2050     wxCHECK_RET(popped == this,
2051         wxT("Don't push other event handlers into a window managed by wxEventBlocker!"));
2052 }
2053 
ProcessEvent(wxEvent & event)2054 bool wxEventBlocker::ProcessEvent(wxEvent& event)
2055 {
2056     // should this event be blocked?
2057     for ( size_t i = 0; i < m_eventsToBlock.size(); i++ )
2058     {
2059         wxEventType t = (wxEventType)m_eventsToBlock[i];
2060         if ( t == wxEVT_ANY || t == event.GetEventType() )
2061             return true;   // yes, it should: mark this event as processed
2062     }
2063 
2064     return wxEvtHandler::ProcessEvent(event);
2065 }
2066 
2067 #endif // wxUSE_GUI
2068 
2069