Wierd bug in 2.4.2.4 on Linux

The method wx.BeginBusyCursor() calls OnIdle functions.

I was getting an infinite loop due to calling wx.BeginBusyCursor
in my OnIdle handler, which caused the idle handler to called
again which called BeginBusyCursor which caused the idle handler
to be called ... You get the idea :slight_smile:

Putting a guard in my idle handler resolved the issue. However
I really don't think idle handlers should be called if the
event loop is already in one, and certainly not from such
an innocuous call!

Roger

My apologies if this is old news to you and I'm misunderstanding your problem. This should still be useful for everyone else that doesn't know about "idle".

Idle in wxWidgets is poorly named and quite misleading. It is the event that occurs when the event queue empties and has nothing to do with whether the machine is "idle". One typical place you will see a flurry of idle events is while moving the mouse and then beware if you have a long-running task called on idle. <wink> If a TextCtrl has focus then you will see idle events as the cursor blinks, but if the focus is on a control such as a Button you will only see one idle when the event queue empties and then no more until the user does something like move the mouse.

If you are using wx.WakeUpIdle() then you will still want to use an idle event handler, but depending on the situation there might be better alternatives such as wx.CallAfter() or using a timer.

This should probably be a FAQ item.

ka

路路路

On Apr 9, 2004, at 11:31 PM, Roger Binns wrote:

The method wx.BeginBusyCursor() calls OnIdle functions.

I was getting an infinite loop due to calling wx.BeginBusyCursor
in my OnIdle handler, which caused the idle handler to called
again which called BeginBusyCursor which caused the idle handler
to be called ... You get the idea :slight_smile:

Putting a guard in my idle handler resolved the issue. However
I really don't think idle handlers should be called if the
event loop is already in one, and certainly not from such
an innocuous call!

Roger

Kevin Altis wrote:

My apologies if this is old news to you and I'm misunderstanding your
problem. This should still be useful for everyone else that doesn't
know about "idle".

You completely missed my point :slight_smile: I know exactly what an idle handler
is and have been using them for several years. Here is a simpler
illustration of the problem:

Lets say you have an idle handler that looks like this:

  def OnIdle(self, _):
      wx.BeginBusyCursor()
      ... do something ...
      wx.EndBusyCursor()

On Linux, what actually happens is that the call to wx.BeginBusyCursor
causes the idle handler to be recursively invoked, which calls
wx.BeginBusyCursor which causes the idle handler to be invoked which
calls wx.BeginBusyCursor which causes the idle handler to be invoked
which calls wx.BeginBusyCursor which causes the idle handler ......

Here is some code that shows the problem:

On Windows, the idledepth is only ever 1 (ie the idle handler is
not called recursively). On Linux it is called recursively
and you will get infinite recursion. On top of that, you get a
stack trace that gives no actual clue to what the problem
is (for real code anyway, this code does sort of a give a clue)

路路路

==================================================================
import wx

class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, "dummy")
        wx.EVT_IDLE(self, self.OnIdle)
        self.idledepth=0

    def OnIdle(self, _):
        self.idledepth+=1
        wx.BeginBusyCursor(wx.StockCursor(wx.CURSOR_ARROWWAIT))
        print "doing something in idle",self.idledepth
        wx.EndBusyCursor()
        self.idledepth-=1

app=wx.PySimpleApp()
f=MyFrame()
f.Show(True)
app.MainLoop()

==================================================================

Roger

Roger,

There you have a nice way to work around this bug.

    def OnIdle(self, _):
        self.idledepth+=1
        wx.BeginBusyCursor(wx.StockCursor(wx.CURSOR_ARROWWAIT))
        print "doing something in idle",self.idledepth
        wx.EndBusyCursor()
        self.idledepth-=1

Why not change it to:

     def OnIdle(self, _):
         self.idledepth+=1
         if self.idledepth == 1:
           wx.BeginBusyCursor(wx.StockCursor(wx.CURSOR_ARROWWAIT))
           print "doing something in idle",self.idledepth
           wx.EndBusyCursor()
         self.idledepth-=1

--eric

路路路

On 10-apr-04, at 18:26, Roger Binns wrote:

An exception generated during unusual circumstances. Just thought someone might want to patch that hole...

路路路

-------------------------------------------------------------------

From: "Felipe Lazo" <chilenius@hotmail.com>
To: T-0.1.4@degreez.net
Subject: BitTornado Bug

BitTorrent T-0.1.4 (BitTornado)

OS: win32
Python version: 2.3.3 (#51, Dec 18 2003, 20:22:39) [MSC v.1200 32 bit (Intel)]
wxWindows version: 2.5.1.5
Allocation method: normal

Traceback (most recent call last):
聽聽File "btdownloadgui.py", line 429, in onInvoke
聽聽File "btdownloadgui.py", line 1464, in onUpdateStatus
聽聽File "wx\windows.pyc", line 1857, in SetIcon
PyAssertionError: C++ assertion "msg == gs_msgTaskbar" failed in ..\..\src\msw\taskbar.cpp(284)

I was something like this:
Using BitTornado to download Slam Dunk! 51 - 60, http://as.carywater.net, while downloading a game using Download Accelerator and MSN Messenger was connected. I opened NeoRAGEx to play a little. When I closed NeoRAGEx, Windows threw a problem with Explorer, it should be closed. When Explorer reinited (everything dissapeared: taskbar, Init Menu, Icons... as always) the error appeared.

I hope that my error be useful. Chao loco.

There you have a nice way to work around this bug.

Yes, I know and pointed that out in my original message. The
point of my message was to show that a bug existed, that
it is extremely hard to figure out (my OnIdle is a lot
larger than 4 lines), and that as a matter of philosophy
wx should not be calling idle stuff while in an idle loop.
It is also a lesson for anyone who wants to program defensively
that they should ensure their idle handlers are re-entrant.

Roger

Roger Binns wrote:

The method wx.BeginBusyCursor() calls OnIdle functions.

I was getting an infinite loop due to calling wx.BeginBusyCursor
in my OnIdle handler, which caused the idle handler to called
again which called BeginBusyCursor which caused the idle handler
to be called ... You get the idea :slight_smile:

It's probably calling wx.Yeild in order to coerce the cursor to be changed.

Putting a guard in my idle handler resolved the issue. However
I really don't think idle handlers should be called if the
event loop is already in one, and certainly not from such
an innocuous call!

I agree. If it's possible to avoid it, then it should. Enter a bug
report about it please.

路路路

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Robin Dunn wrote:

I agree. If it's possible to avoid it, then it should. Enter a bug
report about it please.

Done. #933744.

Roger