diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index 197cb73fb7..d05fef0768 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -102,6 +102,8 @@ class ShowBase(DirectObject.DirectObject): self.sfxManagerIsValidList = [] self.wantStats = self.config.GetBool('want-pstats', 0) + self.wantTk = False + self.wantWx = False # Fill this in with a function to invoke when the user "exits" # the program by closing the main window. @@ -341,7 +343,10 @@ class ShowBase(DirectObject.DirectObject): __builtin__.aspect2dp = self.aspect2dp __builtin__.pixel2dp = self.pixel2dp - ShowBase.notify.info('__dev__ == %s' % __dev__) + if not __dev__: + ShowBase.notify.debug('__dev__ == %s' % __dev__) + else: + ShowBase.notify.info('__dev__ == %s' % __dev__) # set up recording of Functor creation stacks in __dev__ PythonUtil.recordFunctorCreationStacks() @@ -366,8 +371,9 @@ class ShowBase(DirectObject.DirectObject): import Transitions self.transitions = Transitions.Transitions(self.loader) - # Setup the window controls - handy for multiwindow applications - self.setupWindowControls() + if self.win: + # Setup the window controls - handy for multiwindow applications + self.setupWindowControls() # Client sleep sleepTime = self.config.GetFloat('client-sleep', 0.0) @@ -2643,20 +2649,21 @@ class ShowBase(DirectObject.DirectObject): sys.exit() # [gjeon] start wxPyhton - def startWx(self, fWantWx = 1): - self.wantWx = fWantWx - if self.wantWx: - initAppForGui() - from direct.showbase import WxGlobal - taskMgr.remove('wxLoop') - WxGlobal.spawnWxLoop() + def startWx(self, fWantWx = True): + fWantWx = bool(fWantWx) + if self.wantWx != fWantWx: + self.wantWx = fWantWx + if self.wantWx: + initAppForGui() + from direct.showbase import WxGlobal + WxGlobal.spawnWxLoop() - def startTk(self, fWantTk = 1): - self.wantTk = fWantTk - if self.wantTk: + def startTk(self, fWantTk = True): + fWantTk = bool(fWantTk) + if self.wantTk != fWantTk: + self.wantTk = fWantTk initAppForGui() from direct.showbase import TkGlobal - taskMgr.remove('tkLoop') TkGlobal.spawnTkLoop() def startDirect(self, fWantDirect = 1, fWantTk = 1, fWantWx = 0): diff --git a/direct/src/showbase/TkGlobal.py b/direct/src/showbase/TkGlobal.py index 4341cdade4..c62993e9f1 100644 --- a/direct/src/showbase/TkGlobal.py +++ b/direct/src/showbase/TkGlobal.py @@ -27,7 +27,7 @@ def tkLoop(self): def spawnTkLoop(): # Spawn this task + taskMgr.remove('tkLoop') taskMgr.add(tkLoop, "tkLoop") -taskMgr.remove('tkLoop') spawnTkLoop() diff --git a/direct/src/showbase/WxGlobal.py b/direct/src/showbase/WxGlobal.py index b89aed37d7..9e465219c7 100755 --- a/direct/src/showbase/WxGlobal.py +++ b/direct/src/showbase/WxGlobal.py @@ -18,4 +18,5 @@ def spawnWxLoop(): base.wxApp = wx.PySimpleApp(redirect = False) # Spawn this task + taskMgr.remove('wxLoop') taskMgr.add(wxLoop, "wxLoop") diff --git a/direct/src/wxwidgets/ViewPort.py b/direct/src/wxwidgets/ViewPort.py index 4989451169..494c3ab845 100755 --- a/direct/src/wxwidgets/ViewPort.py +++ b/direct/src/wxwidgets/ViewPort.py @@ -12,6 +12,7 @@ from direct.showbase.DirectObject import DirectObject from direct.directtools.DirectGrid import DirectGrid from direct.showbase.ShowBase import WindowControls from direct.directtools.DirectGlobals import * +from WxPandaWindow import WxPandaWindow from pandac.PandaModules import WindowProperties, OrthographicLens, Point3, Plane, CollisionPlane, CollisionNode, NodePath import wx @@ -46,7 +47,7 @@ class ViewportManager: for v in ViewportManager.viewports: v.Layout(*args, **kwargs) -class Viewport(wx.Panel, DirectObject): +class Viewport(WxPandaWindow, DirectObject): """Class representing a 3D Viewport.""" CREATENEW = CREATENEW VPLEFT = VPLEFT @@ -56,10 +57,14 @@ class Viewport(wx.Panel, DirectObject): def __init__(self, name, *args, **kwargs): self.name = name DirectObject.__init__(self) - wx.Panel.__init__(self, *args, **kwargs) + + kwargs['gsg'] = ViewportManager.gsg + WxPandaWindow.__init__(self, *args, **kwargs) ViewportManager.viewports.append(self) - self.win = None + if ViewportManager.gsg == None: + ViewportManager.gsg = self.win.getGsg() + self.camera = None self.lens = None self.camPos = None @@ -70,23 +75,10 @@ class Viewport(wx.Panel, DirectObject): def initialize(self): self.Update() - wp = WindowProperties() - wp.setOrigin(0, 0) - wp.setSize(self.ClientSize.GetWidth(), self.ClientSize.GetHeight()) - assert self.GetHandle() != 0 - wp.setParentWindow(self.GetHandle()) - - # initializing panda window - base.windowType = "onscreen" - props = WindowProperties.getDefault() - props.addProperties(wp) - self.win = base.openWindow(props = props, gsg = ViewportManager.gsg) if self.win: self.cam2d = base.makeCamera2d(self.win) self.cam2d.node().setCameraMask(LE_CAM_MASKS[self.name]) - if ViewportManager.gsg == None: - ViewportManager.gsg = self.win.getGsg() self.cam = base.camList[-1] self.camera = render.attachNewNode(self.name) #self.camera.setName(self.name) @@ -135,18 +127,16 @@ class Viewport(wx.Panel, DirectObject): """Closes the viewport.""" if self.initialized: wx.Window.Close(self) - base.closeWindow(self.win) + #base.closeWindow(self.win) ViewportManager.viewports.remove(self) def onSize(self, evt): """Invoked when the viewport is resized.""" + WxPandaWindow.onSize(self, evt) + if self.win != None: - wp = WindowProperties() - wp.setOrigin(0, 0) newWidth = self.ClientSize.GetWidth() newHeight = self.ClientSize.GetHeight() - wp.setSize(newWidth, newHeight) - self.win.requestProperties(wp) if hasattr(base, "direct") and base.direct: for dr in base.direct.drList: diff --git a/direct/src/wxwidgets/WxPandaShell.py b/direct/src/wxwidgets/WxPandaShell.py index f36fec9aae..4bffda319d 100755 --- a/direct/src/wxwidgets/WxPandaShell.py +++ b/direct/src/wxwidgets/WxPandaShell.py @@ -9,7 +9,7 @@ from direct.directtools.DirectGlobals import * try: base except NameError: - base = ShowBase(False) + base = ShowBase(False, windowType = 'none') from WxAppShell import * from ViewPort import * @@ -196,7 +196,7 @@ class WxPandaShell(WxAppShell): else: base.direct=None - base.closeWindow(base.win) + #base.closeWindow(base.win) base.win = base.winList[3] def wxStep(self, task = None): diff --git a/direct/src/showbase/WxPandaWindow.py b/direct/src/wxwidgets/WxPandaWindow.py similarity index 70% rename from direct/src/showbase/WxPandaWindow.py rename to direct/src/wxwidgets/WxPandaWindow.py index ed7c337639..8b2aa818d2 100644 --- a/direct/src/showbase/WxPandaWindow.py +++ b/direct/src/wxwidgets/WxPandaWindow.py @@ -17,33 +17,60 @@ from panda3d.core import * __all__ = ['WxPandaWindow'] -if platform.system() != 'Darwin': - class EmbeddedPandaWindow(wx.Window): - """ This class implements a Panda3D window that is directly - embedded within the frame. It is fully supported on Windows, - partially supported on Linux, and not at all on OSX. """ +class EmbeddedPandaWindow(wx.Window): + """ This class implements a Panda3D window that is directly + embedded within the frame. It is fully supported on Windows, + partially supported on Linux, and not at all on OSX. """ - def __init__(self, *args, **kw): - wx.Window.__init__(self, *args, **kw) + def __init__(self, *args, **kw): + gsg = None + if 'gsg' in kw: + gsg = kw['gsg'] + del kw['gsg'] - wp = WindowProperties.getDefault() + base.startWx() + wx.Window.__init__(self, *args, **kw) + + wp = WindowProperties.getDefault() + if platform.system() != 'Darwin': wp.setParentWindow(self.GetHandle()) - if base.win: - self.win = base.openWindow(props = wp) - else: - base.openDefaultWindow(props = wp) - self.win = base.win + if base.win: + self.win = base.openWindow(props = wp, gsg = gsg, type = 'onscreen') + else: + base.openDefaultWindow(props = wp, gsg = gsg, type = 'onscreen') + self.win = base.win - self.Bind(wx.EVT_SIZE, self.__resized) + self.Bind(wx.EVT_SIZE, self.onSize) - def __resized(self, event): - wp = WindowProperties() - wp.setOrigin(0, 0) - wp.setSize(*self.GetClientSizeTuple()) - self.win.requestProperties(wp) + # This doesn't actually do anything, since wx won't call + # EVT_CLOSE on a child window, only on the toplevel window + # that contains it. + self.Bind(wx.EVT_CLOSE, self.__closeEvent) -if hasattr(wxgl, 'GLCanvas'): + def __closeEvent(self, event): + self.cleanup() + event.Skip() + + def cleanup(self): + """ Parent windows should call cleanp() to clean up the + wxPandaWindow explicitly (since we can't catch EVT_CLOSE + directly). """ + if self.win: + base.closeWindow(self.win) + self.win = None + self.Destroy() + + def onSize(self, event): + wp = WindowProperties() + wp.setOrigin(0, 0) + wp.setSize(*self.GetClientSizeTuple()) + self.win.requestProperties(wp) + event.Skip() + +if not hasattr(wxgl, 'GLCanvas'): + OpenGLPandaWindow = None +else: class OpenGLPandaWindow(wxgl.GLCanvas): """ This class implements a Panda3D "window" that actually draws within the wx GLCanvas object. It is supported whenever OpenGL is @@ -88,8 +115,18 @@ if hasattr(wxgl, 'GLCanvas'): } def __init__(self, *args, **kw): + gsg = None + if 'gsg' in kw: + gsg = kw['gsg'] + del kw['gsg'] + + base.startWx() wxgl.GLCanvas.__init__(self, *args, **kw) + # Can't share the GSG when a new wxgl.GLContext is created + # automatically. + gsg = None + callbackWindowDict = { 'Events' : self.__eventsCallback, 'Properties' : self.__propertiesCallback, @@ -111,14 +148,14 @@ if hasattr(wxgl, 'GLCanvas'): self.SetCurrent() if base.win: - self.win = base.openWindow(callbackWindowDict = callbackWindowDict, pipe = pipe) + self.win = base.openWindow(callbackWindowDict = callbackWindowDict, pipe = pipe, gsg = gsg, type = 'onscreen') else: - base.openDefaultWindow(callbackWindowDict = callbackWindowDict, pipe = pipe) + base.openDefaultWindow(callbackWindowDict = callbackWindowDict, pipe = pipe, gsg = gsg, type = 'onscreen') self.win = base.win self.inputDevice = self.win.getInputDevice(0) - self.Bind(wx.EVT_SIZE, self.__resized) + self.Bind(wx.EVT_SIZE, self.onSize) self.Bind(wx.EVT_LEFT_DOWN, lambda event: self.__buttonDown(MouseButton.one())) self.Bind(wx.EVT_LEFT_UP, lambda event: self.__buttonUp(MouseButton.one())) self.Bind(wx.EVT_MIDDLE_DOWN, lambda event: self.__buttonDown(MouseButton.two())) @@ -131,6 +168,24 @@ if hasattr(wxgl, 'GLCanvas'): self.Bind(wx.EVT_KEY_UP, self.__keyUp) self.Bind(wx.EVT_CHAR, self.__keystroke) + # This doesn't actually do anything, since wx won't call + # EVT_CLOSE on a child window, only on the toplevel window + # that contains it. + self.Bind(wx.EVT_CLOSE, self.__closeEvent) + + def __closeEvent(self, event): + self.cleanup() + event.Skip() + + def cleanup(self): + """ Parent windows should call cleanp() to clean up the + wxPandaWindow explicitly (since we can't catch EVT_CLOSE + directly). """ + if self.win: + base.closeWindow(self.win) + self.win = None + self.Destroy() + def __buttonDown(self, button): self.inputDevice.buttonDown(button) @@ -189,18 +244,23 @@ if hasattr(wxgl, 'GLCanvas'): cbType = data.getCallbackType() if cbType == CallbackGraphicsWindow.RCTBeginFrame: self.SetCurrent() + if not self.IsShownOnScreen(): + return False elif cbType == CallbackGraphicsWindow.RCTEndFlip: self.SwapBuffers() data.upcall() - def __resized(self, event): + def onSize(self, event): wp = WindowProperties() wp.setSize(*self.GetClientSizeTuple()) self.win.requestProperties(wp) + event.Skip() # Choose the best implementation of WxPandaWindow for the platform. +WxPandaWindow = None if platform.system() == 'Darwin': WxPandaWindow = OpenGLPandaWindow -else: + +if not WxPandaWindow: WxPandaWindow = EmbeddedPandaWindow diff --git a/panda/src/device/mouseAndKeyboard.cxx b/panda/src/device/mouseAndKeyboard.cxx index 205386b0e3..e8c102746e 100644 --- a/panda/src/device/mouseAndKeyboard.cxx +++ b/panda/src/device/mouseAndKeyboard.cxx @@ -23,7 +23,7 @@ TypeHandle MouseAndKeyboard::_type_handle; //////////////////////////////////////////////////////////////////// // Function: MouseAndKeyboard::Constructor -// Access: Public +// Access: Published // Description: //////////////////////////////////////////////////////////////////// MouseAndKeyboard:: @@ -46,7 +46,7 @@ MouseAndKeyboard(GraphicsWindow *window, int device, const string &name) : //////////////////////////////////////////////////////////////////// // Function: MouseAndKeyboard::set_source -// Access: Public +// Access: Published // Description: Redirects the class to get the data from the mouse // and keyboard associated with a different window // and/or device number. @@ -59,7 +59,7 @@ set_source(GraphicsWindow *window, int device) { //////////////////////////////////////////////////////////////////// // Function: MouseAndKeyboard::get_source_window -// Access: Public +// Access: Published // Description: Returns the associated source window. //////////////////////////////////////////////////////////////////// PT(GraphicsWindow) MouseAndKeyboard:: @@ -69,7 +69,7 @@ get_source_window() const { //////////////////////////////////////////////////////////////////// // Function: MouseAndKeyboard::get_source_device -// Access: Public +// Access: Published // Description: Returns the associated source device. //////////////////////////////////////////////////////////////////// int MouseAndKeyboard:: diff --git a/panda/src/device/mouseAndKeyboard.h b/panda/src/device/mouseAndKeyboard.h index bc77f08dda..939a04aa8a 100644 --- a/panda/src/device/mouseAndKeyboard.h +++ b/panda/src/device/mouseAndKeyboard.h @@ -49,7 +49,6 @@ PUBLISHED: MouseAndKeyboard(GraphicsWindow *window, int device, const string &name); void set_source(GraphicsWindow *window, int device); -public: PT(GraphicsWindow) get_source_window() const; int get_source_device() const; diff --git a/panda/src/display/callbackGraphicsWindow.cxx b/panda/src/display/callbackGraphicsWindow.cxx index fb729daf59..aa36d825f7 100644 --- a/panda/src/display/callbackGraphicsWindow.cxx +++ b/panda/src/display/callbackGraphicsWindow.cxx @@ -38,6 +38,11 @@ CallbackGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe, #ifdef DO_MEMORY_USAGE MemoryUsage::update_type(this, this); #endif + + // Let's ensure that these properties are set to *something* + // initially. + _properties.set_origin(0, 0); + _properties.set_size(0, 0); } ////////////////////////////////////////////////////////////////////