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
1111import wx
2626WIDTH = 800
2727HEIGHT = 600
2828
29+ # Globals
30+ g_count_windows = 0
31+
2932
3033def 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
4851def 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