@@ -17,75 +17,109 @@ MOUSEBUTTON_RIGHT = cef_types.MBT_RIGHT
1717# get segmentation faults, as they will be garbage collected.
1818
1919cdef dict g_pyBrowsers = {}
20+
21+ # Unreferenced browsers are added to this list in OnBeforeClose().
22+ # Must keep a list of unreferenced browsers so that a new reference
23+ # is not created in GetPyBrowser() when browser was closed.
24+ cdef list g_unreferenced_browsers = [] # [int identifier, ..]
25+
26+ # Browsers that are about to be closed are added to this list in
27+ # CloseBrowser().
2028cdef list g_closed_browsers = [] # [int identifier, ..]
2129
2230cdef PyBrowser GetPyBrowserById(int browserId):
31+ """ May return None value so always check returned value."""
2332 if browserId in g_pyBrowsers:
2433 return g_pyBrowsers[browserId]
2534 return None
2635
27- cdef PyBrowser GetPyBrowser(CefRefPtr[CefBrowser] cefBrowser):
36+ cdef PyBrowser GetPyBrowser(CefRefPtr[CefBrowser] cefBrowser,
37+ callerIdStr = " GetPyBrowser" ):
38+ """ The second argument 'callerIdStr' is so that a debug
39+ message can be displayed informing which CEF handler callback
40+ is being called to which an incomplete PyBrowser instance is
41+ provided."""
42+
2843 global g_pyBrowsers
44+
45+ # This probably ain't needed, but just to be sure.
2946 if < void * > cefBrowser == NULL or not cefBrowser.get():
30- # noinspection PyUnresolvedReferences
31- Debug(" GetPyBrowser(): returning None" )
32- return None
47+ raise Exception (" {caller}: CefBrowser reference is NULL"
48+ .format(caller = callerIdStr))
3349
3450 cdef PyBrowser pyBrowser
3551 cdef int browserId
36- cdef int identifier
37-
3852 browserId = cefBrowser.get().GetIdentifier()
53+
3954 if browserId in g_pyBrowsers:
4055 return g_pyBrowsers[browserId]
4156
57+ # This code probably ain't needed.
58+ # ----
59+ cdef list toRemove = []
60+ cdef int identifier
4261 for identifier, pyBrowser in g_pyBrowsers.items():
4362 if not pyBrowser.cefBrowser.get():
44- # noinspection PyUnresolvedReferences
45- Debug(" GetPyBrowser(): removing an empty CefBrowser reference, "
46- " browserId=%s " % identifier)
47- del g_pyBrowsers[identifier]
63+ toRemove.append(identifier)
64+ for identifier in toRemove:
65+ Debug(" GetPyBrowser(): removing an empty CefBrowser reference,"
66+ " browserId=%s " % identifier)
67+ RemovePyBrowser(identifier)
68+ # ----
4869
49- # noinspection PyUnresolvedReferences
50- Debug(" GetPyBrowser(): creating new PyBrowser, browserId=%s " % browserId)
5170 pyBrowser = PyBrowser()
5271 pyBrowser.cefBrowser = cefBrowser
53- g_pyBrowsers[browserId] = pyBrowser
54-
55- # Inherit client callbacks and javascript bindings
56- # from parent browser.
57-
58- # Checking __outerWindowHandle as we should not inherit
59- # client callbacks and javascript bindings if the browser
60- # was created explicitily by calling CreateBrowserSync().
61-
62- # Popups inherit client callbacks by default.
63-
64- # Popups inherit javascript bindings only when "bindToPopups"
65- # constructor param was set to True.
6672
6773 cdef WindowHandle openerHandle
6874 cdef dict clientCallbacks
6975 cdef JavascriptBindings javascriptBindings
7076 cdef PyBrowser tempPyBrowser
7177
72- if pyBrowser.IsPopup() and \
73- not pyBrowser.GetUserData(" __outerWindowHandle" ):
74- openerHandle = pyBrowser.GetOpenerWindowHandle()
75- for identifier, tempPyBrowser in g_pyBrowsers.items():
76- if tempPyBrowser.GetWindowHandle() == openerHandle:
77- clientCallbacks = tempPyBrowser.GetClientCallbacksDict()
78- if clientCallbacks:
79- pyBrowser.SetClientCallbacksDict(clientCallbacks)
80- javascriptBindings = tempPyBrowser.GetJavascriptBindings()
81- if javascriptBindings:
82- if javascriptBindings.GetBindToPopups():
83- pyBrowser.SetJavascriptBindings(javascriptBindings)
78+ if browserId in g_unreferenced_browsers:
79+ # This browser was already unreferenced due to OnBeforeClose
80+ # was already called. An incomplete new instance of Browser
81+ # object is created. This instance doesn't have the client
82+ # callbacks, javascript bindings or user data that was already
83+ # available in the original Browser object.
84+ Debug(" {caller}: Browser was already globally unreferenced"
85+ " , a new incomplete instance is created, browser id={id}"
86+ .format(caller = callerIdStr, id = str (browserId)))
87+ else :
88+ # This is first creation of browser. Store a reference globally
89+ # and inherit client callbacks and javascript bindings from
90+ # parent browsers.
91+ Debug(" GetPyBrowser(): create new PyBrowser, browserId=%s "
92+ % browserId)
93+
94+ g_pyBrowsers[browserId] = pyBrowser
95+
96+ # Inherit client callbacks and javascript bindings
97+ # from parent browser.
98+ # - Checking __outerWindowHandle as we should not inherit
99+ # client callbacks and javascript bindings if the browser
100+ # was created explicitily by calling CreateBrowserSync().
101+ # - Popups inherit client callbacks by default.
102+ # - Popups inherit javascript bindings only when "bindToPopups"
103+ # constructor param was set to True.
104+
105+ if pyBrowser.IsPopup() and \
106+ not pyBrowser.GetUserData(" __outerWindowHandle" ):
107+ openerHandle = pyBrowser.GetOpenerWindowHandle()
108+ for identifier, tempPyBrowser in g_pyBrowsers.items():
109+ if tempPyBrowser.GetWindowHandle() == openerHandle:
110+ clientCallbacks = tempPyBrowser.GetClientCallbacksDict()
111+ if clientCallbacks:
112+ pyBrowser.SetClientCallbacksDict(clientCallbacks)
113+ javascriptBindings = tempPyBrowser.GetJavascriptBindings()
114+ if javascriptBindings:
115+ if javascriptBindings.GetBindToPopups():
116+ pyBrowser.SetJavascriptBindings(javascriptBindings)
117+
84118 return pyBrowser
85119
86120cdef void RemovePyBrowser(int browserId) except * :
87121 # Called from LifespanHandler_OnBeforeClose().
88- global g_pyBrowsers
122+ global g_pyBrowsers, g_unreferenced_browsers
89123 if browserId in g_pyBrowsers:
90124 if len (g_pyBrowsers) == 1 :
91125 # This is the last browser remaining.
@@ -97,6 +131,7 @@ cdef void RemovePyBrowser(int browserId) except *:
97131 # noinspection PyUnresolvedReferences
98132 Debug(" del g_pyBrowsers[%s ]" % browserId)
99133 del g_pyBrowsers[browserId]
134+ g_unreferenced_browsers.append(browserId)
100135 else :
101136 # noinspection PyUnresolvedReferences
102137 Debug(" RemovePyBrowser() FAILED: browser not found, id = %s " \
@@ -116,7 +151,7 @@ cdef public void PyBrowser_ShowDevTools(CefRefPtr[CefBrowser] cefBrowser
116151 # Called from ClientHandler::OnContextMenuCommand
117152 cdef PyBrowser pyBrowser
118153 try :
119- pyBrowser = GetPyBrowser(cefBrowser)
154+ pyBrowser = GetPyBrowser(cefBrowser, " ShowDevTools " )
120155 pyBrowser.ShowDevTools()
121156 except :
122157 (exc_type, exc_value, exc_trace) = sys.exc_info()
0 commit comments