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

This commit is contained in:
rdb 2015-03-15 13:06:49 +01:00
parent 78c3593d2c
commit 753b1c623d
4 changed files with 123 additions and 84 deletions

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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 direct.directnotify.DirectNotifyGlobal import directNotify, giveNotify
from MessengerGlobal import * from MessengerGlobal import messenger
from BulletinBoardGlobal import * from BulletinBoardGlobal import bulletinBoard
from direct.task.TaskManagerGlobal import * from direct.task.TaskManagerGlobal import taskMgr
from JobManagerGlobal import * from JobManagerGlobal import jobMgr
from EventManagerGlobal import * 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()
@atexit.register
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 ## This contains the global appRunner instance, as imported from
# has been. ## 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" ## Fill this in with a function to invoke when the user "exits"
# the program by closing the main window. ## the program by closing the main window.
self.exitFunc = None self.exitFunc = None
# Add final-exit callbacks to this list. These will be called ## Add final-exit callbacks to this list. These will be called
# when sys.exit() is called, after Panda has unloaded, and ## when sys.exit() is called, after Panda has unloaded, and
# just before Python is about to shut down. ## 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 ## This is the main, or only window; see winList for a list of *all* windows.
# *all* windows. Similarly with base.camList.
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 ## This is a placeholder for a CollisionTraverser. If someone
# stores a CollisionTraverser pointer here, we'll traverse it ## stores a CollisionTraverser pointer here, we'll traverse it
# in the collisionLoop task. ## in the collisionLoop task.
self.shadowTrav = 0
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 ## The normal 2-d DisplayRegion has an aspect ratio that
# matches the window, but its coordinate system is square. ## matches the window, but its coordinate system is square.
# This means anything we parent to render2d gets stretched. ## This means anything we parent to render2d gets stretched.
# For things where that makes a difference, we set up ## For things where that makes a difference, we set up
# aspect2d, which scales things back to the right aspect ## aspect2d, which scales things back to the right aspect
# ratio. ## ratio along the X axis (Z is still from -1 to 1)
aspectRatio = self.getAspectRatio()
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 ## This special root, pixel2d, uses units in pixels that are relative
# to the window. The upperleft corner of the window is (0, 0), ## to the window. The upperleft corner of the window is (0, 0),
# the lowerleft corner is (xsize, -ysize), in this coordinate system. ## the lowerleft corner is (xsize, -ysize), in this coordinate system.
xsize, ysize = self.getSize()
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 ## The normal 2-d DisplayRegion has an aspect ratio that
# matches the window, but its coordinate system is square. ## matches the window, but its coordinate system is square.
# This means anything we parent to render2d gets stretched. ## This means anything we parent to render2dp gets stretched.
# For things where that makes a difference, we set up ## For things where that makes a difference, we set up
# aspect2d, which scales things back to the right aspect ## aspect2dp, which scales things back to the right aspect
# ratio. ## ratio along the X axis (Z is still from -1 to 1)
aspectRatio = self.getAspectRatio()
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 ## This special root, pixel2d, uses units in pixels that are relative
# to the window. The upperleft corner of the window is (0, 0), ## to the window. The upperleft corner of the window is (0, 0),
# the lowerleft corner is (xsize, -ysize), in this coordinate system. ## the lowerleft corner is (xsize, -ysize), in this coordinate system.
xsize, ysize = self.getSize()
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 """ This method runs the TaskManager when self.appRunner is
# None, which is to say, when we are not running from within a None, which is to say, when we are not running from within a
# p3d file. When we *are* within a p3d file, the Panda p3d file. When we *are* within a p3d file, the Panda
# runtime has to be responsible for running the main loop, so runtime has to be responsible for running the main loop, so
# we can't allow the application to do it. 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()