@@ -125,7 +125,7 @@ def __init__(self, url=None, popup=False):
125125 wx .Frame .__init__ (self , parent = None , id = wx .ID_ANY ,
126126 title = title )
127127 size = (800 ,600 )
128-
128+
129129 # This is an optional code to enable High DPI support.
130130 if "auto_zooming" in g_applicationSettings \
131131 and g_applicationSettings ["auto_zooming" ] == "system_dpi" :
@@ -150,22 +150,22 @@ def __init__(self, url=None, popup=False):
150150 self .mainPanel = wx .Panel (self , style = wx .WANTS_CHARS )
151151
152152 # Global client callbacks must be set before browser is created.
153- clientHandler = ClientHandler ()
153+ self . clientHandler = ClientHandler ()
154154 cefpython .SetGlobalClientCallback ("OnCertificateError" ,
155- clientHandler ._OnCertificateError )
155+ self . clientHandler ._OnCertificateError )
156156 cefpython .SetGlobalClientCallback ("OnBeforePluginLoad" ,
157- clientHandler ._OnBeforePluginLoad )
157+ self . clientHandler ._OnBeforePluginLoad )
158158 cefpython .SetGlobalClientCallback ("OnAfterCreated" ,
159- clientHandler ._OnAfterCreated )
159+ self . clientHandler ._OnAfterCreated )
160160
161161 windowInfo = cefpython .WindowInfo ()
162162 windowInfo .SetAsChild (self .GetHandleForBrowser ())
163163 self .browser = cefpython .CreateBrowserSync (windowInfo ,
164164 browserSettings = g_browserSettings ,
165165 navigateUrl = url )
166-
167- clientHandler .mainBrowser = self .browser
168- self .browser .SetClientHandler (clientHandler )
166+
167+ self . clientHandler .mainBrowser = self .browser
168+ self .browser .SetClientHandler (self . clientHandler )
169169
170170 jsBindings = cefpython .JavascriptBindings (
171171 bindToFrames = False , bindToPopups = True )
@@ -174,7 +174,8 @@ def __init__(self, url=None, popup=False):
174174 jsBindings .SetProperty ("pyConfig" , ["This was set in Python" ,
175175 {"name" : "Nested dictionary" , "isNested" : True },
176176 [1 ,"2" , None ]])
177- jsBindings .SetObject ("external" , JavascriptExternal (self .browser ))
177+ self .javascriptExternal = JavascriptExternal (self .browser )
178+ jsBindings .SetObject ("external" , self .javascriptExternal )
178179 jsBindings .SetProperty ("sources" , GetSources ())
179180 self .browser .SetJavascriptBindings (jsBindings )
180181
@@ -210,17 +211,25 @@ def OnSize(self, event):
210211 cefpython .WindowUtils .OnSize (self .GetHandleForBrowser (), 0 , 0 , 0 )
211212
212213 def OnClose (self , event ):
213- # In wx.chromectrl calling browser.CloseBrowser() and/or
214- # self.Destroy() in OnClose is causing crashes when embedding
215- # multiple browser tabs. The solution is to call only
216- # browser.ParentWindowWillClose. Behavior of this example
217- # seems different as it extends wx.Frame, while ChromeWindow
218- # from chromectrl extends wx.Window. Calling CloseBrowser
219- # and Destroy does not cause crashes, but is not recommended.
220- # Call ParentWindowWillClose and event.Skip() instead. See
221- # also Issue 107.
222- self .browser .ParentWindowWillClose ()
223- event .Skip ()
214+ if self .browser :
215+ # Calling CloseBrowser will cause that OnClose event occurs again,
216+ # so self.browser must be checked if non-empty.
217+ self .browser .StopLoad ()
218+ self .browser .CloseBrowser ()
219+ # Remove all CEF browser references so that browser is closed
220+ # cleanly. Otherwise there may be issues for example with cookies
221+ # not being flushed to disk when closing app immediately
222+ # (Issue 158).
223+ del self .javascriptExternal .mainBrowser
224+ del self .clientHandler .mainBrowser
225+ del self .browser
226+ self .Destroy ()
227+ # In wx.chromectrl calling browser.CloseBrowser and/or self.Destroy
228+ # may cause crashes when embedding multiple browsers in tab
229+ # (Issue 107). In such case instead of calling CloseBrowser/Destroy
230+ # try this code:
231+ # | self.browser.ParentWindowWillClose()
232+ # | event.Skip()
224233
225234 def OnIdle (self , event ):
226235 cefpython .MessageLoopWork ()
@@ -514,6 +523,11 @@ def GetCookieManager(self, browser, mainUrl):
514523 print ("[wxpython.py] RequestHandler::GetCookieManager():" \
515524 " created cookie manager" )
516525 cookieManager = cefpython .CookieManager .CreateManager ("" )
526+ if "cache_path" in g_applicationSettings :
527+ path = g_applicationSettings ["cache_path" ]
528+ # path = os.path.join(path, "cookies_browser_{}".format(
529+ # browser.GetIdentifier()))
530+ cookieManager .SetStoragePath (path )
517531 browser .SetUserData ("cookieManager" , cookieManager )
518532 return cookieManager
519533
@@ -595,7 +609,7 @@ def OnLoadEnd(self, browser, frame, httpStatusCode):
595609 print (" http status code = %s" % httpStatusCode )
596610 # Tests for the Browser object methods
597611 self ._Browser_LoadUrl (browser )
598-
612+
599613 def _Browser_LoadUrl (self , browser ):
600614 if browser .GetUrl () == "data:text/html,Test#Browser.LoadUrl" :
601615 browser .LoadUrl ("file://" + GetApplicationPath ("wxpython.html" ))
@@ -635,7 +649,7 @@ def OnBeforePopup(self, browser, frame, targetUrl, targetFrameName,
635649
636650 # Set WindowInfo object:
637651 # > windowInfo[0] = cefpython.WindowInfo()
638-
652+
639653 # On Windows there are keyboard problems in popups, when popup
640654 # is created using "window.open" or "target=blank". This issue
641655 # occurs only in wxPython. PyGTK or PyQt do not require this fix.
@@ -711,14 +725,15 @@ def OnJavascriptDialogClosed(self, browser):
711725class MyApp (wx .App ):
712726 timer = None
713727 timerID = 1
728+ mainFrame = None
714729
715730 def OnInit (self ):
716731 if not USE_EVT_IDLE :
717- print ("Using TIMER to execute the CEF message loop work " )
732+ print ("[wxpython.py] Using TIMER to run CEF message loop" )
718733 self .CreateTimer ()
719- frame = MainFrame ()
720- self .SetTopWindow (frame )
721- frame .Show ()
734+ self . mainFrame = MainFrame ()
735+ self .SetTopWindow (self . mainFrame )
736+ self . mainFrame .Show ()
722737 return True
723738
724739 def CreateTimer (self ):
@@ -736,6 +751,7 @@ def OnTimer(self, event):
736751 def OnExit (self ):
737752 # When app.MainLoop() returns, MessageLoopWork() should
738753 # not be called anymore.
754+ print ("[wxpython.py] MyApp.OnExit" )
739755 if not USE_EVT_IDLE :
740756 self .timer .Stop ()
741757
@@ -772,6 +788,9 @@ def GetSources():
772788
773789 # Application settings
774790 g_applicationSettings = {
791+ # Disk cache
792+ # "cache_path": "webcache/",
793+
775794 # CEF Python debug messages in console and in log_file
776795 "debug" : True ,
777796 # Set it to LOGSEVERITY_VERBOSE for more details
@@ -780,6 +799,7 @@ def GetSources():
780799 "log_file" : GetApplicationPath ("debug.log" ),
781800 # This should be enabled only when debugging
782801 "release_dcheck_enabled" : True ,
802+
783803 # These directories must be set on Linux
784804 "locales_dir_path" : cefpython .GetModuleDirectory ()+ "/locales" ,
785805 "resources_dir_path" : cefpython .GetModuleDirectory (),
@@ -788,13 +808,15 @@ def GetSources():
788808 # executable if you like.
789809 "browser_subprocess_path" : "%s/%s" % (
790810 cefpython .GetModuleDirectory (), "subprocess" ),
811+
791812 # This option is required for the GetCookieManager callback
792813 # to work. It affects renderer processes, when this option
793814 # is set to True. It will force a separate renderer process
794815 # for each browser created using CreateBrowserSync.
795816 "unique_request_context_per_browser" : True ,
796- # Downloads are handled automatically. A default SaveAs file
817+ # Downloads are handled automatically. A default SaveAs file
797818 # dialog provided by OS will be displayed.
819+
798820 "downloads_enabled" : True ,
799821 # Remote debugging port, required for Developer Tools support.
800822 # A value of 0 will generate a random port. To disable devtools
@@ -809,17 +831,18 @@ def GetSources():
809831 "external_browser" : True , # Open in external browser
810832 "devtools" : True , # Developer Tools
811833 },
834+
812835 # See also OnCertificateError which allows you to ignore
813836 # certificate errors for specific websites.
814837 "ignore_certificate_errors" : True ,
815838 }
816839
817840 # You can comment out the code below if you do not want High
818- # DPI support. If you disable it text will look fuzzy on
841+ # DPI support. If you disable it text will look fuzzy on
819842 # high DPI displays.
820- #
843+ #
821844 # Enabling High DPI support in app can be done by
822- # embedding a DPI awareness xml manifest in executable
845+ # embedding a DPI awareness xml manifest in executable
823846 # (see Issue 112 comment #2), or by calling SetProcessDpiAware
824847 # function. Embedding xml manifest is the most reliable method.
825848 # The downside of calling SetProcessDpiAware is that scrollbar
@@ -831,15 +854,15 @@ def GetSources():
831854 # javascript dialogs (alert) are tiny. However, you can implement
832855 # custom javascript dialogs using JavascriptDialogHandler.
833856 #
834- # Additionally you have to set "auto_zomming" application
857+ # Additionally you have to set "auto_zomming" application
835858 # setting. High DPI support is available only on Windows.
836859 # You may set auto_zooming to "system_dpi" and browser
837860 # contents will be zoomed using OS DPI settings. On Win7
838861 # these can be set in: Control Panel > Appearance and
839862 # Personalization > Display.
840863 #
841864 # Example values for auto_zooming are:
842- # "system_dpi", "0.0" (96 DPI), "1.0" (120 DPI),
865+ # "system_dpi", "0.0" (96 DPI), "1.0" (120 DPI),
843866 # "2.0" (144 DPI), "-1.0" (72 DPI)
844867 # Numeric value means a zoom level.
845868 # Example values that can be set in Win7 DPI settings:
@@ -850,15 +873,15 @@ def GetSources():
850873 g_applicationSettings ["auto_zooming" ] = "system_dpi"
851874 print ("[wxpython.py] Calling SetProcessDpiAware" )
852875 cefpython .DpiAware .SetProcessDpiAware ()
853-
876+
854877 # Browser settings. You may have different settings for each
855878 # browser, see the call to CreateBrowserSync.
856879 g_browserSettings = {
857880 # "plugins_disabled": True,
858881 # "file_access_from_file_urls_allowed": True,
859882 # "universal_access_from_file_urls_allowed": True,
860883 }
861-
884+
862885 # Command line switches set programmatically
863886 g_commandLineSwitches = {
864887 # "proxy-server": "socks5://127.0.0.1:8888",
@@ -867,12 +890,15 @@ def GetSources():
867890 # "disable-gpu": "",
868891
869892 }
870-
893+
871894 cefpython .Initialize (g_applicationSettings , g_commandLineSwitches )
872-
895+
873896 app = MyApp (False )
874897 app .MainLoop ()
875- # Let wx.App destructor do the cleanup before calling cefpython.Shutdown().
898+
899+ # Let wx.App destructor do the cleanup before calling
900+ # cefpython.Shutdown(). This is to ensure reliable CEF shutdown.
876901 del app
877-
902+
878903 cefpython .Shutdown ()
904+
0 commit comments