[pygtk] Warning when closing top-level windows

Tony Nelson tonynelson at georgeanelson.com
Thu Dec 8 03:55:29 WST 2005


My app can have multiple top-level windows, and I've been fighting with
warnings when closing them.  It seems that something is trying to do stuff
after it's window has been destroyed.  I have been able to work around the
problem, but I don't like my solution.  I think that most GTK apps won't
have this issue, as most have only one top-level window.

Specifically, in a test program, I find that if I have a UIManager and a
focusable widget that needed to set its own action group (in focus-in and
focus-out handlers), that the test app gets (at least) these signals:

    delete      (saves dirty docs per user)
    focus-out   (calls UIManager)
    destroy 	(if last window calls gtk.main_quit())
    assertion failure in gtk_container_foreach, indicating signal
        processing after the window was destroyed

In one case I used gdb (ddd) on my real app to trace the assertion to the
UIManager.  Note that with only one window, destroy calls gtk.main_quit(),
preventing any further signals being delivered.  Disconnecting any signals
I had connected to seemed to fix the problem, until I tried my real app on
a different platform (MSWindows instead of Linux).

What I do now to work around the problem is what I have had to do several
places to work around GTK's delayed delivery of signals:  my delete handler
calls gtk.main_iteration() in a loop until there are no
gtk.events_pending().  This works on both platforms, but it is obviously
dangerous and stupid.  Is it the only way to fix such problems?  Do I have
something else wrong, even in my small test app?

The test app follows.  It is presently set up to display the problem.
Uncomment the call to gtkeat() to enable the current workaround, or change
False to True in on_delete_event to enable the old workaround.

Linux Fedora Core 3, Python 2.3.4, GTK 2.4.14
WinXP SP2, Python 2.4.2, GTK 2.8.6

---
#! /usr/bin/env python2.3
# -*- coding: utf-8 -*-
'''demo gtk warning after close problem
'''

import gtk

def gtkeat():
    '''Brute-force way to get our window updated.

    Note that self.window.process_updates(True) and
    gtk.gdk.window_process_all_updates() don't draw anything at all.
    '''
    while gtk.events_pending():
        gtk.main_iteration(False)

class TestWind(gtk.Window):
    top_level_windows = []

    def __init__(self):
        gtk.Window.__init__(self)
        TestWind.top_level_windows.append(self)
        self.connect('destroy', self.on_destroy)
        self.connect('delete_event', self.on_delete_event)
        self.set_default_size(200, 120)

        box = gtk.VBox(False, 4)
        self.add(box)
        box.show()

        self.uimgr = gtk.UIManager()
        self.add_accel_group(self.uimgr.get_accel_group())
        ag = gtk.ActionGroup('main')
        ag.add_actions([
            ('File',    None, "_File"),
            ('Quit',    gtk.STOCK_QUIT, None, None, None,
                lambda *args: gtk.main_quit()),
        ])
        self.uimgr.insert_action_group(ag, 0)
        self.none_ag = ag = gtk.ActionGroup('none')
        ag.add_actions([
            # Edit menu
            ('Entry', None, 'Entry', None, None, lambda *args: None),
        ])
        self.uimgr.insert_action_group(ag, 3)
        ag.set_property('sensitive', False)
        self.entry_ag = ag = gtk.ActionGroup('entry')
        ag.add_actions([
            # Edit menu
            ('Entry', None, 'Entry', None, None, lambda *args: None),
        ])
        merge_id = self.uimgr.add_ui_from_string('''
            <ui>
                <menubar>
                    <menu action="File">
                        <menuitem action="Entry" />
                        <menuitem action="Quit" />
                    </menu>
                </menubar>
            </ui>''')
        mbar = self.uimgr.get_widget('/menubar')
        mbar.show()
        box.pack_start(mbar, False, False, 0)

        self.entry = e = gtk.Entry(0)
        box.pack_start(e, False, False, 0)
        e.sigids = [
            e.connect('focus-in-event', self.on_focusIn_entry),
            e.connect('focus-out-event', self.on_focusOut_entry) ]
        e.show()

        self.button = gtk.Button('New Window')
        box.pack_start(self.button, False, False, 0)
        self.button.connect('clicked', self.on_new_window)
        self.button.show()

        self.show()

    def on_destroy(self, wid):
        TestWind.top_level_windows.remove(self)
        if not len(TestWind.top_level_windows):
            gtk.main_quit()
        else:
            #gtkeat()
            print 'destroy'

    def on_delete_event(self, a1, a2):
        if False:
            def discon(o):
                for sid in o.sigids:
                    o.disconnect(sid)
            discon(self.entry)
        print 'delete'

    def on_focusIn_entry(self, widget, event):
        self.uimgr.insert_action_group(self.entry_ag, 4)
        self.uimgr.remove_action_group(self.none_ag)
        print 'focus-in'

    def on_focusOut_entry(self, widget, event):
        self.uimgr.insert_action_group(self.none_ag, 3)
        self.uimgr.remove_action_group(self.entry_ag)
        print 'focus-out'

    def on_new_window(self, widget):
        w = TestWind()

TestWind()
gtk.main()
---
____________________________________________________________________
TonyN.:'                       <mailto:tonynelson at georgeanelson.com>
      '                              <http://www.georgeanelson.com/>


More information about the pygtk mailing list