Browse Source

Deprecate DirectStart and run(), allow clean ShowBase teardown, docstrings for ShowBase members

rdb 10 years ago
parent
commit
753b1c623d

+ 2 - 1
direct/src/directbase/DirectStart.py

@@ -1,4 +1,5 @@
-print 'DirectStart: Starting the game.'
+__all__ = []
+print('Using deprecated DirectStart interface.')
 
 
 from direct.showbase import ShowBase
 from direct.showbase import ShowBase
 base = ShowBase.ShowBase()
 base = ShowBase.ShowBase()

+ 2 - 0
direct/src/directnotify/DirectNotifyGlobal.py

@@ -1,5 +1,7 @@
 """instantiate global DirectNotify used in Direct"""
 """instantiate global DirectNotify used in Direct"""
 
 
+__all__ = ['directNotify', 'giveNotify']
+
 import DirectNotify
 import DirectNotify
 
 
 directNotify = DirectNotify.DirectNotify()
 directNotify = DirectNotify.DirectNotify()

+ 5 - 0
direct/src/showbase/EventManager.py

@@ -187,3 +187,8 @@ class EventManager:
 
 
     def shutdown(self):
     def shutdown(self):
         taskMgr.remove('eventManager')
         taskMgr.remove('eventManager')
+
+        # Flush the event queue.  We do this after removing the task
+        # since the task removal itself might also fire off an event.
+        if self.eventQueue is not None:
+            self.eventQueue.clear()

+ 114 - 83
direct/src/showbase/ShowBase.py

@@ -14,12 +14,12 @@ from panda3d.direct import get_config_showbase, throw_new_frame, init_app_for_gu
 import __builtin__
 import __builtin__
 __builtin__.config = get_config_showbase()
 __builtin__.config = get_config_showbase()
 
 
-from direct.directnotify.DirectNotifyGlobal import *
-from MessengerGlobal import *
-from BulletinBoardGlobal import *
-from direct.task.TaskManagerGlobal import *
-from JobManagerGlobal import *
-from EventManagerGlobal import *
+from direct.directnotify.DirectNotifyGlobal import directNotify, giveNotify
+from MessengerGlobal import messenger
+from BulletinBoardGlobal import bulletinBoard
+from direct.task.TaskManagerGlobal import taskMgr
+from JobManagerGlobal import jobMgr
+from EventManagerGlobal import eventMgr
 from PythonUtil import *
 from PythonUtil import *
 from direct.showbase import PythonUtil
 from direct.showbase import PythonUtil
 #from direct.interval.IntervalManager import ivalMgr
 #from direct.interval.IntervalManager import ivalMgr
@@ -29,11 +29,11 @@ from direct.showbase.BufferViewer import BufferViewer
 from direct.task import Task
 from direct.task import Task
 from direct.directutil import Verify
 from direct.directutil import Verify
 from direct.showbase import GarbageReport
 from direct.showbase import GarbageReport
-import EventManager
 import math,sys,os
 import math,sys,os
 import Loader
 import Loader
 import time
 import time
 import gc
 import gc
+import atexit
 from direct.fsm import ClassicFSM
 from direct.fsm import ClassicFSM
 from direct.fsm import State
 from direct.fsm import State
 from direct.showbase import ExceptionVarDump
 from direct.showbase import ExceptionVarDump
@@ -47,6 +47,14 @@ import AppRunnerGlobal
 __builtin__.FADE_SORT_INDEX = 1000
 __builtin__.FADE_SORT_INDEX = 1000
 __builtin__.NO_FADE_SORT_INDEX = 2000
 __builtin__.NO_FADE_SORT_INDEX = 2000
 
 
+def legacyRun():
+    __builtin__.base.notify.warning("run() is deprecated, use base.run() instead")
+    __builtin__.base.run()
+
[email protected]
+def exitfunc():
+    if getattr(__builtin__, 'base', None) is not None:
+        __builtin__.base.destroy()
 
 
 # Now ShowBase is a DirectObject.  We need this so ShowBase can hang
 # Now ShowBase is a DirectObject.  We need this so ShowBase can hang
 # hooks on messages, particularly on window-event.  This doesn't
 # hooks on messages, particularly on window-event.  This doesn't
@@ -65,11 +73,12 @@ class ShowBase(DirectObject.DirectObject):
         if logStackDump or uploadStackDump:
         if logStackDump or uploadStackDump:
             ExceptionVarDump.install(logStackDump, uploadStackDump)
             ExceptionVarDump.install(logStackDump, uploadStackDump)
 
 
-        # Locate the directory containing the main program
+        ## The directory containing the main Python file of this application.
         self.mainDir = ExecutionEnvironment.getEnvironmentVariable("MAIN_DIR")
         self.mainDir = ExecutionEnvironment.getEnvironmentVariable("MAIN_DIR")
 
 
-        # The appRunner should have been created by the time ShowBase
-        # has been.
+        ## This contains the global appRunner instance, as imported from
+        ## AppRunnerGlobal.  This will be None if we are not running in the
+        ## runtime environment (ie. from a .p3d file).
         self.appRunner = AppRunnerGlobal.appRunner
         self.appRunner = AppRunnerGlobal.appRunner
 
 
         #debug running multiplier
         #debug running multiplier
@@ -108,13 +117,13 @@ class ShowBase(DirectObject.DirectObject):
         self.wantTk = False
         self.wantTk = False
         self.wantWx = False
         self.wantWx = False
 
 
-        # Fill this in with a function to invoke when the user "exits"
-        # the program by closing the main window.
+        ## Fill this in with a function to invoke when the user "exits"
+        ## the program by closing the main window.
         self.exitFunc = None
         self.exitFunc = None
 
 
-        # Add final-exit callbacks to this list.  These will be called
-        # when sys.exit() is called, after Panda has unloaded, and
-        # just before Python is about to shut down.
+        ## Add final-exit callbacks to this list.  These will be called
+        ## when sys.exit() is called, after Panda has unloaded, and
+        ## just before Python is about to shut down.
         self.finalExitCallbacks = []
         self.finalExitCallbacks = []
 
 
         Task.TaskManager.taskTimerVerbose = self.config.GetBool('task-timer-verbose', 0)
         Task.TaskManager.taskTimerVerbose = self.config.GetBool('task-timer-verbose', 0)
@@ -139,13 +148,15 @@ class ShowBase(DirectObject.DirectObject):
         # we get a window-event.
         # we get a window-event.
         self.__oldAspectRatio = None
         self.__oldAspectRatio = None
 
 
+        ## This is set to the value of the window-type config variable, but may
+        ## optionally be overridden in the Showbase constructor.  Should either be
+        ## 'onscreen' (the default), 'offscreen' or 'none'.
         self.windowType = windowType
         self.windowType = windowType
         if self.windowType is None:
         if self.windowType is None:
             self.windowType = self.config.GetString('window-type', 'onscreen')
             self.windowType = self.config.GetString('window-type', 'onscreen')
         self.requireWindow = self.config.GetBool('require-window', 1)
         self.requireWindow = self.config.GetBool('require-window', 1)
 
 
-        # base.win is the main, or only window; base.winList is a list of
-        # *all* windows.  Similarly with base.camList.
+        ## This is the main, or only window; see winList for a list of *all* windows.
         self.win = None
         self.win = None
         self.frameRateMeter = None
         self.frameRateMeter = None
         self.sceneGraphAnalyzerMeter = None
         self.sceneGraphAnalyzerMeter = None
@@ -165,17 +176,29 @@ class ShowBase(DirectObject.DirectObject):
         self.trackball = None
         self.trackball = None
         self.texmem = None
         self.texmem = None
         self.showVertices = None
         self.showVertices = None
+
+        ## This is a NodePath pointing to the Camera object set up for the 3D scene.
+        ## This is usually a child of self.camera.
         self.cam = None
         self.cam = None
         self.cam2d = None
         self.cam2d = None
         self.cam2dp = None
         self.cam2dp = None
+
+        ## This is the NodePath that should be used to manipulate the camera.  This
+        ## is the node to which the default camera is attached.
         self.camera = None
         self.camera = None
         self.camera2d = None
         self.camera2d = None
         self.camera2dp = None
         self.camera2dp = None
+
+        ## This is a list of all cameras created with makeCamera, including base.cam.
         self.camList = []
         self.camList = []
+        ## Convenience accessor for base.cam.node()
         self.camNode = None
         self.camNode = None
+        ## Convenience accessor for base.camNode.get_lens()
         self.camLens = None
         self.camLens = None
         self.camFrustumVis = None
         self.camFrustumVis = None
         self.direct = None
         self.direct = None
+        ## This is used to store the wx.Application object used when want-wx is
+        ## set or base.startWx() is called.
         self.wxApp = None
         self.wxApp = None
         self.tkRoot = None
         self.tkRoot = None
 
 
@@ -189,6 +212,7 @@ class ShowBase(DirectObject.DirectObject):
 
 
         self.hidden = NodePath('hidden')
         self.hidden = NodePath('hidden')
 
 
+        ## The global graphics engine, ie. GraphicsEngine.getGlobalPtr()
         self.graphicsEngine = GraphicsEngine.getGlobalPtr()
         self.graphicsEngine = GraphicsEngine.getGlobalPtr()
         self.setupRender()
         self.setupRender()
         self.setupRender2d()
         self.setupRender2d()
@@ -198,11 +222,11 @@ class ShowBase(DirectObject.DirectObject):
             self.setupRender2dp()
             self.setupRender2dp()
 
 
 
 
-        # This is a placeholder for a CollisionTraverser.  If someone
-        # stores a CollisionTraverser pointer here, we'll traverse it
-        # in the collisionLoop task.
-        self.shadowTrav = 0
+        ## This is a placeholder for a CollisionTraverser.  If someone
+        ## stores a CollisionTraverser pointer here, we'll traverse it
+        ## in the collisionLoop task.
         self.cTrav = 0
         self.cTrav = 0
+        self.shadowTrav = 0
         self.cTravStack = Stack()
         self.cTravStack = Stack()
         # Ditto for an AppTraverser.
         # Ditto for an AppTraverser.
         self.appTrav = 0
         self.appTrav = 0
@@ -233,10 +257,6 @@ class ShowBase(DirectObject.DirectObject):
             random.seed(seed)
             random.seed(seed)
             #whrandom.seed(seed & 0xff, (seed >> 8) & 0xff, (seed >> 16) & 0xff)
             #whrandom.seed(seed & 0xff, (seed >> 8) & 0xff, (seed >> 16) & 0xff)
 
 
-        # Now that we've set up the window structures, assign an exitfunc.
-        self.oldexitfunc = getattr(sys, 'exitfunc', None)
-        sys.exitfunc = self.exitfunc
-
         # Open the default rendering window.
         # Open the default rendering window.
         if self.windowType != 'none':
         if self.windowType != 'none':
             props = WindowProperties.getDefault()
             props = WindowProperties.getDefault()
@@ -254,17 +274,22 @@ class ShowBase(DirectObject.DirectObject):
         self.loader = Loader.Loader(self)
         self.loader = Loader.Loader(self)
         self.graphicsEngine.setDefaultLoader(self.loader.loader)
         self.graphicsEngine.setDefaultLoader(self.loader.loader)
 
 
+        ## The global event manager, as imported from EventManagerGlobal.
         self.eventMgr = eventMgr
         self.eventMgr = eventMgr
+        ## The global messenger, as imported from MessengerGlobal.
         self.messenger = messenger
         self.messenger = messenger
+        ## The global bulletin board, as imported from BulletinBoardGlobal.
         self.bboard = bulletinBoard
         self.bboard = bulletinBoard
+        ## The global task manager, as imported from TaskManagerGlobal.
         self.taskMgr = taskMgr
         self.taskMgr = taskMgr
+        ## The global job manager, as imported from JobManagerGlobal.
         self.jobMgr = jobMgr
         self.jobMgr = jobMgr
 
 
-        # Particle manager
+        ## Particle manager
         self.particleMgr = None
         self.particleMgr = None
         self.particleMgrEnabled = 0
         self.particleMgrEnabled = 0
 
 
-        # Physics manager
+        ## Physics manager
         self.physicsMgr = None
         self.physicsMgr = None
         self.physicsMgrEnabled = 0
         self.physicsMgrEnabled = 0
         self.physicsMgrAngular = 0
         self.physicsMgrAngular = 0
@@ -316,6 +341,8 @@ class ShowBase(DirectObject.DirectObject):
         if 'base' in __builtin__.__dict__:
         if 'base' in __builtin__.__dict__:
             raise StandardError, "Attempt to spawn multiple ShowBase instances!"
             raise StandardError, "Attempt to spawn multiple ShowBase instances!"
 
 
+        # DO NOT ADD TO THIS LIST.  We're trying to phase out the use of
+        # built-in variables by ShowBase.  Use a Global module if necessary.
         __builtin__.base = self
         __builtin__.base = self
         __builtin__.render2d = self.render2d
         __builtin__.render2d = self.render2d
         __builtin__.aspect2d = self.aspect2d
         __builtin__.aspect2d = self.aspect2d
@@ -331,7 +358,7 @@ class ShowBase(DirectObject.DirectObject):
         __builtin__.bboard = self.bboard
         __builtin__.bboard = self.bboard
         # Config needs to be defined before ShowBase is constructed
         # Config needs to be defined before ShowBase is constructed
         #__builtin__.config = self.config
         #__builtin__.config = self.config
-        __builtin__.run = self.run
+        __builtin__.run = legacyRun
         __builtin__.ostream = Notify.out()
         __builtin__.ostream = Notify.out()
         __builtin__.directNotify = directNotify
         __builtin__.directNotify = directNotify
         __builtin__.giveNotify = giveNotify
         __builtin__.giveNotify = giveNotify
@@ -426,7 +453,7 @@ class ShowBase(DirectObject.DirectObject):
         self.cTrav = self.cTravStack.pop()
         self.cTrav = self.cTravStack.pop()
 
 
     def __setupProfile(self):
     def __setupProfile(self):
-        """ Sets up the Python profiler, if avaialable, according to
+        """ Sets up the Python profiler, if available, according to
         some Panda config settings. """
         some Panda config settings. """
 
 
         try:
         try:
@@ -445,8 +472,7 @@ class ShowBase(DirectObject.DirectObject):
         return 0
         return 0
 
 
     def printEnvDebugInfo(self):
     def printEnvDebugInfo(self):
-        """
-        Print some information about the environment that we are running
+        """Print some information about the environment that we are running
         in.  Stuff like the model paths and other paths.  Feel free to
         in.  Stuff like the model paths and other paths.  Feel free to
         add stuff to this.
         add stuff to this.
         """
         """
@@ -470,11 +496,18 @@ class ShowBase(DirectObject.DirectObject):
         for cb in self.finalExitCallbacks[:]:
         for cb in self.finalExitCallbacks[:]:
             cb()
             cb()
 
 
+        # Remove the built-in base reference
+        if getattr(__builtin__, 'base', None) is self:
+            del __builtin__.base
+            del __builtin__.loader
+            del __builtin__.taskMgr
+
         # [gjeon] restore sticky key settings
         # [gjeon] restore sticky key settings
         if self.config.GetBool('disable-sticky-keys', 0):
         if self.config.GetBool('disable-sticky-keys', 0):
             allowAccessibilityShortcutKeys(True)
             allowAccessibilityShortcutKeys(True)
 
 
-        taskMgr.destroy()
+        self.ignoreAll()
+        self.shutdown()
 
 
         if getattr(self, 'musicManager', None):
         if getattr(self, 'musicManager', None):
             self.musicManager.shutdown()
             self.musicManager.shutdown()
@@ -501,19 +534,6 @@ class ShowBase(DirectObject.DirectObject):
         vfs = VirtualFileSystem.getGlobalPtr()
         vfs = VirtualFileSystem.getGlobalPtr()
         vfs.unmountAll()
         vfs.unmountAll()
 
 
-
-    def exitfunc(self):
-        """
-        This should be assigned to sys.exitfunc to be called just
-        before Python shutdown.  It guarantees that the Panda window
-        is closed cleanly, so that we free system resources, restore
-        the desktop and keyboard functionality, etc.
-        """
-        self.destroy()
-
-        if self.oldexitfunc:
-            self.oldexitfunc()
-
     def makeDefaultPipe(self, printPipeTypes = True):
     def makeDefaultPipe(self, printPipeTypes = True):
         """
         """
         Creates the default GraphicsPipe, which will be used to make
         Creates the default GraphicsPipe, which will be used to make
@@ -1022,6 +1042,7 @@ class ShowBase(DirectObject.DirectObject):
         Creates the render scene graph, the primary scene graph for
         Creates the render scene graph, the primary scene graph for
         rendering 3-d geometry.
         rendering 3-d geometry.
         """
         """
+        ## This is the root of the 3-D scene graph.
         self.render = NodePath('render')
         self.render = NodePath('render')
         self.render.setAttrib(RescaleNormalAttrib.makeDefault())
         self.render.setAttrib(RescaleNormalAttrib.makeDefault())
 
 
@@ -1037,6 +1058,7 @@ class ShowBase(DirectObject.DirectObject):
         2-d objects and gui elements that are superimposed over the
         2-d objects and gui elements that are superimposed over the
         3-d geometry in the window.
         3-d geometry in the window.
         """
         """
+        ## This is the root of the 2-D scene graph.
         self.render2d = NodePath('render2d')
         self.render2d = NodePath('render2d')
 
 
         # Set up some overrides to turn off certain properties which
         # Set up some overrides to turn off certain properties which
@@ -1057,22 +1079,26 @@ class ShowBase(DirectObject.DirectObject):
         self.render2d.setMaterialOff(1)
         self.render2d.setMaterialOff(1)
         self.render2d.setTwoSided(1)
         self.render2d.setTwoSided(1)
 
 
-        # The normal 2-d DisplayRegion has an aspect ratio that
-        # matches the window, but its coordinate system is square.
-        # This means anything we parent to render2d gets stretched.
-        # For things where that makes a difference, we set up
-        # aspect2d, which scales things back to the right aspect
-        # ratio.
-        aspectRatio = self.getAspectRatio()
+        ## The normal 2-d DisplayRegion has an aspect ratio that
+        ## matches the window, but its coordinate system is square.
+        ## This means anything we parent to render2d gets stretched.
+        ## For things where that makes a difference, we set up
+        ## aspect2d, which scales things back to the right aspect
+        ## ratio along the X axis (Z is still from -1 to 1)
         self.aspect2d = self.render2d.attachNewNode(PGTop("aspect2d"))
         self.aspect2d = self.render2d.attachNewNode(PGTop("aspect2d"))
+
+        aspectRatio = self.getAspectRatio()
         self.aspect2d.setScale(1.0 / aspectRatio, 1.0, 1.0)
         self.aspect2d.setScale(1.0 / aspectRatio, 1.0, 1.0)
 
 
         self.a2dBackground = self.aspect2d.attachNewNode("a2dBackground")
         self.a2dBackground = self.aspect2d.attachNewNode("a2dBackground")
 
 
-        # It's important to know the bounds of the aspect2d screen.
+        ## The Z position of the top border of the aspect2d screen.
         self.a2dTop = 1.0
         self.a2dTop = 1.0
+        ## The Z position of the bottom border of the aspect2d screen.
         self.a2dBottom = -1.0
         self.a2dBottom = -1.0
+        ## The X position of the left border of the aspect2d screen.
         self.a2dLeft = -aspectRatio
         self.a2dLeft = -aspectRatio
+        ## The X position of the right border of the aspect2d screen.
         self.a2dRight = aspectRatio
         self.a2dRight = aspectRatio
 
 
         self.a2dTopCenter = self.aspect2d.attachNewNode("a2dTopCenter")
         self.a2dTopCenter = self.aspect2d.attachNewNode("a2dTopCenter")
@@ -1112,12 +1138,12 @@ class ShowBase(DirectObject.DirectObject):
         self.a2dBottomRight.setPos(self.a2dRight, 0, self.a2dBottom)
         self.a2dBottomRight.setPos(self.a2dRight, 0, self.a2dBottom)
         self.a2dBottomRightNs.setPos(self.a2dRight, 0, self.a2dBottom)
         self.a2dBottomRightNs.setPos(self.a2dRight, 0, self.a2dBottom)
 
 
-        # This special root, pixel2d, uses units in pixels that are relative
-        # to the window. The upperleft corner of the window is (0, 0),
-        # the lowerleft corner is (xsize, -ysize), in this coordinate system.
-        xsize, ysize = self.getSize()
+        ## This special root, pixel2d, uses units in pixels that are relative
+        ## to the window. The upperleft corner of the window is (0, 0),
+        ## the lowerleft corner is (xsize, -ysize), in this coordinate system.
         self.pixel2d = self.render2d.attachNewNode(PGTop("pixel2d"))
         self.pixel2d = self.render2d.attachNewNode(PGTop("pixel2d"))
         self.pixel2d.setPos(-1, 0, 1)
         self.pixel2d.setPos(-1, 0, 1)
+        xsize, ysize = self.getSize()
         if xsize > 0 and ysize > 0:
         if xsize > 0 and ysize > 0:
             self.pixel2d.setScale(2.0 / xsize, 1.0, 2.0 / ysize)
             self.pixel2d.setScale(2.0 / xsize, 1.0, 2.0 / ysize)
 
 
@@ -1144,25 +1170,27 @@ class ShowBase(DirectObject.DirectObject):
         self.render2dp.setMaterialOff(1)
         self.render2dp.setMaterialOff(1)
         self.render2dp.setTwoSided(1)
         self.render2dp.setTwoSided(1)
 
 
-        # The normal 2-d DisplayRegion has an aspect ratio that
-        # matches the window, but its coordinate system is square.
-        # This means anything we parent to render2d gets stretched.
-        # For things where that makes a difference, we set up
-        # aspect2d, which scales things back to the right aspect
-        # ratio.
-
-        aspectRatio = self.getAspectRatio()
+        ## The normal 2-d DisplayRegion has an aspect ratio that
+        ## matches the window, but its coordinate system is square.
+        ## This means anything we parent to render2dp gets stretched.
+        ## For things where that makes a difference, we set up
+        ## aspect2dp, which scales things back to the right aspect
+        ## ratio along the X axis (Z is still from -1 to 1)
         self.aspect2dp = self.render2dp.attachNewNode(PGTop("aspect2dp"))
         self.aspect2dp = self.render2dp.attachNewNode(PGTop("aspect2dp"))
         self.aspect2dp.node().setStartSort(16384)
         self.aspect2dp.node().setStartSort(16384)
+
+        aspectRatio = self.getAspectRatio()
         self.aspect2dp.setScale(1.0 / aspectRatio, 1.0, 1.0)
         self.aspect2dp.setScale(1.0 / aspectRatio, 1.0, 1.0)
 
 
-        # It's important to know the bounds of the aspect2d screen.
+        ## The Z position of the top border of the aspect2dp screen.
         self.a2dpTop = 1.0
         self.a2dpTop = 1.0
+        ## The Z position of the bottom border of the aspect2dp screen.
         self.a2dpBottom = -1.0
         self.a2dpBottom = -1.0
+        ## The X position of the left border of the aspect2dp screen.
         self.a2dpLeft = -aspectRatio
         self.a2dpLeft = -aspectRatio
+        ## The X position of the right border of the aspect2dp screen.
         self.a2dpRight = aspectRatio
         self.a2dpRight = aspectRatio
 
 
-
         self.a2dpTopCenter = self.aspect2dp.attachNewNode("a2dpTopCenter")
         self.a2dpTopCenter = self.aspect2dp.attachNewNode("a2dpTopCenter")
         self.a2dpBottomCenter = self.aspect2dp.attachNewNode("a2dpBottomCenter")
         self.a2dpBottomCenter = self.aspect2dp.attachNewNode("a2dpBottomCenter")
         self.a2dpLeftCenter = self.aspect2dp.attachNewNode("a2dpLeftCenter")
         self.a2dpLeftCenter = self.aspect2dp.attachNewNode("a2dpLeftCenter")
@@ -1184,13 +1212,13 @@ class ShowBase(DirectObject.DirectObject):
         self.a2dpBottomLeft.setPos(self.a2dpLeft, 0, self.a2dpBottom)
         self.a2dpBottomLeft.setPos(self.a2dpLeft, 0, self.a2dpBottom)
         self.a2dpBottomRight.setPos(self.a2dpRight, 0, self.a2dpBottom)
         self.a2dpBottomRight.setPos(self.a2dpRight, 0, self.a2dpBottom)
 
 
-        # This special root, pixel2d, uses units in pixels that are relative
-        # to the window. The upperleft corner of the window is (0, 0),
-        # the lowerleft corner is (xsize, -ysize), in this coordinate system.
-        xsize, ysize = self.getSize()
+        ## This special root, pixel2d, uses units in pixels that are relative
+        ## to the window. The upperleft corner of the window is (0, 0),
+        ## the lowerleft corner is (xsize, -ysize), in this coordinate system.
         self.pixel2dp = self.render2dp.attachNewNode(PGTop("pixel2dp"))
         self.pixel2dp = self.render2dp.attachNewNode(PGTop("pixel2dp"))
         self.pixel2dp.node().setStartSort(16384)
         self.pixel2dp.node().setStartSort(16384)
         self.pixel2dp.setPos(-1, 0, 1)
         self.pixel2dp.setPos(-1, 0, 1)
+        xsize, ysize = self.getSize()
         if xsize > 0 and ysize > 0:
         if xsize > 0 and ysize > 0:
             self.pixel2dp.setScale(2.0 / xsize, 1.0, 2.0 / ysize)
             self.pixel2dp.setScale(2.0 / xsize, 1.0, 2.0 / ysize)
 
 
@@ -1502,12 +1530,14 @@ class ShowBase(DirectObject.DirectObject):
             np = mw.getParent().attachNewNode(mouseRecorder)
             np = mw.getParent().attachNewNode(mouseRecorder)
             mw.reparentTo(np)
             mw.reparentTo(np)
 
 
-        # A special ButtonThrower to generate keyboard events and
-        # include the time from the OS.  This is separate only to
-        # support legacy code that did not expect a time parameter; it
-        # will eventually be folded into the normal ButtonThrower,
-        # above.
+
         mw = self.buttonThrowers[0].getParent()
         mw = self.buttonThrowers[0].getParent()
+
+        ## A special ButtonThrower to generate keyboard events and
+        ## include the time from the OS.  This is separate only to
+        ## support legacy code that did not expect a time parameter; it
+        ## will eventually be folded into the normal ButtonThrower,
+        ## above.
         self.timeButtonThrower = mw.attachNewNode(ButtonThrower('timeButtons'))
         self.timeButtonThrower = mw.attachNewNode(ButtonThrower('timeButtons'))
         self.timeButtonThrower.node().setPrefix('time-')
         self.timeButtonThrower.node().setPrefix('time-')
         self.timeButtonThrower.node().setTimeFlag(1)
         self.timeButtonThrower.node().setTimeFlag(1)
@@ -1931,7 +1961,7 @@ class ShowBase(DirectObject.DirectObject):
         throw_new_frame()
         throw_new_frame()
         return Task.cont
         return Task.cont
 
 
-    def restart(self,clusterSync=False,cluster=None):
+    def restart(self, clusterSync=False, cluster=None):
         self.shutdown()
         self.shutdown()
         # __resetPrevTransform goes at the very beginning of the frame.
         # __resetPrevTransform goes at the very beginning of the frame.
         self.taskMgr.add(
         self.taskMgr.add(
@@ -1970,7 +2000,7 @@ class ShowBase(DirectObject.DirectObject):
         self.taskMgr.remove('dataLoop')
         self.taskMgr.remove('dataLoop')
         self.taskMgr.remove('resetPrevTransform')
         self.taskMgr.remove('resetPrevTransform')
         self.taskMgr.remove('ivalLoop')
         self.taskMgr.remove('ivalLoop')
-        self.taskMgr.remove('garbage_collect')
+        self.taskMgr.remove('garbageCollectStates')
         self.eventMgr.shutdown()
         self.eventMgr.shutdown()
 
 
     def getBackgroundColor(self, win = None):
     def getBackgroundColor(self, win = None):
@@ -2931,11 +2961,12 @@ class ShowBase(DirectObject.DirectObject):
         self.startDirect(fWantDirect = fDirect, fWantTk = fTk, fWantWx = fWx)
         self.startDirect(fWantDirect = fDirect, fWantTk = fTk, fWantWx = fWx)
 
 
     def run(self):
     def run(self):
-        # This method runs the TaskManager when self.appRunner is
-        # None, which is to say, when we are not running from within a
-        # p3d file.  When we *are* within a p3d file, the Panda
-        # runtime has to be responsible for running the main loop, so
-        # we can't allow the application to do it.
+        """ This method runs the TaskManager when self.appRunner is
+        None, which is to say, when we are not running from within a
+        p3d file.  When we *are* within a p3d file, the Panda
+        runtime has to be responsible for running the main loop, so
+        we can't allow the application to do it. """
+
         if self.appRunner is None or self.appRunner.dummy or \
         if self.appRunner is None or self.appRunner.dummy or \
            (self.appRunner.interactiveConsole and not self.appRunner.initialAppImport):
            (self.appRunner.interactiveConsole and not self.appRunner.initialAppImport):
             self.taskMgr.run()
             self.taskMgr.run()