]> git.saurik.com Git - wxWidgets.git/commitdiff
implement the wxGTK selective yield with a different approach: rather than getting...
authorFrancesco Montorsi <f18m_cpp217828@yahoo.it>
Sat, 14 Mar 2009 23:59:21 +0000 (23:59 +0000)
committerFrancesco Montorsi <f18m_cpp217828@yahoo.it>
Sat, 14 Mar 2009 23:59:21 +0000 (23:59 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@59541 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/gtk/evtloop.h
src/gtk/evtloop.cpp

index 36c62e168e1be2607f2ef90bc0af1a32bbd01e18..79cb753185edb892bba583eb9fb0f608f6b84fed 100644 (file)
@@ -15,6 +15,8 @@
 // wxGUIEventLoop for wxGTK
 // ----------------------------------------------------------------------------
 
+typedef union  _GdkEvent        GdkEvent;
+
 class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopBase
 {
 public:
@@ -28,6 +30,9 @@ public:
     virtual void WakeUp();
     virtual bool YieldFor(long eventsToProcess);
 
+    void StoreGdkEventForLaterProcessing(GdkEvent* ev)
+        { m_arrGdkEvents.Add(ev); }
+    
 protected:
 
     // the exit code of this event loop
index 76dbdda5ee78837b47fb007f4109d19df9890ac1..9a5717c06bb7f2e125b9b370e595b0eb17a8d760 100644 (file)
@@ -133,6 +133,78 @@ int wxGUIEventLoop::DispatchTimeout(unsigned long timeout)
 // YieldFor
 //-----------------------------------------------------------------------------
 
+static void wxgtk_main_do_event(GdkEvent *event, wxGUIEventLoop* evtloop)
+{
+    // categorize the GDK event according to wxEventCategory.
+    // See http://library.gnome.org/devel/gdk/unstable/gdk-Events.html#GdkEventType
+    // for more info.
+
+    wxEventCategory cat = wxEVT_CATEGORY_UNKNOWN;
+    switch (event->type)
+    {
+    case GDK_SELECTION_REQUEST:
+    case GDK_SELECTION_NOTIFY:
+    case GDK_SELECTION_CLEAR:
+    case GDK_OWNER_CHANGE:
+        cat = wxEVT_CATEGORY_CLIPBOARD;
+        break;
+
+
+    case GDK_KEY_PRESS:
+    case GDK_KEY_RELEASE:
+    case GDK_BUTTON_PRESS:
+    case GDK_2BUTTON_PRESS:
+    case GDK_3BUTTON_PRESS:
+    case GDK_BUTTON_RELEASE:
+    case GDK_SCROLL:        // generated from mouse buttons
+    case GDK_CLIENT_EVENT:
+        cat = wxEVT_CATEGORY_USER_INPUT;
+        break;
+
+    case GDK_PROXIMITY_IN:
+    case GDK_PROXIMITY_OUT:
+
+    case GDK_MOTION_NOTIFY:
+    case GDK_ENTER_NOTIFY:
+    case GDK_LEAVE_NOTIFY:
+    case GDK_VISIBILITY_NOTIFY:
+    case GDK_PROPERTY_NOTIFY:
+
+    case GDK_FOCUS_CHANGE:
+    case GDK_CONFIGURE:
+    case GDK_WINDOW_STATE:
+    case GDK_SETTING:
+    case GDK_DELETE:
+    case GDK_DESTROY:
+
+    case GDK_EXPOSE:
+    case GDK_NO_EXPOSE:
+    case GDK_MAP:
+    case GDK_UNMAP:
+
+    case GDK_DRAG_ENTER:
+    case GDK_DRAG_LEAVE:
+    case GDK_DRAG_MOTION:
+    case GDK_DRAG_STATUS:
+    case GDK_DROP_START:
+    case GDK_DROP_FINISHED:
+    case GDK_GRAB_BROKEN:
+        cat = wxEVT_CATEGORY_UI;
+        break;
+
+    default:
+        cat = wxEVT_CATEGORY_UNKNOWN;
+        break;
+    }
+
+    // is this event allowed now?
+    if (evtloop->IsEventAllowedInsideYield(cat))
+        gtk_main_do_event(event);         // process it now
+    else if (event->type != GDK_NOTHING)
+        evtloop->StoreGdkEventForLaterProcessing(gdk_event_copy(event));
+            // process it later (but make a copy; the caller will free the event pointer)
+}
+
 bool wxGUIEventLoop::YieldFor(long eventsToProcess)
 {
 #if wxUSE_THREADS
@@ -152,90 +224,18 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess)
     wxLog::Suspend();
 #endif
 
-    // NOTE: gtk_main_iteration() doesn't allow us to filter events, so we
-    //       rather use gtk_main_do_event() after filtering the events at
-    //       GDK level
-
-    GdkDisplay* disp = gtk_widget_get_display(wxGetRootWindow());
-
-    // gdk_display_get_event() will transform X11 events into GDK events
-    // and will queue all of them in the display (private) structure;
-    // finally it will "unqueue" the last one and return it to us
-    GdkEvent* event = gdk_display_get_event(disp);
-    while (event)
-    {
-        // categorize the GDK event according to wxEventCategory.
-        // See http://library.gnome.org/devel/gdk/unstable/gdk-Events.html#GdkEventType
-        // for more info.
-
-        wxEventCategory cat = wxEVT_CATEGORY_UNKNOWN;
-        switch (event->type)
-        {
-        case GDK_SELECTION_REQUEST:
-        case GDK_SELECTION_NOTIFY:
-        case GDK_SELECTION_CLEAR:
-        case GDK_OWNER_CHANGE:
-            cat = wxEVT_CATEGORY_CLIPBOARD;
-            break;
-
-
-        case GDK_KEY_PRESS:
-        case GDK_KEY_RELEASE:
-        case GDK_BUTTON_PRESS:
-        case GDK_2BUTTON_PRESS:
-        case GDK_3BUTTON_PRESS:
-        case GDK_BUTTON_RELEASE:
-        case GDK_SCROLL:        // generated from mouse buttons
-        case GDK_CLIENT_EVENT:
-            cat = wxEVT_CATEGORY_USER_INPUT;
-            break;
-
-
-        case GDK_PROXIMITY_IN:
-        case GDK_PROXIMITY_OUT:
-
-        case GDK_MOTION_NOTIFY:
-        case GDK_ENTER_NOTIFY:
-        case GDK_LEAVE_NOTIFY:
-        case GDK_VISIBILITY_NOTIFY:
-        case GDK_PROPERTY_NOTIFY:
-
-        case GDK_FOCUS_CHANGE:
-        case GDK_CONFIGURE:
-        case GDK_WINDOW_STATE:
-        case GDK_SETTING:
-        case GDK_DELETE:
-        case GDK_DESTROY:
-
-        case GDK_EXPOSE:
-        case GDK_NO_EXPOSE:
-        case GDK_MAP:
-        case GDK_UNMAP:
-        //case GDK_DAMAGE:
-
-        case GDK_DRAG_ENTER:
-        case GDK_DRAG_LEAVE:
-        case GDK_DRAG_MOTION:
-        case GDK_DRAG_STATUS:
-        case GDK_DROP_START:
-        case GDK_DROP_FINISHED:
-        case GDK_GRAB_BROKEN:
-            cat = wxEVT_CATEGORY_UI;
-            break;
-
-        default:
-            cat = wxEVT_CATEGORY_UNKNOWN;
-            break;
-        }
-
-        if (eventsToProcess & cat)
-            gtk_main_do_event(event);       // process it now
-        else
-            m_arrGdkEvents.Add(event);      // process it later
-
-        // get next event
-        event = gdk_display_get_event(disp);
-    }
+    // temporarily replace the global GDK event handler with our function, which
+    // categorizes the events and using m_eventsToProcessInsideYield decides
+    // if an event should be processed immediately or not
+    // NOTE: this approach is better than using gdk_display_get_event() because
+    //       gtk_main_iteration() does more than just calling gdk_display_get_event()
+    //       and then call gtk_main_do_event()!
+    //       In particular in this way we also process input from sources like
+    //       GIOChannels (this is needed for e.g. wxGUIAppTraits::WaitForChild).
+    gdk_event_handler_set ((GdkEventFunc)wxgtk_main_do_event, this, NULL);
+    while (Pending())   // avoid false positives from our idle source
+        gtk_main_iteration();
+    gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
 
     if (eventsToProcess != wxEVT_CATEGORY_CLIPBOARD)
     {
@@ -252,6 +252,7 @@ bool wxGUIEventLoop::YieldFor(long eventsToProcess)
     //      then we fall into a never-ending loop...
 
     // put all unprocessed GDK events back in the queue
+    GdkDisplay* disp = gtk_widget_get_display(wxGetRootWindow());
     for (size_t i=0; i<m_arrGdkEvents.GetCount(); i++)
     {
         GdkEvent* ev = (GdkEvent*)m_arrGdkEvents[i];