X Tutup
# Copyright (c) 2012 CEF Python, see the Authors file. # All rights reserved. Licensed under BSD 3-clause license. # Project website: https://github.com/cztomczak/cefpython include "cefpython.pyx" include "browser.pyx" cdef dict g_pyFrames = {} # If a frame was unreferenced (browser closed or OnContextReleased) # it shouldn't be kept global anymore. cdef list g_unreferenced_frames = [] # [str unique identifier, ..] cdef str GetUniqueFrameId(int browserId, py_string frameId): return str(browserId) +"#"+ frameId cdef PyFrame GetPyFrameById(int browserId, py_string frameId): cdef object uniqueFrameId = GetUniqueFrameId(browserId, frameId) if uniqueFrameId in g_pyFrames: return g_pyFrames[uniqueFrameId] return None cdef PyFrame GetPyFrame(CefRefPtr[CefFrame] cefFrame): global g_pyFrames if not cefFrame or not cefFrame.get(): raise Exception("GetPyFrame(): CefFrame reference is NULL") cdef PyFrame pyFrame cdef CefString frameId = cefFrame.get().GetIdentifier() cdef int browserId = cefFrame.get().GetBrowser().get().GetIdentifier() assert (not frameId.empty() and browserId), "frameId or browserId empty" cdef str uniqueFrameId = GetUniqueFrameId(browserId, CefToPyString(frameId)) if frameId.empty(): # Underlying frame does not yet exist. In such case PyFrame # is not stored in g_pyFrames since frameId is invalid. # However even though frame is not supposed to exist, you # can still call CefFrame.ExecuteFunction and it works fine # in tutorial.py example. Debug("GetPyFrame(): underlying frame does not yet exist:" " browserId = {0}, frameId = {1}".format(browserId, CefToPyString(frameId))) else: if uniqueFrameId in g_pyFrames: return g_pyFrames[uniqueFrameId] # This code probably ain't needed. # ---- cdef list toRemove = [] for uFid, pyFrame in g_pyFrames.items(): if not pyFrame.cefFrame.get(): toRemove.append(uFid) for uFid in toRemove: Debug("GetPyFrame(): removing an empty CefFrame reference, " "uniqueFrameId = %s" % uniqueFrameId) del g_pyFrames[uFid] # ---- pyFrame = PyFrame(browserId, CefToPyString(frameId)) pyFrame.cefFrame = cefFrame if uniqueFrameId in g_unreferenced_frames \ or frameId.empty() \ or browserId in g_unreferenced_browsers \ or browserId in g_closed_browsers: # Browser was already globally unreferenced in OnBeforeClose, # thus all frames are globally unreferenced too, or frame # was unreferenced in OnContextReleased. Create a new # incomplete instance of PyFrame object. Read comments in # browser.pyx > GetPyBrowser and in Browser.md for what # "incomplete" means. pass else: # Keep a global reference to this frame only if the browser # wasn't destroyed in OnBeforeClose. Otherwise we would leave # dead frames references living forever. # SIDE EFFECT: two calls to GetPyFrame for the same frame object # may return two different PyFrame objects. Compare # frame objects always using GetIdentifier(). Debug("GetPyFrame(): create new PyFrame, frameId=%s" % CefToPyString(frameId)) g_pyFrames[uniqueFrameId] = pyFrame return pyFrame cdef void RemovePyFrame(int browserId, str frameId) except *: # Called from V8ContextHandler_OnContextReleased(). global g_pyFrames cdef PyFrame pyFrame cdef str uniqueFrameId = GetUniqueFrameId(browserId, frameId) if uniqueFrameId in g_pyFrames: Debug("del g_pyFrames[%s]" % uniqueFrameId) pyFrame = g_pyFrames[uniqueFrameId] pyFrame.cefFrame.Assign(nullptr) del pyFrame del g_pyFrames[uniqueFrameId] g_unreferenced_frames.append(uniqueFrameId) RemovePythonCallbacksForFrame(frameId) else: Debug("RemovePyFrame() FAILED: uniqueFrameId = %s" % uniqueFrameId) cdef void RemovePyFramesForBrowser(int browserId) except *: # Called from LifespanHandler_BeforeClose(). cdef list toRemove = [] cdef object uniqueFrameId cdef PyFrame pyFrame global g_pyFrames for uniqueFrameId, pyFrame in g_pyFrames.iteritems(): if pyFrame.GetBrowserIdentifier() == browserId: toRemove.append(uniqueFrameId) for uniqueFrameId in toRemove: Debug("del g_pyFrames[%s]" % uniqueFrameId) pyFrame = g_pyFrames[uniqueFrameId] pyFrame.cefFrame.Assign(nullptr) del pyFrame del g_pyFrames[uniqueFrameId] g_unreferenced_frames.append(uniqueFrameId) # RemovePythonCallbacksForBrowser already called # in LifespanHandler_OnBeforeClose. cdef class PyFrame: cdef CefRefPtr[CefFrame] cefFrame cdef int browserId cdef str frameId cdef CefRefPtr[CefFrame] GetCefFrame(self) except *: # Do not call IsValid() here, if the frame does not exist # then no big deal, no reason to crash the application. # The CEF calls will fail, but they also won't cause crash. if self.cefFrame.get(): return self.cefFrame raise Exception("PyFrame.GetCefFrame() failed: CefFrame was destroyed") def __init__(self, int browserId, py_string frameId): self.browserId = browserId self.frameId = frameId cpdef py_bool IsValid(self): if self.cefFrame and self.cefFrame.get() \ and self.cefFrame.get().IsValid(): return True return False def CallFunction(self, *args): # DEPRECATED - keep for backwards compatibility. self.ExecuteFunction(*args) cpdef py_void Copy(self): self.GetCefFrame().get().Copy() cpdef py_void Cut(self): self.GetCefFrame().get().Cut() cpdef py_void Delete(self): self.GetCefFrame().get().Delete() def ExecuteFunction(self, funcName, *args): # No need to enter V8 context as we're calling javascript # asynchronously using ExecuteJavascript() function. code = funcName+"(" for i in range(0, len(args)): if i != 0: code += ", " code += json.dumps(args[i]) code += ")" self.ExecuteJavascript(code) cpdef py_void ExecuteJavascript(self, py_string jsCode, py_string scriptUrl="", int startLine=1): self.GetCefFrame().get().ExecuteJavaScript(PyToCefStringValue(jsCode), PyToCefStringValue(scriptUrl), startLine) cpdef str GetIdentifier(self): # It is better to save browser and frame identifiers during # browser instantiation. When freeing PyBrowser and PyFrame # we need these identifiers. CefFrame and CefBrowser may already # be freed and calling methods on these objects may fail, this # may or may not include GetIdentifier() method, but let's be sure. return self.frameId cpdef PyFrame GetParent(self): return GetPyFrame(self.GetCefFrame().get().GetParent()) cpdef PyBrowser GetBrowser(self): return GetPyBrowser(self.GetCefFrame().get().GetBrowser()) cpdef int GetBrowserIdentifier(self) except *: return self.browserId cpdef str GetName(self): return CefToPyString(self.GetCefFrame().get().GetName()) cpdef py_void GetSource(self, object visitor): self.GetCefFrame().get().GetSource(CreateStringVisitor(visitor)) cpdef py_void GetText(self, object visitor): self.GetCefFrame().get().GetText(CreateStringVisitor(visitor)) cpdef str GetUrl(self): return CefToPyString(self.GetCefFrame().get().GetURL()) cpdef py_bool IsFocused(self): return self.GetCefFrame().get().IsFocused() cpdef py_bool IsMain(self): return self.GetCefFrame().get().IsMain() # cpdef py_void LoadString(self, py_string value, py_string url): # cdef CefString cefValue # cdef CefString cefUrl # PyToCefString(value, cefValue) # PyToCefString(url, cefUrl) # self.GetCefFrame().get().LoadString(cefValue, cefUrl) cpdef py_void LoadUrl(self, py_string url): cdef CefString cefUrl PyToCefString(url, cefUrl) self.GetCefFrame().get().LoadURL(cefUrl) cpdef py_void Paste(self): self.GetCefFrame().get().Paste() cpdef py_void Redo(self): self.GetCefFrame().get().Redo() cpdef py_void SelectAll(self): self.GetCefFrame().get().SelectAll() cpdef py_void Undo(self): self.GetCefFrame().get().Undo() cpdef py_void ViewSource(self): self.GetCefFrame().get().ViewSource() cpdef py_void SendProcessMessage(self, cef_process_id_t targetProcess, py_string frameId, py_string messageName, list pyArguments ) : cdef CefRefPtr[CefProcessMessage] message = \ CefProcessMessage_Create(PyToCefStringValue(messageName)) # This does not work, no idea why, the CEF implementation # seems not to allow it, both Assign() and swap() do not work: # | message.get().GetArgumentList().Assign(arguments.get()) # | message.get().GetArgumentList().swap(arguments) cdef CefRefPtr[CefListValue] messageArguments = \ message.get().GetArgumentList() PyListToExistingCefListValue(self.GetBrowserIdentifier(), frameId, pyArguments, messageArguments) Debug("SendProcessMessage(): message=%s, arguments size=%d" % ( messageName, message.get().GetArgumentList().get().GetSize())) self.GetCefFrame().get().SendProcessMessage(targetProcess, message)
X Tutup