From 12873c0d7e1062cb686dbbf028a7c1c9894125bf Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 10 Jun 2016 02:00:54 +0200 Subject: [PATCH] Fix wxPython and tkinter issues on Mac OS X --- direct/src/showbase/ShowBase.py | 27 ++++++++++++++++++++----- panda/src/cocoadisplay/cocoaPandaApp.mm | 20 ++++++++++++++++++ samples/particles/particle_panel.py | 7 ++++--- 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index 4a6e2b8d66..e5a9e18bce 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -205,7 +205,9 @@ class ShowBase(DirectObject.DirectObject): ## This is used to store the wx.Application object used when want-wx is ## set or base.startWx() is called. self.wxApp = None + self.wxAppCreated = False self.tkRoot = None + self.tkRootCreated = False # This is used for syncing multiple PCs in a distributed cluster try: @@ -262,6 +264,17 @@ class ShowBase(DirectObject.DirectObject): random.seed(seed) #whrandom.seed(seed & 0xff, (seed >> 8) & 0xff, (seed >> 16) & 0xff) + # For some reason, wx needs to be initialized before the graphics window + if sys.platform == "darwin": + if self.config.GetBool("want-wx", 0): + import wx + self.wxApp = wx.App() + + # Same goes for Tk, which uses a conflicting NSApplication + if self.config.GetBool("want-tk", 0): + import Pmw + self.tkRoot = Pmw.initialise() + # Open the default rendering window. if self.windowType != 'none': props = WindowProperties.getDefault() @@ -2804,15 +2817,16 @@ class ShowBase(DirectObject.DirectObject): updated, but wxPython owns the main loop (which seems to make it happier than the other way around). """ - if self.wxApp: + if self.wxAppCreated: # Don't do this twice. return init_app_for_gui() import wx - # Create a new base.wxApp. - self.wxApp = wx.PySimpleApp(redirect = False) + if not self.wxApp: + # Create a new base.wxApp. + self.wxApp = wx.PySimpleApp(redirect = False) if ConfigVariableBool('wx-main-loop', True): # Put wxPython in charge of the main loop. It really @@ -2847,6 +2861,7 @@ class ShowBase(DirectObject.DirectObject): return task.again self.taskMgr.add(wxLoop, 'wxLoop') + self.wxAppCreated = True def __wxTimerCallback(self, event): if Thread.getCurrentThread().getCurrentTask(): @@ -2881,7 +2896,7 @@ class ShowBase(DirectObject.DirectObject): updated, but Tkinter owns the main loop (which seems to make it happier than the other way around). """ - if self.tkRoot: + if self.tkRootCreated: # Don't do this twice. return @@ -2889,7 +2904,8 @@ class ShowBase(DirectObject.DirectObject): import Pmw # Create a new Tk root. - self.tkRoot = Pmw.initialise() + if not self.tkRoot: + self.tkRoot = Pmw.initialise() builtins.tkroot = self.tkRoot init_app_for_gui() @@ -2925,6 +2941,7 @@ class ShowBase(DirectObject.DirectObject): return task.again self.taskMgr.add(tkLoop, 'tkLoop') + self.tkRootCreated = True def __tkTimerCallback(self): if not Thread.getCurrentThread().getCurrentTask(): diff --git a/panda/src/cocoadisplay/cocoaPandaApp.mm b/panda/src/cocoadisplay/cocoaPandaApp.mm index 95efc8fe2d..8737429801 100644 --- a/panda/src/cocoadisplay/cocoaPandaApp.mm +++ b/panda/src/cocoadisplay/cocoaPandaApp.mm @@ -26,4 +26,24 @@ [super sendEvent: event]; } } + +- (void) _setup: (void *) interp { + // This is called by Tk when it launches and naively assumes that it is + // the first to create an NSApplication. We can't do anything about it + // at this point except display an error message. + + cocoadisplay_cat.error() + << "Detected attempt to initialize Tk after creating a Panda window. " + "This will likely cause a crash.\n" + "To fix this, set 'want-tk true' in Config.prc to force " + "initialization of Tk before opening the Panda window.\n"; +} + +- (void) _setupEventLoop { + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + [self finishLaunching]; + [self setWindowsNeedUpdate:YES]; + [pool drain]; +} + @end diff --git a/samples/particles/particle_panel.py b/samples/particles/particle_panel.py index d74e42155c..b449bc474f 100755 --- a/samples/particles/particle_panel.py +++ b/samples/particles/particle_panel.py @@ -17,13 +17,14 @@ try: except: sys.exit("Please install Python megawidgets") +# Makes sure that Panda is configured to play nice with Tkinter +from panda3d.core import * +loadPrcFileData("", "want-tk true") + # Open the Panda window from direct.showbase.ShowBase import ShowBase base = ShowBase() -# Makes sure that Panda is configured to play nice with Tkinter -base.startTk() - from direct.tkpanels.ParticlePanel import ParticlePanel pp = ParticlePanel() # Create the panel