#include "wx/thread.h"
+#if wxUSE_BASE
+ #include "wx/ptr_scpd.h"
+
+ wxDECLARE_SCOPED_PTR(wxEvent, wxEventPtr)
+ wxDEFINE_SCOPED_PTR(wxEvent, wxEventPtr)
+#endif // wxUSE_BASE
+
// ----------------------------------------------------------------------------
// wxWin macros
// ----------------------------------------------------------------------------
DEFINE_EVENT_TYPE(wxEVT_COMMAND_TOOL_RCLICKED)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_TOOL_ENTER)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPINCTRL_UPDATED)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED)
DEFINE_EVENT_TYPE(wxEVT_COMMAND_TOOL_DROPDOWN_CLICKED)
// Mouse event types
m_propagationLevel = wxEVENT_PROPAGATE_NONE;
}
-wxEvent::wxEvent(const wxEvent &src)
+wxEvent::wxEvent(const wxEvent& src)
: wxObject(src)
, m_eventObject(src.m_eventObject)
, m_eventType(src.m_eventType)
{
}
+wxEvent& wxEvent::operator=(const wxEvent& src)
+{
+ wxObject::operator=(src);
+
+ m_eventObject = src.m_eventObject;
+ m_eventType = src.m_eventType;
+ m_timeStamp = src.m_timeStamp;
+ m_id = src.m_id;
+ m_callbackUserData = src.m_callbackUserData;
+ m_propagationLevel = src.m_propagationLevel;
+ m_skipped = src.m_skipped;
+ m_isCommandEvent = src.m_isCommandEvent;
+
+ return *this;
+}
+
#endif // wxUSE_BASE
#if wxUSE_GUI
wxString wxCommandEvent::GetString() const
{
- if(m_eventType != wxEVT_COMMAND_TEXT_UPDATED || !m_eventObject)
+ if (m_eventType != wxEVT_COMMAND_TEXT_UPDATED || !m_eventObject)
+ {
return m_cmdString;
+ }
else
{
#if wxUSE_TEXTCTRL
wxTextCtrl *txt = wxDynamicCast(m_eventObject, wxTextCtrl);
- if(txt)
+ if ( txt )
return txt->GetValue();
else
#endif // wxUSE_TEXTCTRL
m_aux1Down = false;
m_aux2Down = false;
- m_controlDown = false;
- m_shiftDown = false;
- m_altDown = false;
- m_metaDown = false;
-
m_clickCount = -1;
m_wheelRotation = 0;
void wxMouseEvent::Assign(const wxMouseEvent& event)
{
- m_eventType = event.m_eventType;
+ wxEvent::operator=(event);
+
+ // Borland C++ 5.82 doesn't compile an explicit call to an implicitly
+ // defined operator=() so need to do it this way:
+ *static_cast<wxMouseState *>(this) = event;
m_x = event.m_x;
m_y = event.m_y;
m_aux1Down = event.m_aux1Down;
m_aux2Down = event.m_aux2Down;
- m_controlDown = event.m_controlDown;
- m_shiftDown = event.m_shiftDown;
- m_altDown = event.m_altDown;
- m_metaDown = event.m_metaDown;
-
m_wheelRotation = event.m_wheelRotation;
m_wheelDelta = event.m_wheelDelta;
m_linesPerAction = event.m_linesPerAction;
wxKeyEvent::wxKeyEvent(wxEventType type)
{
m_eventType = type;
- m_shiftDown = false;
- m_controlDown = false;
- m_metaDown = false;
- m_altDown = false;
m_keyCode = 0;
m_scanCode = 0;
#if wxUSE_UNICODE
}
wxKeyEvent::wxKeyEvent(const wxKeyEvent& evt)
- : wxEvent(evt)
+ : wxEvent(evt),
+ wxKeyboardState(evt)
{
m_x = evt.m_x;
m_y = evt.m_y;
m_keyCode = evt.m_keyCode;
- m_controlDown = evt.m_controlDown;
- m_shiftDown = evt.m_shiftDown;
- m_altDown = evt.m_altDown;
- m_metaDown = evt.m_metaDown;
m_scanCode = evt.m_scanCode;
m_rawCode = evt.m_rawCode;
m_rawFlags = evt.m_rawFlags;
delete[] oldEventTypeTable;
}
-
// ----------------------------------------------------------------------------
// wxEvtHandler
// ----------------------------------------------------------------------------
{
wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)*it;
+ // Remove ourselves from sink destructor notifications
+ // (this has usually been been done, in wxTrackable destructor)
+ wxEvtHandler *eventSink = entry->m_eventSink;
+ if ( eventSink )
+ {
+ wxEventConnectionRef * const
+ evtConnRef = FindRefInTrackerList(eventSink);
+ if ( evtConnRef )
+ {
+ eventSink->RemoveNode(evtConnRef);
+ delete evtConnRef;
+ }
+ }
+
if (entry->m_callbackUserData)
delete entry->m_callbackUserData;
delete entry;
// Remove us from wxPendingEvents if necessary.
if ( wxPendingEvents )
{
- if(wxPendingEventsLocker)
+#if wxUSE_THREADS
+ if (wxPendingEventsLocker)
wxENTER_CRIT_SECT(*wxPendingEventsLocker);
+#endif
if ( wxPendingEvents->DeleteObject(this) )
{
}
//else: we weren't in this list at all, it's ok
- if(wxPendingEventsLocker)
+#if wxUSE_THREADS
+ if (wxPendingEventsLocker)
wxLEAVE_CRIT_SECT(*wxPendingEventsLocker);
+#endif
}
// we only delete object data, not untyped
#endif // wxUSE_THREADS
-void wxEvtHandler::AddPendingEvent(const wxEvent& event)
+void wxEvtHandler::QueueEvent(wxEvent *event)
{
- // 1) Add event to list of pending events of this event handler
-
- wxEvent *eventCopy = event.Clone();
-
- // we must be able to copy the events here so the event class must
- // implement Clone() properly instead of just providing a NULL stab for it
- wxCHECK_RET( eventCopy,
- _T("events of this type aren't supposed to be posted") );
+ wxCHECK_RET( event, "NULL event can't be posted" );
+ // 1) Add this event to our list of pending events
wxENTER_CRIT_SECT( m_pendingEventsLock );
if ( !m_pendingEvents )
m_pendingEvents = new wxList;
- m_pendingEvents->Append(eventCopy);
-
- wxLEAVE_CRIT_SECT( m_pendingEventsLock );
+ m_pendingEvents->Append(event);
// 2) Add this event handler to list of event handlers that
// have pending events.
wxLEAVE_CRIT_SECT(*wxPendingEventsLocker);
+ // only release m_pendingEventsLock now because otherwise there is a race
+ // condition as described in the ticket #9093: we could process the event
+ // just added to m_pendingEvents in our ProcessPendingEvents() below before
+ // we had time to append this pointer to wxPendingEvents list; thus
+ // breaking the invariant that a handler should be in the list iff it has
+ // any pending events to process
+ wxLEAVE_CRIT_SECT( m_pendingEventsLock );
+
// 3) Inform the system that new pending events are somewhere,
// and that these should be processed in idle time.
wxWakeUpIdle();
"should have pending events if called" );
wxList::compatibility_iterator node = m_pendingEvents->GetFirst();
- wxEvent * const event = wx_static_cast(wxEvent *, node->GetData());
+ wxEventPtr event(static_cast<wxEvent *>(node->GetData()));
// it's important we remove event from list before processing it, else a
// nested event loop, for example from a modal dialog, might process the
// if there are no more pending events left, we don't need to stay in this
// list
if ( m_pendingEvents->IsEmpty() )
+ {
+#if wxUSE_THREADS
+ if (wxPendingEventsLocker)
+ wxENTER_CRIT_SECT(*wxPendingEventsLocker);
+#endif
wxPendingEvents->DeleteObject(this);
+#if wxUSE_THREADS
+ if (wxPendingEventsLocker)
+ wxLEAVE_CRIT_SECT(*wxPendingEventsLocker);
+#endif
+ }
wxLEAVE_CRIT_SECT( m_pendingEventsLock );
// careful: this object could have been deleted by the event handler
// executed by the above ProcessEvent() call, so we can't access any fields
// of this object any more
-
- delete event;
}
/*
bool wxEvtHandler::TryParent(wxEvent& event)
{
+ if ( GetNextHandler() )
+ {
+ // the next handler will pass it to wxTheApp if it doesn't process it,
+ // so return from here to avoid doing it again
+ return GetNextHandler()->TryParent(event);
+ }
+
if ( wxTheApp && (this != wxTheApp) )
{
// Special case: don't pass wxEVT_IDLE to wxApp, since it'll always
//else: proceed normally
}
+ if ( ProcessEventHere(event) )
+ return true;
+
+ // propagate the event upwards the window chain and/or to the application
+ // object if it wasn't processed at this level
+ return TryParent(event);
+}
+
+bool wxEvtHandler::ProcessEventHere(wxEvent& event)
+{
// An event handler can be enabled or disabled
if ( GetEvtHandlerEnabled() )
{
}
// Try going down the event handler chain
- if ( GetNextHandler() )
- {
- // notice that we shouldn't let the parent have the event even if the
- // next handler does not process it because it will have already passed
- // it to the parent in this case
- return GetNextHandler()->ProcessEvent(event);
- }
+ if ( GetNextHandler() && GetNextHandler()->ProcessEventHere(event) )
+ return true;
- // Finally propagate the event upwards the window chain and/or to the
- // application object as necessary
- return TryParent(event);
+ // We don't have a handler for this event.
+ return false;
}
bool wxEvtHandler::SafelyProcessEvent(wxEvent& event)
}
void wxEvtHandler::Connect( int id, int lastId,
- int eventType,
+ wxEventType eventType,
wxObjectEventFunction func,
wxObject *userData,
wxEvtHandler* eventSink )
// Insert at the front of the list so most recent additions are found first
m_dynamicEvents->Insert( (wxObject*) entry );
+
+ // Make sure we get to know when a sink is destroyed
+ if ( eventSink && eventSink != this )
+ {
+ wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink);
+ if ( evtConnRef )
+ evtConnRef->IncRef( );
+ else
+ new wxEventConnectionRef(this, eventSink);
+ }
}
bool wxEvtHandler::Disconnect( int id, int lastId, wxEventType eventType,
if (!m_dynamicEvents)
return false;
+ // Remove connection from tracker node (wxEventConnectionRef)
+ if ( eventSink && eventSink != this )
+ {
+ wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink);
+ if ( evtConnRef )
+ evtConnRef->DecRef();
+ }
+
wxList::compatibility_iterator node = m_dynamicEvents->GetFirst();
while (node)
{
return m_clientData;
}
+// A helper to find an wxEventConnectionRef object
+wxEventConnectionRef *
+wxEvtHandler::FindRefInTrackerList(wxEvtHandler *eventSink)
+{
+ for ( wxTrackerNode *node = eventSink->GetFirst(); node; node = node->m_nxt )
+ {
+ // we only want wxEventConnectionRef nodes here
+ wxEventConnectionRef *evtConnRef = node->ToEventConnection();
+ if ( evtConnRef && evtConnRef->m_src == this )
+ {
+ wxASSERT( evtConnRef->m_sink==eventSink );
+ return evtConnRef;
+ }
+ }
+
+ return NULL;
+}
+
+void wxEvtHandler::OnSinkDestroyed( wxEvtHandler *sink )
+{
+ wxASSERT(m_dynamicEvents);
+
+ // remove all connections with this sink
+ wxList::compatibility_iterator node = m_dynamicEvents->GetFirst(), node_nxt;
+ while (node)
+ {
+ wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData();
+ node_nxt = node->GetNext();
+
+ if ( entry->m_eventSink==sink )
+ {
+ if (entry->m_callbackUserData)
+ delete entry->m_callbackUserData;
+ m_dynamicEvents->Erase( node );
+ delete entry;
+ }
+ node = node_nxt;
+ }
+}
+
#endif // wxUSE_BASE
#if wxUSE_GUI