]> git.saurik.com Git - wxWidgets.git/blob - src/common/event.cpp
* Changed "wxPendingEvents" to pointers (tested on GTK)
[wxWidgets.git] / src / common / event.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: event.cpp
3 // Purpose: Event classes
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 01/02/97
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "event.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/defs.h"
25 #include "wx/control.h"
26 #include "wx/utils.h"
27 #include "wx/app.h"
28 #include "wx/dc.h"
29 #endif
30
31 #include "wx/event.h"
32 #include "wx/validate.h"
33
34 #if !USE_SHARED_LIBRARY
35 IMPLEMENT_DYNAMIC_CLASS(wxEvtHandler, wxObject)
36 IMPLEMENT_ABSTRACT_CLASS(wxEvent, wxObject)
37 IMPLEMENT_DYNAMIC_CLASS(wxCommandEvent, wxEvent)
38 IMPLEMENT_DYNAMIC_CLASS(wxNotifyEvent, wxCommandEvent)
39 IMPLEMENT_DYNAMIC_CLASS(wxScrollEvent, wxCommandEvent)
40 IMPLEMENT_DYNAMIC_CLASS(wxMouseEvent, wxEvent)
41 IMPLEMENT_DYNAMIC_CLASS(wxKeyEvent, wxEvent)
42 IMPLEMENT_DYNAMIC_CLASS(wxSizeEvent, wxEvent)
43 IMPLEMENT_DYNAMIC_CLASS(wxPaintEvent, wxEvent)
44 IMPLEMENT_DYNAMIC_CLASS(wxEraseEvent, wxEvent)
45 IMPLEMENT_DYNAMIC_CLASS(wxMoveEvent, wxEvent)
46 IMPLEMENT_DYNAMIC_CLASS(wxFocusEvent, wxEvent)
47 IMPLEMENT_DYNAMIC_CLASS(wxCloseEvent, wxEvent)
48 IMPLEMENT_DYNAMIC_CLASS(wxShowEvent, wxEvent)
49 IMPLEMENT_DYNAMIC_CLASS(wxMaximizeEvent, wxEvent)
50 IMPLEMENT_DYNAMIC_CLASS(wxIconizeEvent, wxEvent)
51 IMPLEMENT_DYNAMIC_CLASS(wxMenuEvent, wxEvent)
52 IMPLEMENT_DYNAMIC_CLASS(wxJoystickEvent, wxEvent)
53 IMPLEMENT_DYNAMIC_CLASS(wxDropFilesEvent, wxEvent)
54 IMPLEMENT_DYNAMIC_CLASS(wxActivateEvent, wxEvent)
55 IMPLEMENT_DYNAMIC_CLASS(wxInitDialogEvent, wxEvent)
56 IMPLEMENT_DYNAMIC_CLASS(wxSysColourChangedEvent, wxEvent)
57 IMPLEMENT_DYNAMIC_CLASS(wxIdleEvent, wxEvent)
58 IMPLEMENT_DYNAMIC_CLASS(wxUpdateUIEvent, wxCommandEvent)
59 IMPLEMENT_DYNAMIC_CLASS(wxNavigationKeyEvent, wxCommandEvent)
60 IMPLEMENT_DYNAMIC_CLASS(wxPaletteChangedEvent, wxEvent)
61 IMPLEMENT_DYNAMIC_CLASS(wxQueryNewPaletteEvent, wxEvent)
62
63 const wxEventTable *wxEvtHandler::GetEventTable() const
64 { return &wxEvtHandler::sm_eventTable; }
65
66 const wxEventTable wxEvtHandler::sm_eventTable =
67 { (const wxEventTable *)NULL, &wxEvtHandler::sm_eventTableEntries[0] };
68
69 const wxEventTableEntry wxEvtHandler::sm_eventTableEntries[] =
70 { { 0, 0, 0,
71 #ifdef __SGI_CC__
72 // stupid SGI compiler --- offer aug 98
73 0L }
74 #else // !SGI CC
75 NULL }
76 #endif // SGI/!SGI
77 };
78
79 #endif // !USE_SHARED_LIBRARY
80
81 #if wxUSE_THREADS
82 /* To put pending event handlers */
83 extern wxList *wxPendingEvents;
84 extern wxCriticalSection *wxPendingEventsLocker;
85 #endif
86
87 /*
88 * General wxWindows events, covering
89 * all interesting things that might happen (button clicking, resizing,
90 * setting text in widgets, etc.).
91 *
92 * For each completely new event type, derive a new event class.
93 *
94 */
95
96 wxEvent::wxEvent(int theId)
97 {
98 m_eventType = wxEVT_NULL;
99 m_eventObject = (wxObject *) NULL;
100 m_eventHandle = (char *) NULL;
101 m_timeStamp = 0;
102 m_id = theId;
103 m_skipped = FALSE;
104 m_callbackUserData = (wxObject *) NULL;
105 m_isCommandEvent = FALSE;
106 }
107
108 /*
109 * Command events
110 *
111 */
112
113 wxCommandEvent::wxCommandEvent(wxEventType commandType, int theId)
114 {
115 m_eventType = commandType;
116 m_clientData = (char *) NULL;
117 m_clientObject = (wxClientData *) NULL;
118 m_extraLong = 0;
119 m_commandInt = 0;
120 m_id = theId;
121 m_commandString = (char *) NULL;
122 m_isCommandEvent = TRUE;
123 }
124
125 /*
126 * Scroll events
127 */
128
129 wxScrollEvent::wxScrollEvent(wxEventType commandType,
130 int id,
131 int pos,
132 int orient)
133 : wxCommandEvent(commandType, id)
134 {
135 m_extraLong = orient;
136 m_commandInt = pos;
137 }
138
139
140 /*
141 * Mouse events
142 *
143 */
144
145 wxMouseEvent::wxMouseEvent(wxEventType commandType)
146 {
147 m_eventType = commandType;
148 m_metaDown = FALSE;
149 m_altDown = FALSE;
150 m_controlDown = FALSE;
151 m_shiftDown = FALSE;
152 m_leftDown = FALSE;
153 m_rightDown = FALSE;
154 m_middleDown = FALSE;
155 m_x = 0;
156 m_y = 0;
157 }
158
159 // True if was a button dclick event (1 = left, 2 = middle, 3 = right)
160 // or any button dclick event (but = -1)
161 bool wxMouseEvent::ButtonDClick(int but) const
162 {
163 switch (but)
164 {
165 case -1:
166 return (LeftDClick() || MiddleDClick() || RightDClick());
167 case 1:
168 return LeftDClick();
169 case 2:
170 return MiddleDClick();
171 case 3:
172 return RightDClick();
173 default:
174 wxFAIL_MSG("invalid parameter in wxMouseEvent::ButtonDClick");
175 }
176
177 return FALSE;
178 }
179
180 // True if was a button down event (1 = left, 2 = middle, 3 = right)
181 // or any button down event (but = -1)
182 bool wxMouseEvent::ButtonDown(int but) const
183 {
184 switch (but)
185 {
186 case -1:
187 return (LeftDown() || MiddleDown() || RightDown());
188 case 1:
189 return LeftDown();
190 case 2:
191 return MiddleDown();
192 case 3:
193 return RightDown();
194 default:
195 wxFAIL_MSG("invalid parameter in wxMouseEvent::ButtonDown");
196 }
197
198 return FALSE;
199 }
200
201 // True if was a button up event (1 = left, 2 = middle, 3 = right)
202 // or any button up event (but = -1)
203 bool wxMouseEvent::ButtonUp(int but) const
204 {
205 switch (but) {
206 case -1:
207 return (LeftUp() || MiddleUp() || RightUp());
208 case 1:
209 return LeftUp();
210 case 2:
211 return MiddleUp();
212 case 3:
213 return RightUp();
214 default:
215 wxFAIL_MSG("invalid parameter in wxMouseEvent::ButtonUp");
216 }
217
218 return FALSE;
219 }
220
221 // True if the given button is currently changing state
222 bool wxMouseEvent::Button(int but) const
223 {
224 switch (but) {
225 case -1:
226 return (ButtonUp(-1) || ButtonDown(-1) || ButtonDClick(-1)) ;
227 case 1:
228 return (LeftDown() || LeftUp() || LeftDClick());
229 case 2:
230 return (MiddleDown() || MiddleUp() || MiddleDClick());
231 case 3:
232 return (RightDown() || RightUp() || RightDClick());
233 default:
234 wxFAIL_MSG("invalid parameter in wxMouseEvent::Button");
235 }
236
237 return FALSE;
238 }
239
240 bool wxMouseEvent::ButtonIsDown(int but) const
241 {
242 switch (but) {
243 case -1:
244 return (LeftIsDown() || MiddleIsDown() || RightIsDown());
245 case 1:
246 return LeftIsDown();
247 case 2:
248 return MiddleIsDown();
249 case 3:
250 return RightIsDown();
251 default:
252 wxFAIL_MSG("invalid parameter in wxMouseEvent::ButtonIsDown");
253 }
254
255 return FALSE;
256 }
257
258 // Find the logical position of the event given the DC
259 wxPoint wxMouseEvent::GetLogicalPosition(const wxDC& dc) const
260 {
261 wxPoint pt(dc.DeviceToLogicalX(m_x), dc.DeviceToLogicalY(m_y));
262 return pt;
263 }
264
265
266 /*
267 * Keyboard events
268 *
269 */
270
271 wxKeyEvent::wxKeyEvent(wxEventType type)
272 {
273 m_eventType = type;
274 m_shiftDown = FALSE;
275 m_controlDown = FALSE;
276 m_metaDown = FALSE;
277 m_altDown = FALSE;
278 m_keyCode = 0;
279 }
280
281 /*
282 * Event handler
283 */
284
285 wxEvtHandler::wxEvtHandler()
286 {
287 m_nextHandler = (wxEvtHandler *) NULL;
288 m_previousHandler = (wxEvtHandler *) NULL;
289 m_enabled = TRUE;
290 m_dynamicEvents = (wxList *) NULL;
291 m_isWindow = FALSE;
292 #if wxUSE_THREADS
293 m_eventsLocker = new wxCriticalSection();
294 #endif
295 m_pendingEvents = (wxList *) NULL;
296 }
297
298 wxEvtHandler::~wxEvtHandler()
299 {
300 // Takes itself out of the list of handlers
301 if (m_previousHandler)
302 m_previousHandler->m_nextHandler = m_nextHandler;
303
304 if (m_nextHandler)
305 m_nextHandler->m_previousHandler = m_previousHandler;
306
307 if (m_dynamicEvents)
308 {
309 wxNode *node = m_dynamicEvents->First();
310 while (node)
311 {
312 wxEventTableEntry *entry = (wxEventTableEntry*)node->Data();
313 if (entry->m_callbackUserData) delete entry->m_callbackUserData;
314 delete entry;
315 node = node->Next();
316 }
317 delete m_dynamicEvents;
318 };
319
320 if (m_pendingEvents)
321 delete m_pendingEvents;
322
323 #if wxUSE_THREADS
324 delete m_eventsLocker;
325 #endif
326 }
327
328 #if wxUSE_THREADS
329 bool wxEvtHandler::ProcessThreadEvent(wxEvent& event)
330 {
331 wxEvent *event_main;
332 wxCriticalSectionLocker locker(*m_eventsLocker);
333
334 // check that we are really in a child thread
335 wxASSERT( !wxThread::IsMain() );
336
337 if (m_pendingEvents == NULL)
338 m_pendingEvents = new wxList();
339
340 event_main = (wxEvent *)event.GetClassInfo()->CreateObject();
341 *event_main = event;
342
343 m_pendingEvents->Append(event_main);
344
345 wxPendingEventsLocker->Enter();
346 wxPendingEvents->Append(this);
347 wxPendingEventsLocker->Leave();
348
349 return TRUE;
350 }
351
352 void wxEvtHandler::ProcessPendingEvents()
353 {
354 wxCriticalSectionLocker locker(*m_eventsLocker);
355 wxNode *node = m_pendingEvents->First();
356 wxEvent *event;
357
358 while (node != NULL) {
359 event = (wxEvent *)node->Data();
360 ProcessEvent(*event);
361 delete node;
362 node = m_pendingEvents->First();
363 }
364 }
365 #endif
366
367 /*
368 * Event table stuff
369 */
370
371 bool wxEvtHandler::ProcessEvent(wxEvent& event)
372 {
373 // check that our flag corresponds to reality
374 wxASSERT( m_isWindow == IsKindOf(CLASSINFO(wxWindow)) );
375
376 // An event handler can be enabled or disabled
377 if ( GetEvtHandlerEnabled() )
378 {
379 #if wxUSE_THREADS
380 // Check whether we are in a child thread.
381 if (!wxThread::IsMain())
382 return ProcessThreadEvent(event);
383 #endif
384 // Handle per-instance dynamic event tables first
385
386 if ( m_dynamicEvents && SearchDynamicEventTable(event) )
387 return TRUE;
388
389 // Then static per-class event tables
390
391 const wxEventTable *table = GetEventTable();
392
393 // Try the associated validator first, if this is a window.
394 // Problem: if the event handler of the window has been replaced,
395 // this wxEvtHandler may no longer be a window.
396 // Therefore validators won't be processed if the handler
397 // has been replaced with SetEventHandler.
398 // THIS CAN BE CURED if PushEventHandler is used instead of
399 // SetEventHandler, and then processing will be passed down the
400 // chain of event handlers.
401 if ( m_isWindow )
402 {
403 wxWindow *win = (wxWindow *)this;
404
405 // Can only use the validator of the window which
406 // is receiving the event
407 if ( win == event.GetEventObject() )
408 {
409 wxValidator *validator = win->GetValidator();
410 if ( validator && validator->ProcessEvent(event) )
411 {
412 return TRUE;
413 }
414 }
415 }
416
417 // Search upwards through the inheritance hierarchy
418 while ( table )
419 {
420 if ( SearchEventTable((wxEventTable&)*table, event) )
421 return TRUE;
422 table = table->baseTable;
423 }
424 }
425
426 // Try going down the event handler chain
427 if ( GetNextHandler() )
428 {
429 if ( GetNextHandler()->ProcessEvent(event) )
430 return TRUE;
431 }
432
433 // Carry on up the parent-child hierarchy,
434 // but only if event is a command event: it wouldn't
435 // make sense for a parent to receive a child's size event, for example
436 if ( m_isWindow && event.IsCommandEvent() )
437 {
438 wxWindow *win = (wxWindow *)this;
439 wxWindow *parent = win->GetParent();
440 if (parent && !parent->IsBeingDeleted())
441 return parent->GetEventHandler()->ProcessEvent(event);
442 }
443
444 // Last try - application object.
445 if ( wxTheApp && (this != wxTheApp) )
446 {
447 // Special case: don't pass wxEVT_IDLE to wxApp, since it'll always
448 // swallow it. wxEVT_IDLE is sent explicitly to wxApp so it will be
449 // processed appropriately via SearchEventTable.
450 if ( event.GetEventType() != wxEVT_IDLE )
451 {
452 if ( wxTheApp->ProcessEvent(event) )
453 return TRUE;
454 }
455 }
456
457 return FALSE;
458 }
459
460 bool wxEvtHandler::SearchEventTable(wxEventTable& table, wxEvent& event)
461 {
462 int i = 0;
463 int commandId = event.GetId();
464
465 // BC++ doesn't like while (table.entries[i].m_fn)
466
467 #ifdef __SC__
468 while (table.entries[i].m_fn != 0)
469 #else
470 while (table.entries[i].m_fn != 0L)
471 #endif
472 {
473 if ((event.GetEventType() == table.entries[i].m_eventType) &&
474 (table.entries[i].m_id == -1 || // Match, if event spec says any id will do (id == -1)
475 (table.entries[i].m_lastId == -1 && commandId == table.entries[i].m_id) ||
476 (table.entries[i].m_lastId != -1 &&
477 (commandId >= table.entries[i].m_id && commandId <= table.entries[i].m_lastId))))
478 {
479 event.Skip(FALSE);
480 event.m_callbackUserData = table.entries[i].m_callbackUserData;
481
482 (this->*((wxEventFunction) (table.entries[i].m_fn)))(event);
483
484 if ( event.GetSkipped() )
485 return FALSE;
486 else
487 return TRUE;
488 }
489 i++;
490 }
491 return FALSE;
492 }
493 void wxEvtHandler::Connect( int id, int lastId,
494 wxEventType eventType,
495 wxObjectEventFunction func,
496 wxObject *userData )
497 {
498 wxEventTableEntry *entry = new wxEventTableEntry;
499 entry->m_id = id;
500 entry->m_lastId = lastId;
501 entry->m_eventType = eventType;
502 entry->m_fn = func;
503 entry->m_callbackUserData = userData;
504
505 if (!m_dynamicEvents)
506 m_dynamicEvents = new wxList;
507
508 m_dynamicEvents->Append( (wxObject*) entry );
509 }
510
511 bool wxEvtHandler::SearchDynamicEventTable( wxEvent& event )
512 {
513 wxCHECK_MSG( m_dynamicEvents, FALSE,
514 "caller should check that we have dynamic events" );
515
516 int commandId = event.GetId();
517
518 wxNode *node = m_dynamicEvents->First();
519 while (node)
520 {
521 wxEventTableEntry *entry = (wxEventTableEntry*)node->Data();
522
523 if (entry->m_fn)
524 {
525 // Match, if event spec says any id will do (id == -1)
526 if ( (event.GetEventType() == entry->m_eventType) &&
527 (entry->m_id == -1 ||
528 (entry->m_lastId == -1 && commandId == entry->m_id) ||
529 (entry->m_lastId != -1 &&
530 (commandId >= entry->m_id && commandId <= entry->m_lastId))) )
531 {
532 event.Skip(FALSE);
533 event.m_callbackUserData = entry->m_callbackUserData;
534
535 (this->*((wxEventFunction) (entry->m_fn)))(event);
536
537 if (event.GetSkipped())
538 return FALSE;
539 else
540 return TRUE;
541 }
542 }
543 node = node->Next();
544 }
545 return FALSE;
546 };
547
548 #if WXWIN_COMPATIBILITY
549 bool wxEvtHandler::OnClose()
550 {
551 if (GetNextHandler())
552 return GetNextHandler()->OnClose();
553 else
554 return FALSE;
555 }
556 #endif // WXWIN_COMPATIBILITY
557