Created
July 16, 2013 15:33
-
-
Save jegger/6009801 to your computer and use it in GitHub Desktop.
OS-rendering with wxpython
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# An example of embedding CEF browser in wxPython on Linux. | |
import ctypes, os, sys | |
libcef_so = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'libcef.so') | |
if os.path.exists(libcef_so): | |
# Import local module | |
ctypes.CDLL(libcef_so, ctypes.RTLD_GLOBAL) | |
if 0x02070000 <= sys.hexversion < 0x03000000: | |
import cefpython_py27 as cefpython | |
else: | |
raise Exception("Unsupported python version: %s" % sys.version) | |
else: | |
# Import from package | |
from cefpython3 import cefpython | |
import wx | |
import time | |
import re | |
import uuid | |
# Which method to use for message loop processing. | |
# EVT_IDLE - wx application has priority (default) | |
# EVT_TIMER - cef browser has priority | |
# It seems that Flash content behaves better when using a timer. | |
# IMPORTANT! On Linux EVT_IDLE does not work, the events seems to | |
# be propagated only when you move your mouse, which is not the | |
# expected behavior, it is recommended to use EVT_TIMER on Linux, | |
# so set this value to False. | |
USE_EVT_IDLE = False | |
def GetApplicationPath(file=None): | |
import re, os, platform | |
# If file is None return current directory without trailing slash. | |
if file is None: | |
file = "" | |
# Only when relative path. | |
if not file.startswith("/") and not file.startswith("\\") and ( | |
not re.search(r"^[\w-]+:", file)): | |
if hasattr(sys, "frozen"): | |
path = os.path.dirname(sys.executable) | |
elif "__file__" in globals(): | |
path = os.path.dirname(os.path.realpath(__file__)) | |
else: | |
path = os.getcwd() | |
path = path + os.sep + file | |
if platform.system() == "Windows": | |
path = re.sub(r"[/\\]+", re.escape(os.sep), path) | |
path = re.sub(r"[/\\]+$", "", path) | |
return path | |
return str(file) | |
def ExceptHook(excType, excValue, traceObject): | |
import traceback, os, time, codecs | |
# This hook does the following: in case of exception write it to | |
# the "error.log" file, display it to the console, shutdown CEF | |
# and exit application immediately by ignoring "finally" (_exit()). | |
errorMsg = "\n".join(traceback.format_exception(excType, excValue, | |
traceObject)) | |
errorFile = GetApplicationPath("error.log") | |
try: | |
appEncoding = cefpython.g_applicationSettings["string_encoding"] | |
except: | |
appEncoding = "utf-8" | |
if type(errorMsg) == bytes: | |
errorMsg = errorMsg.decode(encoding=appEncoding, errors="replace") | |
try: | |
with codecs.open(errorFile, mode="a", encoding=appEncoding) as fp: | |
fp.write("\n[%s] %s\n" % ( | |
time.strftime("%Y-%m-%d %H:%M:%S"), errorMsg)) | |
except: | |
print("cefpython: WARNING: failed writing to error file: %s" % ( | |
errorFile)) | |
# Convert error message to ascii before printing, otherwise | |
# you may get error like this: | |
# | UnicodeEncodeError: 'charmap' codec can't encode characters | |
errorMsg = errorMsg.encode("ascii", errors="replace") | |
errorMsg = errorMsg.decode("ascii", errors="replace") | |
print("\n"+errorMsg+"\n") | |
cefpython.QuitMessageLoop() | |
cefpython.Shutdown() | |
os._exit(1) | |
class MainFrame(wx.Frame): | |
browser = None | |
mainPanel = None | |
def __init__(self): | |
wx.Frame.__init__(self, parent=None, id=wx.ID_ANY, | |
title='wxPython CEF 3 example', size=(800,600)) | |
self.CreateMenu() | |
# Cannot attach browser to the main frame as this will cause | |
# the menu not to work. | |
self.mainPanel = wx.Panel(self) | |
#WindowInfo offscreen flag | |
windowInfo = cefpython.WindowInfo() | |
windowInfo.SetAsOffscreen(self.mainPanel.GetGtkWidget()) | |
#Create Broswer | |
browserSettings = {} | |
browser = cefpython.CreateBrowserSync(windowInfo, browserSettings, navigateUrl="about:blank") | |
#Create RenderHandler (in ClientHandler) | |
CH = ClientHandler(browser) | |
browser.SetClientHandler(CH) | |
#Call WasResized() => force cef to call GetViewRect() | |
browser.WasResized() | |
#Load desired URL | |
browser.GetMainFrame().LoadUrl("http://www.google.com") | |
self.Bind(wx.EVT_CLOSE, self.OnClose) | |
if USE_EVT_IDLE: | |
# Bind EVT_IDLE only for the main application frame. | |
self.Bind(wx.EVT_IDLE, self.OnIdle) | |
def CreateMenu(self): | |
filemenu = wx.Menu() | |
filemenu.Append(1, "Open") | |
exit = filemenu.Append(2, "Exit") | |
self.Bind(wx.EVT_MENU, self.OnClose, exit) | |
aboutmenu = wx.Menu() | |
aboutmenu.Append(1, "CEF Python") | |
menubar = wx.MenuBar() | |
menubar.Append(filemenu,"&File") | |
menubar.Append(aboutmenu, "&About") | |
self.SetMenuBar(menubar) | |
def OnClose(self, event): | |
self.browser.CloseBrowser() | |
self.Destroy() | |
def OnIdle(self, event): | |
cefpython.MessageLoopWork() | |
class ClientHandler: | |
browser = None | |
texture = None | |
def __init__(self, browser): | |
self.browser = browser | |
def OnPaint(self, browser, paintElementType, dirtyRects, buffer): | |
print("--->OnPaint()<---") | |
return True | |
#do nothing until we know OnPaint get called from cef | |
def GetViewRect(self, browser, rect): | |
print("GetViewRect()") | |
width = 300 | |
height = 300 | |
rect.append(0) | |
rect.append(0) | |
rect.append(width) | |
rect.append(height) | |
return True | |
class MyApp(wx.App): | |
timer = None | |
timerID = 1 | |
timerCount = 0 | |
def OnInit(self): | |
if not USE_EVT_IDLE: | |
self.CreateTimer() | |
frame = MainFrame() | |
self.SetTopWindow(frame) | |
frame.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): | |
self.timerCount += 1 | |
# print("wxpython.py: OnTimer() %d" % self.timerCount) | |
cefpython.MessageLoopWork() | |
def OnExit(self): | |
# When app.MainLoop() returns, MessageLoopWork() should | |
# not be called anymore. | |
if not USE_EVT_IDLE: | |
self.timer.Stop() | |
if __name__ == '__main__': | |
sys.excepthook = ExceptHook | |
cefpython.g_debug = True | |
cefpython.g_debugFile = GetApplicationPath("debug.log") | |
settings = { | |
"log_severity": cefpython.LOGSEVERITY_INFO, | |
"log_file": GetApplicationPath("debug.log"), | |
"release_dcheck_enabled": True, # Enable only when debugging. | |
# This directories must be set on Linux | |
"locales_dir_path": cefpython.GetModuleDirectory()+"/locales", | |
"resources_dir_path": cefpython.GetModuleDirectory(), | |
"browser_subprocess_path": "%s/%s" % ( | |
cefpython.GetModuleDirectory(), "subprocess") | |
} | |
# print("browser_subprocess_path="+settings["browser_subprocess_path"]) | |
cefpython.Initialize(settings) | |
print('wx.version=%s' % wx.version()) | |
app = MyApp(False) | |
app.MainLoop() | |
# Let wx.App destructor do the cleanup before calling cefpython.Shutdown(). | |
del app | |
cefpython.Shutdown() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment