Skip to content

Commit de76641

Browse files
committed
Fix wxpython.py example on Mac (cztomczak#295)
1 parent 7d42d99 commit de76641

File tree

1 file changed

+51
-48
lines changed

1 file changed

+51
-48
lines changed

examples/wxpython.py

Lines changed: 51 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
# To install wxPython on Linux type "sudo apt-get install python-wxtools".
55

66
# Tested configurations:
7+
# - wxPython 3.0 on Windows/Mac
78
# - wxPython 2.8 on Linux
8-
# - wxPython 3.0 on Windows
99
# - CEF Python v55.4+
1010

1111
import wx
@@ -26,6 +26,9 @@
2626
WIDTH = 800
2727
HEIGHT = 600
2828

29+
# Globals
30+
g_count_windows = 0
31+
2932

3033
def main():
3134
check_versions()
@@ -34,15 +37,15 @@ def main():
3437
if WINDOWS:
3538
# High DPI support
3639
settings["auto_zooming"] = "system_dpi"
37-
# Embed DPI awareness xml manifest inside .exe (recommended,
38-
# most reliable) or call the SetProcessDpiAware function.
3940
# noinspection PyUnresolvedReferences, PyArgumentList
40-
cef.DpiAware.SetProcessDpiAware()
41+
cef.DpiAware.SetProcessDpiAware() # Alternative is to embed manifest
4142
cef.Initialize(settings=settings)
4243
app = CefApp(False)
4344
app.MainLoop()
4445
del app # Must destroy before calling Shutdown
45-
cef.Shutdown()
46+
if not MAC:
47+
# On Mac shutdown is called in OnClose
48+
cef.Shutdown()
4649

4750

4851
def check_versions():
@@ -60,6 +63,9 @@ def __init__(self):
6063
title='wxPython example', size=(WIDTH, HEIGHT))
6164
self.browser = None
6265

66+
global g_count_windows
67+
g_count_windows += 1
68+
6369
self.setup_icon()
6470
self.create_menu()
6571
self.Bind(wx.EVT_CLOSE, self.OnClose)
@@ -70,9 +76,14 @@ def __init__(self):
7076
self.browser_panel.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
7177
self.browser_panel.Bind(wx.EVT_SIZE, self.OnSize)
7278

73-
# Must show so that handle is available when embedding browser
74-
self.Show()
75-
self.embed_browser()
79+
# On Linux must show before embedding browser, so that handle
80+
# is available.
81+
if LINUX:
82+
self.Show()
83+
self.embed_browser()
84+
else:
85+
self.embed_browser()
86+
self.Show()
7687

7788
def setup_icon(self):
7889
icon_file = os.path.join(os.path.abspath(os.path.dirname(__file__)),
@@ -85,16 +96,15 @@ def create_menu(self):
8596
filemenu = wx.Menu()
8697
filemenu.Append(1, "Some option")
8798
filemenu.Append(2, "Another option")
88-
aboutmenu = wx.Menu()
89-
aboutmenu.Append(1, "Yet another option")
9099
menubar = wx.MenuBar()
91100
menubar.Append(filemenu, "&File")
92-
menubar.Append(aboutmenu, "&About")
93101
self.SetMenuBar(menubar)
94102

95103
def embed_browser(self):
96104
window_info = cef.WindowInfo()
97-
window_info.SetAsChild(self.browser_panel.GetHandle())
105+
(width, height) = self.browser_panel.GetClientSizeTuple()
106+
window_info.SetAsChild(self.browser_panel.GetHandle(),
107+
[0, 0, width, height])
98108
self.browser = cef.CreateBrowserSync(window_info,
99109
url="https://www.google.com/")
100110
self.browser.SetClientHandler(FocusHandler())
@@ -120,49 +130,42 @@ def OnSize(self, _):
120130
self.browser.NotifyMoveOrResizeStarted()
121131

122132
def OnClose(self, event):
123-
# In cefpython3.wx.chromectrl example calling browser.CloseBrowser()
124-
# and/or self.Destroy() in OnClose is causing crashes when
125-
# embedding multiple browser tabs. The solution is to call only
126-
# browser.ParentWindowWillClose. Behavior of this example
127-
# seems different as it extends wx.Frame, while ChromeWindow
128-
# from chromectrl extends wx.Window. Calling CloseBrowser
129-
# and Destroy does not cause crashes, but is not recommended.
130-
# Call ParentWindowWillClose and event.Skip() instead. See
131-
# also Issue #107: https://github.com/cztomczak/cefpython/issues/107
132-
self.browser.ParentWindowWillClose()
133-
event.Skip()
134-
135-
# Clear all browser references for CEF to shutdown cleanly
136-
del self.browser
137-
138-
139-
class FocusHandler(object):
133+
print("[wxpython.py] OnClose called")
134+
if not self.browser:
135+
# May already be closing, may be called multiple times on Mac
136+
return
140137

141-
def __init__(self):
142-
pass
138+
if MAC:
139+
# On Mac things work differently, other steps are required
140+
self.browser.CloseBrowser()
141+
self.clear_browser_references()
142+
self.Destroy()
143+
global g_count_windows
144+
g_count_windows -= 1
145+
if g_count_windows == 0:
146+
cef.Shutdown()
147+
wx.GetApp().Exit()
148+
else:
149+
# Calling browser.CloseBrowser() and/or self.Destroy()
150+
# in OnClose may cause app crash on some paltforms in
151+
# some use cases, details in Issue #107.
152+
self.browser.ParentWindowWillClose()
153+
event.Skip()
154+
self.clear_browser_references()
155+
156+
def clear_browser_references(self):
157+
# Clear browser references that you keep anywhere in your
158+
# code. All references must be cleared for CEF to shutdown cleanly.
159+
self.browser = None
143160

144-
def OnTakeFocus(self, **kwargs):
145-
# print("[wxpython.py] FocusHandler.OnTakeFocus, next={next}"
146-
# .format(next=kwargs["next_component"]]))
147-
pass
148161

149-
def OnSetFocus(self, **kwargs):
150-
# source_enum = {cef.FOCUS_SOURCE_NAVIGATION: "navigation",
151-
# cef.FOCUS_SOURCE_SYSTEM: "system"}
152-
# print("[wxpython.py] FocusHandler.OnSetFocus, source={source}"
153-
# .format(source=source_enum[kwargs["source"]]))
154-
# return False
155-
pass
162+
class FocusHandler(object):
156163

157164
def OnGotFocus(self, browser, **_):
158165
# Temporary fix for focus issues on Linux (Issue #284).
159-
# If this is not applied then when switching to another
160-
# window (alt+tab) and then back to this example, keyboard
161-
# focus becomes broken, you can't type anything, even
162-
# though a type cursor blinks in web view.
163166
if LINUX:
164167
print("[wxpython.py] FocusHandler.OnGotFocus:"
165-
" keyboard focus fix (#284)")
168+
" keyboard focus fix (Issue #284)")
166169
browser.SetFocus(True)
167170

168171

@@ -185,7 +188,7 @@ def create_timer(self):
185188
# http://wiki.wxwidgets.org/Making_a_render_loop
186189
# Another way would be to use EVT_IDLE in MainFrame.
187190
self.timer = wx.Timer(self, self.timer_id)
188-
self.timer.Start(10) # 10ms
191+
self.timer.Start(10) # 10ms timer
189192
wx.EVT_TIMER(self, self.timer_id, self.on_timer)
190193

191194
def on_timer(self, _):

0 commit comments

Comments
 (0)