]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/event.cpp
Use wxRound() instead of (int)(my_double + 0.5);
[wxWidgets.git] / src / common / event.cpp
index 9eb05a0bbfa01d36e65345fcd315e6c4a61adce9..884a443dd1e3e2eadebd1f7c628fc37044fac5cb 100644 (file)
@@ -38,6 +38,7 @@
         #include "wx/window.h"
         #include "wx/control.h"
         #include "wx/dc.h"
+        #include "wx/spinbutt.h"
         #include "wx/textctrl.h"
         #include "wx/validate.h"
     #endif // wxUSE_GUI
@@ -46,7 +47,7 @@
 #include "wx/thread.h"
 
 #if wxUSE_BASE
-    #include "wx/ptr_scpd.h"
+    #include "wx/scopedptr.h"
 
     wxDECLARE_SCOPED_PTR(wxEvent, wxEventPtr)
     wxDEFINE_SCOPED_PTR(wxEvent, wxEventPtr)
@@ -64,6 +65,7 @@
 
 #if wxUSE_GUI
     IMPLEMENT_DYNAMIC_CLASS(wxCommandEvent, wxEvent)
+    IMPLEMENT_DYNAMIC_CLASS(wxThreadEvent, wxCommandEvent)
     IMPLEMENT_DYNAMIC_CLASS(wxNotifyEvent, wxCommandEvent)
     IMPLEMENT_DYNAMIC_CLASS(wxScrollEvent, wxCommandEvent)
     IMPLEMENT_DYNAMIC_CLASS(wxScrollWinEvent, wxEvent)
@@ -146,6 +148,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxEventTableEntryModule, wxModule)
 // List containing event handlers with pending events (each handler can occur
 // at most once here)
 wxList *wxHandlersWithPendingEvents = NULL;
+wxList *wxHandlersWithPendingDelayedEvents = NULL;
 
 #if wxUSE_THREADS
     // protects wxHandlersWithPendingEvents list
@@ -232,6 +235,21 @@ wxDEFINE_EVENT( wxEVT_SCROLL_THUMBTRACK, wxScrollEvent )
 wxDEFINE_EVENT( wxEVT_SCROLL_THUMBRELEASE, wxScrollEvent )
 wxDEFINE_EVENT( wxEVT_SCROLL_CHANGED, wxScrollEvent )
 
+// Due to a bug in older wx versions, wxSpinEvents were being sent with type of
+// wxEVT_SCROLL_LINEUP, wxEVT_SCROLL_LINEDOWN and wxEVT_SCROLL_THUMBTRACK. But
+// with the type-safe events in place, these event types are associated with
+// wxScrollEvent. To allow handling of spin events, new event types have been
+// defined in spinbutt.h/spinnbuttcmn.cpp. To maintain backward compatibility
+// the spin event types are being initialized with the scroll event types.
+
+#if wxUSE_SPINBTN
+
+wxDEFINE_EVENT_ALIAS( wxEVT_SPIN_UP,   wxSpinEvent, wxEVT_SCROLL_LINEUP )
+wxDEFINE_EVENT_ALIAS( wxEVT_SPIN_DOWN, wxSpinEvent, wxEVT_SCROLL_LINEDOWN )
+wxDEFINE_EVENT_ALIAS( wxEVT_SPIN,      wxSpinEvent, wxEVT_SCROLL_THUMBTRACK )
+
+#endif // wxUSE_SPINBTN
+
 // Scroll events from wxWindow
 wxDEFINE_EVENT( wxEVT_SCROLLWIN_TOP, wxScrollWinEvent )
 wxDEFINE_EVENT( wxEVT_SCROLLWIN_BOTTOM, wxScrollWinEvent )
@@ -300,6 +318,9 @@ wxDEFINE_EVENT( wxEVT_COMMAND_ENTER, wxCommandEvent )
 wxDEFINE_EVENT( wxEVT_HELP, wxHelpEvent )
 wxDEFINE_EVENT( wxEVT_DETAILED_HELP, wxHelpEvent )
 
+// Thread event
+wxDEFINE_EVENT( wxEVT_COMMAND_THREAD, wxThreadEvent )
+
 #endif // wxUSE_GUI
 
 #if wxUSE_BASE
@@ -334,15 +355,14 @@ wxEventFunctor::~wxEventFunctor()
 // ----------------------------------------------------------------------------
 
 /*
- * General wxWidgets events, covering
- * all interesting things that might happen (button clicking, resizing,
- * setting text in widgets, etc.).
+ * General wxWidgets events, covering all interesting things that might happen
+ * (button clicking, resizing, setting text in widgets, etc.).
  *
  * For each completely new event type, derive a new event class.
  *
  */
 
-wxEvent::wxEvent(int theId, wxEventType commandType )
+wxEvent::wxEvent(int theId, wxEventType commandType)
 {
     m_eventType = commandType;
     m_eventObject = NULL;
@@ -352,6 +372,7 @@ wxEvent::wxEvent(int theId, wxEventType commandType )
     m_callbackUserData = NULL;
     m_isCommandEvent = false;
     m_propagationLevel = wxEVENT_PROPAGATE_NONE;
+    m_wasProcessed = false;
 }
 
 wxEvent::wxEvent(const wxEvent& src)
@@ -364,6 +385,7 @@ wxEvent::wxEvent(const wxEvent& src)
     , m_propagationLevel(src.m_propagationLevel)
     , m_skipped(src.m_skipped)
     , m_isCommandEvent(src.m_isCommandEvent)
+    , m_wasProcessed(false)
 {
 }
 
@@ -380,6 +402,8 @@ wxEvent& wxEvent::operator=(const wxEvent& src)
     m_skipped = src.m_skipped;
     m_isCommandEvent = src.m_isCommandEvent;
 
+    // don't change m_wasProcessed
+
     return *this;
 }
 
@@ -895,11 +919,9 @@ bool wxEventHashTable::HandleEvent(wxEvent &event, wxEvtHandler *self)
         const size_t count = eventEntryTable.GetCount();
         for (size_t n = 0; n < count; n++)
         {
-            if ( wxEvtHandler::
-                    ProcessEventIfMatches(*eventEntryTable[n], self, event) )
-            {
+            const wxEventTableEntry& entry = *eventEntryTable[n];
+            if ( wxEvtHandler::ProcessEventIfMatchesId(entry, self, event) )
                 return true;
-            }
         }
     }
 
@@ -1034,12 +1056,7 @@ wxEvtHandler::wxEvtHandler()
 
 wxEvtHandler::~wxEvtHandler()
 {
-    // Takes itself out of the list of handlers
-    if (m_previousHandler)
-        m_previousHandler->m_nextHandler = m_nextHandler;
-
-    if (m_nextHandler)
-        m_nextHandler->m_previousHandler = m_previousHandler;
+    Unlink();
 
     if (m_dynamicEvents)
     {
@@ -1052,7 +1069,7 @@ wxEvtHandler::~wxEvtHandler()
 
             // Remove ourselves from sink destructor notifications
             // (this has usually been done, in wxTrackable destructor)
-            wxEvtHandler *eventSink = entry->m_fn->GetHandler();
+            wxEvtHandler *eventSink = entry->m_fn->GetEvtHandler();
             if ( eventSink )
             {
                 wxEventConnectionRef * const
@@ -1090,6 +1107,14 @@ wxEvtHandler::~wxEvtHandler()
         }
         //else: we weren't in this list at all, it's ok
 
+        if ( wxHandlersWithPendingDelayedEvents->DeleteObject(this) )
+        {
+            // check that we were present only once in the list
+            wxASSERT_MSG( !wxHandlersWithPendingDelayedEvents->Find(this),
+                          "Handler occurs twice in wxHandlersWithPendingDelayedEvents list" );
+        }
+        //else: we weren't in this list at all, it's ok
+
 #if wxUSE_THREADS
         if (wxHandlersWithPendingEventsLocker)
             wxLEAVE_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
@@ -1101,6 +1126,26 @@ wxEvtHandler::~wxEvtHandler()
         delete m_clientObject;
 }
 
+void wxEvtHandler::Unlink()
+{
+    // this event handler must take itself out of the chain of handlers:
+
+    if (m_previousHandler)
+        m_previousHandler->SetNextHandler(m_nextHandler);
+
+    if (m_nextHandler)
+        m_nextHandler->SetPreviousHandler(m_previousHandler);
+
+    m_nextHandler = NULL;
+    m_previousHandler = NULL;
+}
+
+bool wxEvtHandler::IsUnlinked() const
+{
+    return m_previousHandler == NULL &&
+           m_nextHandler == NULL;
+}
+
 #if wxUSE_THREADS
 
 bool wxEvtHandler::ProcessThreadEvent(const wxEvent& event)
@@ -1155,6 +1200,10 @@ void wxEvtHandler::QueueEvent(wxEvent *event)
 
 void wxEvtHandler::ProcessPendingEvents()
 {
+    // we need to process only a single pending event in this call because
+    // each call to ProcessEvent() could result in the destruction of this
+    // same event handler (see the comment at the end of this function)
+
     wxENTER_CRIT_SECT( m_pendingEventsLock );
 
     // this method is only called by wxApp if this handler does have
@@ -1163,7 +1212,40 @@ void wxEvtHandler::ProcessPendingEvents()
                  "should have pending events if called" );
 
     wxList::compatibility_iterator node = m_pendingEvents->GetFirst();
-    wxEventPtr event(static_cast<wxEvent *>(node->GetData()));
+    wxEvent* pEvent = static_cast<wxEvent *>(node->GetData());
+
+    // find the first event which can be processed now:
+    if (wxTheApp && wxTheApp->IsYielding())
+    {
+        while (node && pEvent && !wxTheApp->IsEventAllowedInsideYield(pEvent->GetEventCategory()))
+        {
+            node = node->GetNext();
+            pEvent = node ? static_cast<wxEvent *>(node->GetData()) : NULL;
+        }
+
+        if (!node)
+        {
+            // all our events are NOT processable now... signal this:
+#if wxUSE_THREADS
+            if (wxHandlersWithPendingEventsLocker)
+                wxENTER_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
+#endif
+            // move us from the list of handlers with processable pending events
+            // to the list of handlers with pending events which needs to be processed later
+            wxHandlersWithPendingEvents->DeleteObject(this);
+            if ( !wxHandlersWithPendingDelayedEvents->Find(this) )
+                wxHandlersWithPendingDelayedEvents->Append(this);
+#if wxUSE_THREADS
+            if (wxHandlersWithPendingEventsLocker)
+                wxLEAVE_CRIT_SECT(*wxHandlersWithPendingEventsLocker);
+#endif
+            wxLEAVE_CRIT_SECT( m_pendingEventsLock );
+
+            return;
+        }
+    }
+
+    wxEventPtr event(pEvent);
 
     // it's important we remove event from list before processing it, else a
     // nested event loop, for example from a modal dialog, might process the
@@ -1198,9 +1280,9 @@ void wxEvtHandler::ProcessPendingEvents()
  * Event table stuff
  */
 /* static */ bool
-wxEvtHandler::ProcessEventIfMatches(const wxEventTableEntryBase& entry,
-                                    wxEvtHandler *handler,
-                                    wxEvent& event)
+wxEvtHandler::ProcessEventIfMatchesId(const wxEventTableEntryBase& entry,
+                                      wxEvtHandler *handler,
+                                      wxEvent& event)
 {
     int tableId1 = entry.m_id,
         tableId2 = entry.m_lastId;
@@ -1265,22 +1347,56 @@ bool wxEvtHandler::TryParent(wxEvent& event)
 bool wxEvtHandler::ProcessEvent(wxEvent& event)
 {
     // allow the application to hook into event processing
-    if ( wxTheApp )
+    //
+    // note that we should only do it if we're the first event handler called
+    // to avoid calling FilterEvent() multiple times as the event goes through
+    // the event handler chain and possibly upwards the window hierarchy
+    if ( !event.WasProcessed() )
     {
-        int rc = wxTheApp->FilterEvent(event);
-        if ( rc != -1 )
+        if ( wxTheApp )
         {
-            wxASSERT_MSG( rc == 1 || rc == 0,
-                          _T("unexpected wxApp::FilterEvent return value") );
+/*
+    CANNOT ENABLE: ProcessEvent() must always immediately process the event!
+
+            if (wxTheApp->IsYielding() &&
+                !wxTheApp->IsEventAllowedInsideYield(event.GetEventCategory()))
+            {
+                wxEvent* queuedEv = event.Clone();
+
+                // queue this event rather than processing it now
+                QueueEvent(queuedEv);
+                    // the wxWakeUpIdle call shouldn't probably be done
+                    // in this context (there's wxYield in the call stack)
 
-            return rc != 0;
+                return true;
+                    // it's not completely true that the event was processed;
+                    // but we cannot even say it was skipped or discarded...
+            }
+            //else: either we're not inside a wxYield() call or if we are,
+            //      we can process this event immediately.
+*/
+
+            int rc = wxTheApp->FilterEvent(event);
+            if ( rc != -1 )
+            {
+                wxASSERT_MSG( rc == 1 || rc == 0,
+                              "unexpected wxApp::FilterEvent return value" );
+
+                return rc != 0;
+            }
+            //else: proceed normally
         }
-        //else: proceed normally
     }
 
     if ( ProcessEventHere(event) )
         return true;
 
+    // pass the event to the next handler, notice that we shouldn't call
+    // TryParent() even if it doesn't handle the event as the last handler in
+    // the chain will do it
+    if ( GetNextHandler() )
+        return GetNextHandler()->ProcessEvent(event);
+
     // propagate the event upwards the window chain and/or to the application
     // object if it wasn't processed at this level
     return TryParent(event);
@@ -1288,25 +1404,21 @@ bool wxEvtHandler::ProcessEvent(wxEvent& event)
 
 bool wxEvtHandler::ProcessEventHere(wxEvent& event)
 {
-    // An event handler can be enabled or disabled
-    if ( GetEvtHandlerEnabled() )
-    {
-        // if we have a validator, it has higher priority than our own event
-        // table
-        if ( TryValidator(event) )
-            return true;
+    // If the event handler is disabled it doesn't process any events
+    if ( !GetEvtHandlerEnabled() )
+        return false;
 
-        // Handle per-instance dynamic event tables first
-        if ( m_dynamicEvents && SearchDynamicEventTable(event) )
-            return true;
+    // If we have a validator, it has higher priority than our own event
+    // handlers
+    if ( TryValidator(event) )
+        return true;
 
-        // Then static per-class event tables
-        if ( GetEventHashTable().HandleEvent(event, this) )
-            return true;
-    }
+    // Handle per-instance dynamic event tables first
+    if ( m_dynamicEvents && SearchDynamicEventTable(event) )
+        return true;
 
-    // Try going down the event handler chain
-    if ( GetNextHandler() && GetNextHandler()->ProcessEventHere(event) )
+    // Then static per-class event tables
+    if ( GetEventHashTable().HandleEvent(event, this) )
         return true;
 
     // We don't have a handler for this event.
@@ -1358,7 +1470,7 @@ bool wxEvtHandler::SearchEventTable(wxEventTable& table, wxEvent& event)
         const wxEventTableEntry& entry = table.entries[i];
         if ( eventType == entry.m_eventType )
         {
-            if ( ProcessEventIfMatches(entry, this, event) )
+            if ( ProcessEventIfMatchesId(entry, this, event) )
                 return true;
         }
     }
@@ -1366,10 +1478,11 @@ bool wxEvtHandler::SearchEventTable(wxEventTable& table, wxEvent& event)
     return false;
 }
 
-void wxEvtHandler::Subscribe( int id, int lastId,
-                            wxEventType eventType,
-                            wxEventFunctor *func,
-                            wxObject *userData )
+void wxEvtHandler::DoConnect(int id,
+                             int lastId,
+                             wxEventType eventType,
+                             wxEventFunctor *func,
+                             wxObject *userData)
 {
     wxDynamicEventTableEntry *entry =
         new wxDynamicEventTableEntry(eventType, id, lastId, func, userData);
@@ -1381,7 +1494,7 @@ void wxEvtHandler::Subscribe( int id, int lastId,
     m_dynamicEvents->Insert( (wxObject*) entry );
 
     // Make sure we get to know when a sink is destroyed
-    wxEvtHandler *eventSink = func->GetHandler();
+    wxEvtHandler *eventSink = func->GetEvtHandler();
     if ( eventSink && eventSink != this )
     {
         wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink);
@@ -1393,17 +1506,17 @@ void wxEvtHandler::Subscribe( int id, int lastId,
 }
 
 bool
-wxEvtHandler::Unsubscribe(int id,
-                          int lastId,
-                          wxEventType eventType,
-                          const wxEventFunctor& func,
-                          wxObject *userData)
+wxEvtHandler::DoDisconnect(int id,
+                           int lastId,
+                           wxEventType eventType,
+                           const wxEventFunctor& func,
+                           wxObject *userData)
 {
     if (!m_dynamicEvents)
         return false;
 
     // Remove connection from tracker node (wxEventConnectionRef)
-    wxEvtHandler *eventSink = func.GetHandler();
+    wxEvtHandler *eventSink = func.GetEvtHandler();
     if ( eventSink && eventSink != this )
     {
         wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink);
@@ -1419,7 +1532,7 @@ wxEvtHandler::Unsubscribe(int id,
         if ((entry->m_id == id) &&
             ((entry->m_lastId == lastId) || (lastId == wxID_ANY)) &&
             ((entry->m_eventType == eventType) || (eventType == wxEVT_NULL)) &&
-            (*entry->m_fn == func) &&
+            entry->m_fn->Matches(func) &&
             ((entry->m_callbackUserData == userData) || !userData))
         {
             delete entry->m_callbackUserData;
@@ -1446,10 +1559,12 @@ bool wxEvtHandler::SearchDynamicEventTable( wxEvent& event )
         // call Disconnect() invalidating the current node
         node = node->GetNext();
 
-        if ((event.GetEventType() == entry->m_eventType) && (entry->m_fn != 0))
+        if ( event.GetEventType() == entry->m_eventType )
         {
-            wxEvtHandler *handler = entry->m_fn->GetHandler() ? entry->m_fn->GetHandler() : this;
-            if ( ProcessEventIfMatches(*entry, handler, event) )
+            wxEvtHandler *handler = entry->m_fn->GetEvtHandler();
+            if ( !handler )
+               handler = this;
+            if ( ProcessEventIfMatchesId(*entry, handler, event) )
                 return true;
         }
     }
@@ -1527,7 +1642,7 @@ void wxEvtHandler::OnSinkDestroyed( wxEvtHandler *sink )
         wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData();
         node_nxt = node->GetNext();
 
-        if ( entry->m_fn->GetHandler() == sink )
+        if ( entry->m_fn->GetEvtHandler() == sink )
         {
             delete entry->m_callbackUserData;
             m_dynamicEvents->Erase( node );