#14760 closed defect (fixed)

wxYield does not flush wxPostEvent events in 2.9.4.

Reported by: bugman Owned by: vadz
Priority: normal Milestone: 3.0.0
Component: wxGTK Version: 2.9.4
Keywords: wxYield, wxPostEvent Cc:
Blocked By: Blocking:
Patch: no

Description

It appears as though in 2.9.4 (as seen via wxPython and discussed at https://groups.google.com/d/topic/wxpython-users/mpWS1yYRMFE/discussion) that a wxYield call does not operate correctly for wxGTK. Application events posted with wxPostEvent are not processed when wxYield is called. wxPython apps are attached to the above discussions and should demonstrate the issue.

Attachments (2)

test_wx_yield.py download (935 bytes) - added by bugman 21 months ago.
test_grid_set.py download (1023 bytes) - added by bugman 21 months ago.

Download all attachments as: .zip

Change History (10)

comment:1 Changed 21 months ago by bugman

I forgot to mention that wxYield calls using wxMSW with 2.9.4 works correctly.

comment:2 Changed 21 months ago by vadz

Could you please try to provide a minimal patch to a sample reproducing the problem?

Changed 21 months ago by bugman

Changed 21 months ago by bugman

comment:3 Changed 21 months ago by bugman

I'm afraid that a patch might be a bit much for me - I am unfamiliar with the wxWidget sources, and I would guess that this problem is quite deep. I am the project admin for an external project called relax (http://www.nmr-relax.com) which uses wxWidgets via wxPython, and relax's test suite uncovered this problem. Is there documentation on how to convert a wxPython app to the equivalent C++ app? I have created 2 wxPython apps attached to https://groups.google.com/forum/#!topic/wxpython-users/mpWS1yYRMFE/discussion (now attached to this report as well), but I do not know how to start to convert these to C++ apps.

comment:4 Changed 21 months ago by vadz

  • Status changed from new to infoneeded_new

wxYield() does result in idle events for me, here is the test code I used:

  • samples/minimal/minimal.cpp

    diff --git a/samples/minimal/minimal.cpp b/samples/minimal/minimal.cpp
    index a78e462..1cef7c4 100644
    a b class MyFrame : public wxFrame 
    6767    // event handlers (these functions should _not_ be virtual) 
    6868    void OnQuit(wxCommandEvent& event); 
    6969    void OnAbout(wxCommandEvent& event); 
     70    void OnIdle(wxIdleEvent& event) 
     71    { 
     72        wxLogDebug("Idling."); 
     73        event.Skip(); 
     74    } 
    7075 
    7176private: 
    7277    // any class wishing to process wxWidgets events must use this macro 
    enum 
    99104BEGIN_EVENT_TABLE(MyFrame, wxFrame) 
    100105    EVT_MENU(Minimal_Quit,  MyFrame::OnQuit) 
    101106    EVT_MENU(Minimal_About, MyFrame::OnAbout) 
     107    EVT_IDLE(MyFrame::OnIdle) 
    102108END_EVENT_TABLE() 
    103109 
    104110// Create a new application object: this macro will allow wxWidgets to create 
    void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) 
    185191 
    186192void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) 
    187193{ 
     194    wxLogDebug("Calling wxYield()..."); 
     195    wxYield(); 
     196    wxLogDebug("Sleeping..."); 
     197    wxMilliSleep(2500); 
     198    wxLogDebug("Woke up, returning."); 
     199    return; 
     200 
    188201    wxMessageBox(wxString::Format 
    189202                 ( 
    190203                    "Welcome to %s!\n" 

Pressing "F1" to enter MyFrame::OnAbout() results in the following output:

12:56:22: Debug: Calling wxYield()...
12:56:22: Debug: Idling.
12:56:22: Debug: Sleeping...
12:56:25: Debug: Woke up, returning.
12:56:25: Debug: Idling.

as expected.

So I don't understand what the problem is, actually. I.e. what do you expect to happen in these Python examples and what really happens? Do you mean that CallAfter() doesn't work? If so, could you please confirm it directly (i.e. by calling some function printing timestamp to stdout)?

comment:5 Changed 21 months ago by robind

  • Status changed from infoneeded_new to new

First, it's not necessarily idle events that are missing in these cases, but the processing of the pending event queue. At least for events that are bound to and posted to the wxApp object. (wxPython's CallAfter uses the App object as the target for the posted events since TLW's can come and go but the App is forever.)

In the sample programs the expected behavior is that those events should be delivered while in the wx.Yield, resulting in the CallAfter's event handler calling the functions, but on wxGTK 2.9.x they are not happening until control returns to the main event loop. So it seems that either the pending event queue is not being processed while in the yield, or something is deferring the App's events until later.

Here is the CallAfter implementation for reference:

def CallAfter(callableObj, *args, **kw):
    """
    Call the specified function after the current and pending event
    handlers have been completed.  This is also good for making GUI
    method calls from non-GUI threads.  Any extra positional or
    keyword args are passed on to the callable when it is called.

    :see: `wx.CallLater`
    """
    assert callable(callableObj), "callableObj is not callable"
    app = wx.GetApp()
    assert app is not None, 'No wx.App created yet'

    if not hasattr(app, "_CallAfterId"):
        app._CallAfterId = wx.NewEventType()
        app.Connect(-1, -1, app._CallAfterId,
                    lambda event: event.callable(*event.args, **event.kw) )
    evt = wx.PyEvent()
    evt.SetEventType(app._CallAfterId)
    evt.callable = callableObj
    evt.args = args
    evt.kw = kw
    wx.PostEvent(app, evt)

comment:6 Changed 21 months ago by vadz

  • Milestone set to 3.0
  • Owner set to vadz
  • Status changed from new to accepted

OK, let me try to implement CallAfter() for C++ and then I'll test this with it.

comment:7 Changed 21 months ago by vadz

I can confirm that it doesn't work. A comment in wxGTK wxGUIEventLoop::YieldFor() says that calling ProcessIdle() also calls ProcessPendingEvents() but this is not true [any more]. Just adding an explicit call to ProcessPendingEvents() is enough to fix the problem so I'll probably just do it, unless somebody sees a reason not to.

comment:8 Changed 21 months ago by VZ

  • Resolution set to fixed
  • Status changed from accepted to closed

(In [72723]) Process pending events from wxYield() in wxGTK.

Calling wxYield() is supposed to process the pending events but it didn't, any
more, in wxGTK. Restore this by explicitly calling ProcessPendingEvents() from
wxGTK wxYield() implementation as wxGUIEventLoop::ProcessIdle() does not call
it, in spite of a comment to the contrary in the sources.

Closes #14760.

Note: See TracTickets for help on using tickets.