Skip to content

Commit 0da1393

Browse files
authored
Fix Mac issues in Tkinter example (cztomczak#309, cztomczak#441)
Still some issues on startup, see: cztomczak#583
1 parent 28afa80 commit 0da1393

File tree

1 file changed

+55
-18
lines changed

1 file changed

+55
-18
lines changed

examples/tkinter_.py

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444

4545

4646
def main():
47-
logger.setLevel(_logging.INFO)
47+
logger.setLevel(_logging.DEBUG)
4848
stream_handler = _logging.StreamHandler()
4949
formatter = _logging.Formatter("[%(filename)s] %(message)s")
5050
stream_handler.setFormatter(formatter)
@@ -55,19 +55,23 @@ def main():
5555
logger.info("Tk {ver}".format(ver=tk.Tcl().eval('info patchlevel')))
5656
assert cef.__version__ >= "55.3", "CEF Python v55.3+ required to run this"
5757
sys.excepthook = cef.ExceptHook # To shutdown all CEF processes on error
58+
# Tk must be initialized before CEF otherwise fatal error (Issue #306)
5859
root = tk.Tk()
5960
app = MainFrame(root)
60-
# Tk must be initialized before CEF otherwise fatal error (Issue #306)
61-
cef.Initialize()
61+
settings = {}
62+
if MAC:
63+
settings["external_message_pump"] = True
64+
cef.Initialize(settings=settings)
6265
app.mainloop()
66+
logger.debug("Main loop exited")
6367
cef.Shutdown()
6468

65-
6669
class MainFrame(tk.Frame):
6770

6871
def __init__(self, root):
6972
self.browser_frame = None
7073
self.navigation_bar = None
74+
self.root = root
7175

7276
# Root
7377
root.geometry("900x640")
@@ -124,7 +128,9 @@ def on_focus_out(self, _):
124128
def on_close(self):
125129
if self.browser_frame:
126130
self.browser_frame.on_root_close()
127-
self.master.destroy()
131+
self.browser_frame = None
132+
else:
133+
self.master.destroy()
128134

129135
def get_browser(self):
130136
if self.browser_frame:
@@ -147,11 +153,12 @@ def setup_icon(self):
147153

148154
class BrowserFrame(tk.Frame):
149155

150-
def __init__(self, master, navigation_bar=None):
156+
def __init__(self, mainframe, navigation_bar=None):
151157
self.navigation_bar = navigation_bar
152158
self.closing = False
153159
self.browser = None
154-
tk.Frame.__init__(self, master)
160+
tk.Frame.__init__(self, mainframe)
161+
self.mainframe = mainframe
155162
self.bind("<FocusIn>", self.on_focus_in)
156163
self.bind("<FocusOut>", self.on_focus_out)
157164
self.bind("<Configure>", self.on_configure)
@@ -165,27 +172,42 @@ def embed_browser(self):
165172
self.browser = cef.CreateBrowserSync(window_info,
166173
url="https://www.google.com/")
167174
assert self.browser
175+
self.browser.SetClientHandler(LifespanHandler(self))
168176
self.browser.SetClientHandler(LoadHandler(self))
169177
self.browser.SetClientHandler(FocusHandler(self))
170178
self.message_loop_work()
171179

172180
def get_window_handle(self):
173-
if self.winfo_id() > 0:
174-
return self.winfo_id()
175-
elif MAC:
176-
# On Mac window id is an invalid negative value (Issue #308).
177-
# This is kind of a dirty hack to get window handle using
178-
# PyObjC package. If you change structure of windows then you
181+
if MAC:
182+
# Do not use self.winfo_id() on Mac, because of these issues:
183+
# 1. Window id sometimes has an invalid negative value (Issue #308).
184+
# 2. Even with valid window id it crashes during the call to NSView.setAutoresizingMask:
185+
# https://github.com/cztomczak/cefpython/issues/309#issuecomment-661094466
186+
#
187+
# To fix it using PyObjC package to obtain window handle. If you change structure of windows then you
179188
# need to do modifications here as well.
189+
#
190+
# There is still one issue with this solution. Sometimes there is more than one window, for example when application
191+
# didn't close cleanly last time Python displays an NSAlert window asking whether to Reopen that window. In such
192+
# case app will crash and you will see in console:
193+
# > Fatal Python error: PyEval_RestoreThread: NULL tstate
194+
# > zsh: abort python tkinter_.py
195+
# Error messages related to this: https://github.com/cztomczak/cefpython/issues/441
196+
#
197+
# There is yet another issue that might be related as well:
198+
# https://github.com/cztomczak/cefpython/issues/583
199+
180200
# noinspection PyUnresolvedReferences
181201
from AppKit import NSApp
182202
# noinspection PyUnresolvedReferences
183203
import objc
184-
# Sometimes there is more than one window, when application
185-
# didn't close cleanly last time Python displays an NSAlert
186-
# window asking whether to Reopen that window.
204+
logger.info("winfo_id={}".format(self.winfo_id()))
187205
# noinspection PyUnresolvedReferences
188-
return objc.pyobjc_id(NSApp.windows()[-1].contentView())
206+
content_view = objc.pyobjc_id(NSApp.windows()[-1].contentView())
207+
logger.info("content_view={}".format(content_view))
208+
return content_view
209+
elif self.winfo_id() > 0:
210+
return self.winfo_id()
189211
else:
190212
raise Exception("Couldn't obtain window handle")
191213

@@ -224,17 +246,32 @@ def on_focus_out(self, _):
224246
self.browser.SetFocus(False)
225247

226248
def on_root_close(self):
249+
logger.info("BrowserFrame.on_root_close")
227250
if self.browser:
251+
logger.debug("CloseBrowser")
228252
self.browser.CloseBrowser(True)
229253
self.clear_browser_references()
230-
self.destroy()
254+
else:
255+
logger.debug("tk.Frame.destroy")
256+
self.destroy()
257+
231258

232259
def clear_browser_references(self):
233260
# Clear browser references that you keep anywhere in your
234261
# code. All references must be cleared for CEF to shutdown cleanly.
235262
self.browser = None
236263

237264

265+
class LifespanHandler(object):
266+
267+
def __init__(self, tkFrame):
268+
self.tkFrame = tkFrame
269+
270+
def OnBeforeClose(self, browser, **_):
271+
logger.debug("LifespanHandler.OnBeforeClose")
272+
self.tkFrame.quit()
273+
274+
238275
class LoadHandler(object):
239276

240277
def __init__(self, browser_frame):

0 commit comments

Comments
 (0)