memory protection fault on shutdown of wx application

Hi all,

after my Debian/Testing system upgraded a few
wxwidgets/wxPython/gtk components my wxPython program
started saying:

  (python:12854): Gtk-CRITICAL **: gtk_container_remove: assertion `GTK_IS_TOOLBAR (container) || widget->parent == GTK_WIDGET (container)' failed

although I didn't change any code at that time. This is
shown a couple times on the console after which the program
crashes with a "Speicherzugriffsfehler" (memory access
error). The crash occurs after my top level frame's
OnClose() handler has called self.Destroy() but before my
application's OnExit() method is invoked.

What sort of things should I scan my wxPython code for ?

Thanks,
Karsten

···

--
GPG key ID E4071346 @ wwwkeys.pgp.net
E167 67FD A291 2BEA 73BD 4537 78B9 A9F9 E407 1346

Karsten Hilbert wrote:

Hi all,

after my Debian/Testing system upgraded a few
wxwidgets/wxPython/gtk components my wxPython program
started saying:

  (python:12854): Gtk-CRITICAL **: gtk_container_remove: assertion `GTK_IS_TOOLBAR (container) || widget->parent == GTK_WIDGET (container)' failed

although I didn't change any code at that time. This is
shown a couple times on the console after which the program
crashes with a "Speicherzugriffsfehler" (memory access
error). The crash occurs after my top level frame's
OnClose() handler has called self.Destroy() but before my
application's OnExit() method is invoked.

What sort of things should I scan my wxPython code for ?

Do you get a core file? If so try loading it into gdb and doing a backtrace to see the callstack.

···

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

after my Debian/Testing system upgraded a few
wxwidgets/wxPython/gtk components my wxPython program
started saying:
  (python:12854): Gtk-CRITICAL **: gtk_container_remove: assertion
`GTK_IS_TOOLBAR (container) || widget->parent == GTK_WIDGET (container)'
failed
although I didn't change any code at that time. This is
shown a couple times on the console after which the program
crashes with a "Speicherzugriffsfehler" (memory access
error). The crash occurs after my top level frame's
OnClose() handler has called self.Destroy() but before my
application's OnExit() method is invoked.

A few more datapoints:

  2.6.3.2 ('__WXGTK__', 'wxGTK', 'unicode', 'gtk2', 'wx-assertions-off', 'SWIG-1.3.27')

By "my Debian system upgraded" I do not mean a version
change as in wxPython 2.4 -> 2.6 or something similar, just
the regular "apt-get upgrade" dance.

What sort of things should I scan my wxPython code for ?

Do you get a core file?

Not in any of

  /
  ~/
  ./
  /tmp
  /var/tmp/
  /var/run/

that I can see. Anywhere else I need to look ?

If so try loading it into gdb and doing a backtrace to see the callstack.

Could I attach gdb to a running instance and go from there ?
If so, how ?

Thanks,
Karsten

···

On Tue, Oct 09, 2007 at 10:08:25AM -0700, Robin Dunn wrote:
--
GPG key ID E4071346 @ wwwkeys.pgp.net
E167 67FD A291 2BEA 73BD 4537 78B9 A9F9 E407 1346

Karsten Hilbert wrote:

after my Debian/Testing system upgraded a few
wxwidgets/wxPython/gtk components my wxPython program
started saying:
  (python:12854): Gtk-CRITICAL **: gtk_container_remove: assertion `GTK_IS_TOOLBAR (container) || widget->parent == GTK_WIDGET (container)' failed
although I didn't change any code at that time. This is
shown a couple times on the console after which the program
crashes with a "Speicherzugriffsfehler" (memory access
error). The crash occurs after my top level frame's
OnClose() handler has called self.Destroy() but before my
application's OnExit() method is invoked.

A few more datapoints:

  2.6.3.2 ('__WXGTK__', 'wxGTK', 'unicode', 'gtk2', 'wx-assertions-off', 'SWIG-1.3.27')

By "my Debian system upgraded" I do not mean a version
change as in wxPython 2.4 -> 2.6 or something similar, just
the regular "apt-get upgrade" dance.

What is the version of libgtk2.0? Did it get upgraded? wx 2.6 is very old so I wouldn't be too surprised if it has problems with a newer libgtk.

What sort of things should I scan my wxPython code for ?

Do you get a core file?

Not in any of

  /
  ~/
  ./
  /tmp
  /var/tmp/
  /var/run/

that I can see. Anywhere else I need to look ?

You may need to run "ulimit -c unlimited" to turn on the generation of the core files and/or allow larger ones to be created.

If so try loading it into gdb and doing a backtrace to see the callstack.

Could I attach gdb to a running instance and go from there ?
If so, how ?

Yep. In your Python app do something like "import os; print "PID:", os.getpid()" in the main module's startup. Then run your app and make note of the printed value. Run gdb with the full path to Python on the command-line and then at the prompt type "attach [the pid]" and then "continue" (the commands can be abbreviated...)

···

On Tue, Oct 09, 2007 at 10:08:25AM -0700, Robin Dunn wrote:

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

  2.6.3.2 ('__WXGTK__', 'wxGTK', 'unicode', 'gtk2', 'wx-assertions-off',
'SWIG-1.3.27')
By "my Debian system upgraded" I do not mean a version
change as in wxPython 2.4 -> 2.6 or something similar, just
the regular "apt-get upgrade" dance.

What is the version of libgtk2.0?

Provides: gtk2.0-binver-2.10.0

Did it get upgraded?

Unfortunately I cannot find that out anymore. I seem to
remember so but am not entirely sure.

wx 2.6 is very old

I know but Debian (Testing) doesn't have a newer version.

so I wouldn't be too surprised if it has problems with a newer libgtk.

I fear as much. If we can verify that it'd make for a good
argument for filing a "please upgrade to new upstream" bug
against python-wxgtk2.6 in Debian proper.

Yep. In your Python app do something like "import os; print "PID:",
os.getpid()" in the main module's startup. Then run your app and make note
of the printed value. Run gdb with the full path to Python on the
command-line and then at the prompt type "attach [the pid]" and then
"continue" (the commands can be abbreviated...)

Here goes:

Loaded symbols for /usr/lib/gtk-2.0/2.10.0/loaders/libpixbufloader-xpm.so
Reading symbols from /usr/lib/python2.4/lib-dynload/md5.so...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/python2.4/lib-dynload/md5.so
Reading symbols from /usr/lib/python2.4/site-packages/wx-2.6-gtk2-unicode/wx/_html.so...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/python2.4/site-packages/wx-2.6-gtk2-unicode/wx/_html.so
(no debugging symbols found)
0xffffe410 in __kernel_vsyscall ()
(gdb) continue
Continuing.

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb7dac6b0 (LWP 18592)]
0x00000039 in ?? ()
(gdb) bt
#0 0x00000039 in ?? ()
#1 0xb719ae02 in wxWindowBase::~wxWindowBase () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#2 0xb70a17a9 in wxWindow::~wxWindow () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#3 0xb71b9d6d in wxPanel::~wxPanel () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#4 0xb712728b in wxBookCtrlBase::DeletePage () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#5 0xb710b0c5 in wxNotebook::DeleteAllPages () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#6 0xb710cce0 in wxNotebook::~wxNotebook () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#7 0xb7195cc3 in wxWindowBase::DestroyChildren () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#8 0xb70a16bc in wxWindow::~wxWindow () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#9 0xb71b9d6d in wxPanel::~wxPanel () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#10 0xb7195cc3 in wxWindowBase::DestroyChildren () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#11 0xb70a16bc in wxWindow::~wxWindow () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#12 0xb71920b1 in wxTopLevelWindowBase::~wxTopLevelWindowBase () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#13 0xb7098739 in wxTopLevelWindowGTK::~wxTopLevelWindowGTK () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#14 0xb7149eef in wxFrameBase::~wxFrameBase () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#15 0xb70f140f in wxFrame::~wxFrame () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#16 0xb712425e in wxAppBase::DeletePendingObjects () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#17 0xb71242cd in wxAppBase::OnIdle () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#18 0xb6e6f665 in wxAppConsole::HandleEvent () from /usr/lib/libwx_baseu-2.6.so.0
#19 0xb6efce82 in wxEvtHandler::ProcessEventIfMatches () from /usr/lib/libwx_baseu-2.6.so.0
#20 0xb6efcfcb in wxEventHashTable::HandleEvent () from /usr/lib/libwx_baseu-2.6.so.0
#21 0xb6efd14f in wxEvtHandler::ProcessEvent () from /usr/lib/libwx_baseu-2.6.so.0
#22 0xb712467c in wxAppBase::ProcessIdle () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#23 0xb7072416 in ?? () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#24 0xb66e11a1 in ?? () from /usr/lib/libglib-2.0.so.0
#25 0x00000000 in ?? ()
(gdb) continue
Continuing.

Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
(gdb)

Does this help any ?

Thanks,
Karsten

···

On Tue, Oct 09, 2007 at 11:18:48AM -0700, Robin Dunn wrote:
--
GPG key ID E4071346 @ wwwkeys.pgp.net
E167 67FD A291 2BEA 73BD 4537 78B9 A9F9 E407 1346

Debian rocks, but it is a little anal when it comes to keeping current.
There are instructions on the wxPython website for how to upgrade. While I
don't think our company has wxPython installed on our Debian boxes, we've
upgraded many other packages beyond what comes with Debian and haven't had
any problems. You can always give it a try:
http://www.wxpython.org/download.php

Mike

···

-----Original Message-----
From: Karsten Hilbert [mailto:Karsten.Hilbert@gmx.net]
Sent: Tuesday, October 09, 2007 3:43 PM
To: wxPython-users@lists.wxwidgets.org
Subject: Re: [wxPython-users] memory protection fault on
shutdown of wxapplication

On Tue, Oct 09, 2007 at 11:18:48AM -0700, Robin Dunn wrote:

>> 2.6.3.2 ('__WXGTK__', 'wxGTK', 'unicode', 'gtk2',
>> 'wx-assertions-off',
>> 'SWIG-1.3.27')
>> By "my Debian system upgraded" I do not mean a version
change as in
>> wxPython 2.4 -> 2.6 or something similar, just the regular
"apt-get
>> upgrade" dance.
>
> What is the version of libgtk2.0?
Provides: gtk2.0-binver-2.10.0

> Did it get upgraded?
Unfortunately I cannot find that out anymore. I seem to
remember so but am not entirely sure.

> wx 2.6 is very old
I know but Debian (Testing) doesn't have a newer version.

> so I wouldn't be too surprised if it has problems with a
newer libgtk.
I fear as much. If we can verify that it'd make for a good
argument for filing a "please upgrade to new upstream" bug
against python-wxgtk2.6 in Debian proper.

> Yep. In your Python app do something like "import os;
print "PID:",
> os.getpid()" in the main module's startup. Then run your
app and make note
> of the printed value. Run gdb with the full path to Python on the
> command-line and then at the prompt type "attach [the pid]"
and then
> "continue" (the commands can be abbreviated...)

Here goes:

Loaded symbols for
/usr/lib/gtk-2.0/2.10.0/loaders/libpixbufloader-xpm.so
Reading symbols from
/usr/lib/python2.4/lib-dynload/md5.so...(no debugging symbols
found)...done.
Loaded symbols for /usr/lib/python2.4/lib-dynload/md5.so
Reading symbols from
/usr/lib/python2.4/site-packages/wx-2.6-gtk2-unicode/wx/_html.
so...(no debugging symbols found)...done.
Loaded symbols for
/usr/lib/python2.4/site-packages/wx-2.6-gtk2-unicode/wx/_html.so
(no debugging symbols found)
0xffffe410 in __kernel_vsyscall ()
(gdb) continue
Continuing.

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb7dac6b0 (LWP 18592)]
0x00000039 in ?? ()
(gdb) bt
#0 0x00000039 in ?? ()
#1 0xb719ae02 in wxWindowBase::~wxWindowBase () from
/usr/lib/libwx_gtk2u_core-2.6.so.0
#2 0xb70a17a9 in wxWindow::~wxWindow () from
/usr/lib/libwx_gtk2u_core-2.6.so.0
#3 0xb71b9d6d in wxPanel::~wxPanel () from
/usr/lib/libwx_gtk2u_core-2.6.so.0
#4 0xb712728b in wxBookCtrlBase::DeletePage () from
/usr/lib/libwx_gtk2u_core-2.6.so.0
#5 0xb710b0c5 in wxNotebook::DeleteAllPages () from
/usr/lib/libwx_gtk2u_core-2.6.so.0
#6 0xb710cce0 in wxNotebook::~wxNotebook () from
/usr/lib/libwx_gtk2u_core-2.6.so.0
#7 0xb7195cc3 in wxWindowBase::DestroyChildren () from
/usr/lib/libwx_gtk2u_core-2.6.so.0
#8 0xb70a16bc in wxWindow::~wxWindow () from
/usr/lib/libwx_gtk2u_core-2.6.so.0
#9 0xb71b9d6d in wxPanel::~wxPanel () from
/usr/lib/libwx_gtk2u_core-2.6.so.0
#10 0xb7195cc3 in wxWindowBase::DestroyChildren () from
/usr/lib/libwx_gtk2u_core-2.6.so.0
#11 0xb70a16bc in wxWindow::~wxWindow () from
/usr/lib/libwx_gtk2u_core-2.6.so.0
#12 0xb71920b1 in wxTopLevelWindowBase::~wxTopLevelWindowBase
() from /usr/lib/libwx_gtk2u_core-2.6.so.0
#13 0xb7098739 in wxTopLevelWindowGTK::~wxTopLevelWindowGTK
() from /usr/lib/libwx_gtk2u_core-2.6.so.0
#14 0xb7149eef in wxFrameBase::~wxFrameBase () from
/usr/lib/libwx_gtk2u_core-2.6.so.0
#15 0xb70f140f in wxFrame::~wxFrame () from
/usr/lib/libwx_gtk2u_core-2.6.so.0
#16 0xb712425e in wxAppBase::DeletePendingObjects () from
/usr/lib/libwx_gtk2u_core-2.6.so.0
#17 0xb71242cd in wxAppBase::OnIdle () from
/usr/lib/libwx_gtk2u_core-2.6.so.0
#18 0xb6e6f665 in wxAppConsole::HandleEvent () from
/usr/lib/libwx_baseu-2.6.so.0
#19 0xb6efce82 in wxEvtHandler::ProcessEventIfMatches () from
/usr/lib/libwx_baseu-2.6.so.0
#20 0xb6efcfcb in wxEventHashTable::HandleEvent () from
/usr/lib/libwx_baseu-2.6.so.0
#21 0xb6efd14f in wxEvtHandler::ProcessEvent () from
/usr/lib/libwx_baseu-2.6.so.0
#22 0xb712467c in wxAppBase::ProcessIdle () from
/usr/lib/libwx_gtk2u_core-2.6.so.0
#23 0xb7072416 in ?? () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#24 0xb66e11a1 in ?? () from /usr/lib/libglib-2.0.so.0
#25 0x00000000 in ?? ()
(gdb) continue
Continuing.

Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
(gdb)

Does this help any ?

Thanks,
Karsten
--
GPG key ID E4071346 @ wwwkeys.pgp.net
E167 67FD A291 2BEA 73BD 4537 78B9 A9F9 E407 1346

Karsten Hilbert wrote:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb7dac6b0 (LWP 18592)]
0x00000039 in ?? ()
(gdb) bt
#0 0x00000039 in ?? ()
#1 0xb719ae02 in wxWindowBase::~wxWindowBase () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#2 0xb70a17a9 in wxWindow::~wxWindow () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#3 0xb71b9d6d in wxPanel::~wxPanel () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#4 0xb712728b in wxBookCtrlBase::DeletePage () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#5 0xb710b0c5 in wxNotebook::DeleteAllPages () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#6 0xb710cce0 in wxNotebook::~wxNotebook () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#7 0xb7195cc3 in wxWindowBase::DestroyChildren () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#8 0xb70a16bc in wxWindow::~wxWindow () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#9 0xb71b9d6d in wxPanel::~wxPanel () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#10 0xb7195cc3 in wxWindowBase::DestroyChildren () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#11 0xb70a16bc in wxWindow::~wxWindow () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#12 0xb71920b1 in wxTopLevelWindowBase::~wxTopLevelWindowBase () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#13 0xb7098739 in wxTopLevelWindowGTK::~wxTopLevelWindowGTK () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#14 0xb7149eef in wxFrameBase::~wxFrameBase () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#15 0xb70f140f in wxFrame::~wxFrame () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#16 0xb712425e in wxAppBase::DeletePendingObjects () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#17 0xb71242cd in wxAppBase::OnIdle () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#18 0xb6e6f665 in wxAppConsole::HandleEvent () from /usr/lib/libwx_baseu-2.6.so.0
#19 0xb6efce82 in wxEvtHandler::ProcessEventIfMatches () from /usr/lib/libwx_baseu-2.6.so.0
#20 0xb6efcfcb in wxEventHashTable::HandleEvent () from /usr/lib/libwx_baseu-2.6.so.0
#21 0xb6efd14f in wxEvtHandler::ProcessEvent () from /usr/lib/libwx_baseu-2.6.so.0
#22 0xb712467c in wxAppBase::ProcessIdle () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#23 0xb7072416 in ?? () from /usr/lib/libwx_gtk2u_core-2.6.so.0
#24 0xb66e11a1 in ?? () from /usr/lib/libglib-2.0.so.0
#25 0x00000000 in ?? ()
(gdb) continue
Continuing.

Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
(gdb)

Does this help any ?

Yes and no. It's the kind of info I was looking for but it doesn't show anything out of the ordinary other than the segfault. It looks like a normal shutdown sequence. You've got a frame being destroyed, which is destroying its children which is destroying a notebook which is destroying a page window... You don't happen to have the page window parented to something besides the notebook do you? If that's not it then we'll probably need to have the problem duplicated in a small sample that we can play with.

···

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

Tell you what. The segfault and the gtk assert were
unrelated. Your suggestion turned out not to be the root of
the failure but it prompted me to carefully audit our
notebook pages. Selective loading quickly isolated one page
causing the crash. Within the constructor of which the
following code looked fishy:

  ...
  dt = wx.FileDropTarget.__init__(self)
  self.SetDropTarget(dt)
  self._LBOX_doc_pages.SetDropTarget(dt)
  ...

If I remove the third line or insert a

  dt = gmGuiHelpers.cFileDropTarget(self._LBOX_doc_pages)

before it the crash goes away :slight_smile: (the asserts are still
there but they are non-fatal so I can debug at a more
convenient time).

Thanks to all who offered ideas.

Karsten

···

On Wed, Oct 10, 2007 at 02:43:40PM -0700, Robin Dunn wrote:

Yes and no. It's the kind of info I was looking for but it doesn't show
anything out of the ordinary other than the segfault. It looks like a
normal shutdown sequence. You've got a frame being destroyed, which is
destroying its children which is destroying a notebook which is destroying
a page window... You don't happen to have the page window parented to
something besides the notebook do you?

--
GPG key ID E4071346 @ wwwkeys.pgp.net
E167 67FD A291 2BEA 73BD 4537 78B9 A9F9 E407 1346

Debian rocks, but it is a little anal when it comes to keeping current.

In this case it is not so much Debian as such being tight
about keeping current but rather the package maintainers
decision. We are running Debian/Testing which is getting new
packages at 10 days notice of the package maintainer. Many
packages are reasonably up to date. However, wxpython ones
aren't due to conservatism on the part of the maintainers
(not even in experimental).

There are instructions on the wxPython website for how to upgrade.
Redirecting...

I'll keep that in mind. One design decision we made for
GNUmed is that on a Debian system it should be as easy as

  apt-get install gnumed-client

(and it is, currently).

However, *recent* GNUmed versions are available on Etch only
of course, so we already do expect the user to run Testing
which may or may not require some fiddling with sources.list
and/or apt.conf, however indirectly (say, via synaptics).

So, it may not be entirely unreasonable to make them add a
repository line for wxPython debs to their system.

But we'll spare that for when bugs *force* us to do so. We
have wxp2.8 testing on Windows/Mac/Suse anyway so we aren't
missing out on that aspect.

Thanks,
Karsten

···

On Wed, Oct 10, 2007 at 08:56:07AM -0500, Mike Driscoll wrote:
--
GPG key ID E4071346 @ wwwkeys.pgp.net
E167 67FD A291 2BEA 73BD 4537 78B9 A9F9 E407 1346

Karsten Hilbert wrote:

···

On Wed, Oct 10, 2007 at 02:43:40PM -0700, Robin Dunn wrote:

Yes and no. It's the kind of info I was looking for but it doesn't show anything out of the ordinary other than the segfault. It looks like a normal shutdown sequence. You've got a frame being destroyed, which is destroying its children which is destroying a notebook which is destroying a page window... You don't happen to have the page window parented to something besides the notebook do you?

Tell you what. The segfault and the gtk assert were
unrelated. Your suggestion turned out not to be the root of
the failure but it prompted me to carefully audit our
notebook pages. Selective loading quickly isolated one page
causing the crash. Within the constructor of which the
following code looked fishy:

  ...
  dt = wx.FileDropTarget.__init__(self)
  self.SetDropTarget(dt)
  self._LBOX_doc_pages.SetDropTarget(dt)
  ...

If I remove the third line or insert a

  dt = gmGuiHelpers.cFileDropTarget(self._LBOX_doc_pages)

before it the crash goes away :slight_smile:

Ah, yes that would do it. The windows assume that if they have a drop target then they own it and will destroy it when they are destroyed. So that drop target was getting destroyed twice.

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