# An example of embedding CEF browser in wxPython on Windows.
# Tested with wxPython 2.8.12.1 and 3.0.2.0.
import os, sys
libcef_dll = os.path.join(os.path.dirname(os.path.abspath(__file__)),
'libcef.dll')
if os.path.exists(libcef_dll):
# Import a local module
if (2,7) browserSettings[0] = {"plugins_disabled": True}
# Set WindowInfo object:
# > windowInfo[0] = cefpython.WindowInfo()
# On Windows there are keyboard problems in popups, when popup
# is created using "window.open" or "target=blank". This issue
# occurs only in wxPython. PyGTK or PyQt do not require this fix.
# The solution is to create window explicitilly, and not depend
# on CEF to create window internally. See Issue 80 for details:
# https://github.com/cztomczak/cefpython/issues/80
# If you set allowPopups=True then CEF will create popup window.
# The wx.Frame cannot be created here, as this callback is
# executed on the IO thread. Window should be created on the UI
# thread. One solution is to call cefpython.CreateBrowser()
# which runs asynchronously and can be called on any thread.
# The other solution is to post a task on the UI thread, so
# that cefpython.CreateBrowserSync() can be used.
# Note that if you return True and create the popup window yourself,
# then the popup window and parent window will not be able to script
# each other. There will be no "window.opener" property available
# in the popup window.
cefpython.PostTask(cefpython.TID_UI, self._CreatePopup, targetUrl)
allowPopups = False
return not allowPopups
def _CreatePopup(self, url):
frame = MainFrame(url=url, popup=True)
frame.Show()
def _OnAfterCreated(self, browser):
# This is a global callback set using SetGlobalClientCallback().
print("[wxpython.py] LifespanHandler::_OnAfterCreated()")
print(" browserId=%s" % browser.GetIdentifier())
def DoClose(self, browser):
print("[wxpython.py] LifespanHandler::DoClose()")
print(" browserId=%s" % browser.GetIdentifier())
def OnBeforeClose(self, browser):
print("[wxpython.py] LifespanHandler::OnBeforeClose")
print(" browserId=%s" % browser.GetIdentifier())
# -------------------------------------------------------------------------
# JavascriptDialogHandler
# -------------------------------------------------------------------------
def OnJavascriptDialog(self, browser, originUrl, dialogType,
messageText, defaultPromptText, callback,
suppressMessage):
print("[wxpython.py] JavascriptDialogHandler::OnJavascriptDialog()")
print(" originUrl="+originUrl)
print(" dialogType="+str(dialogType))
print(" messageText="+messageText)
print(" defaultPromptText="+defaultPromptText)
# If you want to suppress the javascript dialog:
# suppressMessage[0] = True
return False
def OnBeforeUnloadJavascriptDialog(self, browser, messageText, isReload,
callback):
print("[wxpython.py] OnBeforeUnloadJavascriptDialog()")
print(" messageText="+messageText)
print(" isReload="+str(isReload))
# Return True if the application will use a custom dialog:
# callback.Continue(allow=True, userInput="")
# return True
return False
def OnResetJavascriptDialogState(self, browser):
print("[wxpython.py] OnResetDialogState()")
def OnJavascriptDialogClosed(self, browser):
print("[wxpython.py] OnDialogClosed()")
class MyApp(wx.App):
timer = None
timerID = 1
mainFrame = None
def OnInit(self):
if not USE_EVT_IDLE:
print("[wxpython.py] Using TIMER to run CEF message loop")
self.CreateTimer()
self.mainFrame = MainFrame()
self.SetTopWindow(self.mainFrame)
self.mainFrame.Show()
return True
def CreateTimer(self):
# See "Making a render loop":
# http://wiki.wxwidgets.org/Making_a_render_loop
# Another approach is to use EVT_IDLE in MainFrame,
# see which one fits you better.
self.timer = wx.Timer(self, self.timerID)
self.timer.Start(10) # 10ms
wx.EVT_TIMER(self, self.timerID, self.OnTimer)
def OnTimer(self, event):
cefpython.MessageLoopWork()
def OnExit(self):
# When app.MainLoop() returns, MessageLoopWork() should
# not be called anymore.
print("[wxpython.py] MyApp.OnExit")
if not USE_EVT_IDLE:
self.timer.Stop()
def GetSources():
# Get sources of all python functions and methods from this file.
# This is to provide sources preview to wxpython.html.
# The dictionary of functions is binded to "window.sources".
thisModule = sys.modules[__name__]
functions = inspect.getmembers(thisModule, inspect.isfunction)
classes = inspect.getmembers(thisModule, inspect.isclass)
sources = {}
for funcTuple in functions:
sources[funcTuple[0]] = inspect.getsource(funcTuple[1])
for classTuple in classes:
className = classTuple[0]
classObject = classTuple[1]
methods = inspect.getmembers(classObject)
for methodTuple in methods:
try:
sources[methodTuple[0]] = inspect.getsource(\
methodTuple[1])
except:
pass
return sources
if __name__ == '__main__':
print('[wxpython.py] architecture=%s-bit' % (8 * struct.calcsize("P")))
print('[wxpython.py] wx.version=%s' % wx.version())
# Intercept python exceptions. Exit app immediately when exception
# happens on any of the threads.
sys.excepthook = ExceptHook
# Application settings
g_applicationSettings = {
# Disk cache
# "cache_path": "webcache/",
# CEF Python debug messages in console and in log_file
"debug": True,
# Set it to LOGSEVERITY_VERBOSE for more details
"log_severity": cefpython.LOGSEVERITY_INFO,
# Set to "" to disable logging to a file
"log_file": GetApplicationPath("debug.log"),
# These directories must be set on Linux
"locales_dir_path": cefpython.GetModuleDirectory()+"/locales",
"resources_dir_path": cefpython.GetModuleDirectory(),
# The "subprocess" executable that launches the Renderer
# and GPU processes among others. You may rename that
# executable if you like.
"browser_subprocess_path": "%s/%s" % (
cefpython.GetModuleDirectory(), "subprocess"),
# This option is required for the GetCookieManager callback
# to work. It affects renderer processes, when this option
# is set to True. It will force a separate renderer process
# for each browser created using CreateBrowserSync.
"unique_request_context_per_browser": True,
# Downloads are handled automatically. A default SaveAs file
# dialog provided by OS will be displayed.
"downloads_enabled": True,
# Remote debugging port, required for Developer Tools support.
# A value of 0 will generate a random port. To disable devtools
# support set it to -1.
"remote_debugging_port": 0,
# Mouse context menu
"context_menu": {
"enabled": True,
"navigation": True, # Back, Forward, Reload
"print": True,
"view_source": True,
"external_browser": True, # Open in external browser
"devtools": True, # Developer Tools
},
# See also OnCertificateError which allows you to ignore
# certificate errors for specific websites.
"ignore_certificate_errors": True,
}
# You can comment out the code below if you do not want High
# DPI support. If you disable it text will look fuzzy on
# high DPI displays.
#
# Enabling High DPI support in app can be done by
# embedding a DPI awareness xml manifest in executable
# (see Issue 112 comment #2), or by calling SetProcessDpiAware
# function. Embedding xml manifest is the most reliable method.
# The downside of calling SetProcessDpiAware is that scrollbar
# in CEF browser is smaller than it should be. This is because
# DPI awareness was set too late, after the CEF dll was loaded.
# To fix that embed DPI awareness xml manifest in the .exe file.
#
# There is one bug when enabling High DPI support - fonts in
# javascript dialogs (alert) are tiny. However, you can implement
# custom javascript dialogs using JavascriptDialogHandler.
#
# Additionally you have to set "auto_zomming" application
# setting. High DPI support is available only on Windows.
# You may set auto_zooming to "system_dpi" and browser
# contents will be zoomed using OS DPI settings. On Win7
# these can be set in: Control Panel > Appearance and
# Personalization > Display.
#
# Example values for auto_zooming are:
# "system_dpi", "0.0" (96 DPI), "1.0" (120 DPI),
# "2.0" (144 DPI), "-1.0" (72 DPI)
# Numeric value means a zoom level.
# Example values that can be set in Win7 DPI settings:
# Smaller 100% (Default) = 96 DPI = 0.0 zoom level
# Medium 125% = 120 DPI = 1.0 zoom level
# Larger 150% = 144 DPI = 2.0 zoom level
# Custom 75% = 72 DPI = -1.0 zoom level
g_applicationSettings["auto_zooming"] = "system_dpi"
print("[wxpython.py] Calling SetProcessDpiAware")
cefpython.DpiAware.SetProcessDpiAware()
# Browser settings. You may have different settings for each
# browser, see the call to CreateBrowserSync.
g_browserSettings = {
# "plugins_disabled": True,
# "file_access_from_file_urls_allowed": True,
# "universal_access_from_file_urls_allowed": True,
}
# Command line switches set programmatically
g_commandLineSwitches = {
# "proxy-server": "socks5://127.0.0.1:8888",
# "no-proxy-server": "",
# "enable-media-stream": "",
# "disable-gpu": "",
}
cefpython.Initialize(g_applicationSettings, g_commandLineSwitches)
app = MyApp(False)
app.MainLoop()
# Let wx.App destructor do the cleanup before calling
# cefpython.Shutdown(). This is to ensure reliable CEF shutdown.
del app
cefpython.Shutdown()