Window closing event is not being sent

I need a reliable method of detecting when the user closes the app, an error happens or simply when the process is being terminated. From what I found, the advised method is to catch a window-event and then ask whether base.win.isClosed. That works fine, unless:

  • You subclass ShowBase
  • Use directtools
  • For whatever reason, the direct.showbase.ShowBase is not under direct control of the app.
from pandac.PandaModules import loadPrcFileData
from direct.showbase.ShowBase import ShowBase
from direct.showbase.DirectObject import DirectObject

class MyApp(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

# Closing event is not sent/catched when I use any of these lines:
#loadPrcFileData("", "want-directtools #t")
#base = MyApp()
base = ShowBase() # It only works when ShowBase is under control

class ExitCatcher(DirectObject):
    def __init__(self):
        DirectObject.__init__(self)
        self.accept('window-event', self._onExit)

    def _onExit(self, *args):
        print "some window event catched" # Other events work just fine
        if base.win.isClosed():
            print "Closing event catched, app can properly clean up."
ExitCatcher()

base.run()

I’m not sure if this is a bug or I’m simply missing something…

Note: You will probably have to run it in some IDE that allows you to see the console even after the app was closed.

Thanks for any and all help!

I think you can still use base.exitFunc=SomeFuncoinNameHere

ShowBase also has a destroy() and exitfunc() that I might override (I think?) There’s also userExit() and it looks like a good candidate.

There is also base.win.setCloseRequestEvent():

base.win.setCloseRequestEvent('exit_stage_right')
accept('exit_stage_right',TurnOffTheLightFunction)

def TurnOffTheLightFunction():
    DoSomeStuffHere()

Solved it with python’s atexit… Still, if this is a bug, someone might want to fix it, right?

This is not a bug. When writing your code you did not consider that - given there are two subscribers to an event - there is no guarantee on the order in which these subscribers are called.

In your case there are two subscribers to the event ‘window-event’:

  • ShowBase.windowEvent
  • ExitCatcher._onExit

The tricky thing is that if ShowBase.window is called first then the application will be shut down, so your own listener is not called. But ShowBase does a neat thing - it calls base.exitFunc() before finally shutting down.

Setting base.exitFunc is the reliable way of running cleanup code provided by Panda3D.

(Please note that base.exitFunc has an uppercase ‘F’. There is also base.exitfunc with lowercase ‘f’, which can be set by a user too. But base.exitfunc is assigned to sys.exitfunc, and thus will be invoked at a later point of time, i.e. from inside sys.exit(). Superfluous in my opinion, since a user could also set sys.exit directly)