|
1 | | -# This example is throwing segmentation faults when run on Linux, |
2 | | -# the problem seems to be in a call to CreateBrowserSync(), |
3 | | -# the backtrace leads to CefBrowserHostImpl::PlatformCreateWindow(). |
4 | | -# Full backtrace: |
5 | | -""" |
6 | | -0x00007ffff1ee52a0 in CefBrowserHostImpl::PlatformCreateWindow() () |
7 | | - from /home/czarek/cefpython/cefpython/cef3/linux/binaries_64bit/libcef.so |
8 | | -(gdb) backtrace |
9 | | -#0 0x00007ffff1ee52a0 in CefBrowserHostImpl::PlatformCreateWindow() () |
10 | | - from /home/czarek/cefpython/cefpython/cef3/linux/binaries_64bit/libcef.so |
11 | | -#1 0x00007ffff1e24930 in CefBrowserHostImpl::Create(CefWindowInfo const&, CefStructBase<CefBrowserSettingsTraits> const&, CefRefPtr<CefClient>, content::WebContents*, scoped_refptr<CefBrowserInfo>, _GtkWidget*) () |
12 | | - from /home/czarek/cefpython/cefpython/cef3/linux/binaries_64bit/libcef.so |
13 | | -#2 0x00007ffff1e251ec in CefBrowserHost::CreateBrowserSync(CefWindowInfo const&, CefRefPtr<CefClient>, CefStringBase<CefStringTraitsUTF16> const&, CefStructBase<CefBrowserSettingsTraits> const&) () |
14 | | - from /home/czarek/cefpython/cefpython/cef3/linux/binaries_64bit/libcef.so |
15 | | -#3 0x00007ffff1dc9fec in cef_browser_host_create_browser_sync () |
16 | | - from /home/czarek/cefpython/cefpython/cef3/linux/binaries_64bit/libcef.so |
17 | | -#4 0x00007fffe8136e4f in CefBrowserHost::CreateBrowserSync(CefWindowInfo const&, CefRefPtr<CefClient>, CefStringBase<CefStringTraitsUTF16> const&, CefStructBase<CefBrowserSettingsTraits> const&) () |
18 | | - from /home/czarek/cefpython/cefpython/cef3/linux/binaries_64bit/cefpython_py27.so |
19 | | -#5 0x00007fffe8111cce in __pyx_pf_14cefpython_py27_16CreateBrowserSync ( |
20 | | - __pyx_v_windowInfo=<cefpython_py27.WindowInfo at remote 0xdc7fb0>, |
21 | | - __pyx_v_browserSettings=<optimized out>, __pyx_v_navigateUrl= |
22 | | - 'file:///home/czarek/cefpython/cefpython/cef3/linux/binaries_64bit/example.html', __pyx_self=<optimized out>) at cefpython.cpp:65142 |
23 | | -#6 0x00007fffe8114ea6 in __pyx_pw_14cefpython_py27_17CreateBrowserSync ( |
24 | | -""" |
25 | | - |
26 | | -# An example of embedding CEF Python in PyQt4 application. |
27 | | - |
28 | | -# On Ubuntu install the "python-qt4" package. |
29 | | -# Tested with version 4.9.1-2ubuntu1. |
| 1 | +# An example of embedding the CEF browser in a PyQt4 application. |
| 2 | +# Tested with PyQt "4.9.1". |
| 3 | +# Command for installing PyQt4: "sudo apt-get install python-qt4". |
30 | 4 |
|
31 | 5 | # The official CEF Python binaries come with tcmalloc hook |
32 | 6 | # disabled. But if you've built custom binaries and kept tcmalloc |
|
38 | 12 | import ctypes, os, sys |
39 | 13 | libcef_so = os.path.join(os.path.dirname(os.path.abspath(__file__)),\ |
40 | 14 | 'libcef.so') |
41 | | -# Import a local module if exists, otherwise import from |
42 | | -# an installed package. |
43 | 15 | if os.path.exists(libcef_so): |
| 16 | + # Import local module |
44 | 17 | ctypes.CDLL(libcef_so, ctypes.RTLD_GLOBAL) |
45 | 18 | if 0x02070000 <= sys.hexversion < 0x03000000: |
46 | 19 | import cefpython_py27 as cefpython |
47 | 20 | else: |
48 | 21 | raise Exception("Unsupported python version: %s" % sys.version) |
49 | 22 | else: |
| 23 | + # Import from package |
50 | 24 | from cefpython3 import cefpython |
51 | 25 |
|
52 | 26 | from PyQt4 import QtGui |
53 | 27 | from PyQt4 import QtCore |
54 | 28 |
|
55 | | -TEST_RESPONSE_READING = False |
56 | | - |
57 | 29 | def GetApplicationPath(file=None): |
58 | 30 | import re, os, platform |
59 | 31 | # If file is None return current directory without trailing slash. |
@@ -94,7 +66,7 @@ def ExceptHook(excType, excValue, traceObject): |
94 | 66 | fp.write("\n[%s] %s\n" % ( |
95 | 67 | time.strftime("%Y-%m-%d %H:%M:%S"), errorMsg)) |
96 | 68 | except: |
97 | | - print("cefpython: WARNING: failed writing to error file: %s" % ( |
| 69 | + print("[wxpython.py] WARNING: failed writing to error file: %s" % ( |
98 | 70 | errorFile)) |
99 | 71 | # Convert error message to ascii before printing, otherwise |
100 | 72 | # you may get error like this: |
@@ -126,31 +98,65 @@ def createMenu(self): |
126 | 98 | aboutmenu = menubar.addMenu("&About") |
127 | 99 |
|
128 | 100 | def focusInEvent(self, event): |
129 | | - cefpython.WindowUtils.OnSetFocus( |
130 | | - int(self.centralWidget().winId()), 0, 0, 0) |
| 101 | + # cefpython.WindowUtils.OnSetFocus( |
| 102 | + # int(self.centralWidget().winId()), 0, 0, 0) |
| 103 | + pass |
131 | 104 |
|
132 | 105 | def closeEvent(self, event): |
133 | 106 | self.mainFrame.browser.CloseBrowser() |
134 | 107 |
|
135 | | -class MainFrame(QtGui.QWidget): |
| 108 | +class MainFrame(QtGui.QX11EmbedContainer): |
136 | 109 | browser = None |
| 110 | + plug = None |
137 | 111 |
|
138 | 112 | def __init__(self, parent=None): |
139 | 113 | super(MainFrame, self).__init__(parent) |
| 114 | + |
| 115 | + # QX11EmbedContainer provides an X11 window. The CEF |
| 116 | + # browser can be embedded only by providing a GtkWidget |
| 117 | + # pointer. So we're embedding a GtkPlug inside the X11 |
| 118 | + # window. In latest CEF trunk it is possible to embed |
| 119 | + # the CEF browser by providing X11 window id. So it will |
| 120 | + # be possible to remove the GTK dependency from CEF |
| 121 | + # Python in the future. |
| 122 | + gtkPlugPtr = cefpython.WindowUtils.gtk_plug_new(\ |
| 123 | + int(self.winId())) |
| 124 | + print("[pyqt.py] MainFrame: GDK Native Window id: "+str(self.winId())) |
| 125 | + print("[pyqt.py] MainFrame: GTK Plug ptr: "+str(gtkPlugPtr)) |
| 126 | + |
| 127 | + """ |
| 128 | + Embedding GtkPlug is also possible with the pygtk module. |
| 129 | + --------------------------------------------------------- |
| 130 | + self.plug = gtk.Plug(self.winId()) |
| 131 | + import re |
| 132 | + m = re.search("GtkPlug at 0x(\w+)", str(self.plug)) |
| 133 | + hexId = m.group(1) |
| 134 | + gtkPlugPtr = int(hexId, 16) |
| 135 | + ... |
| 136 | + plug.show() |
| 137 | + self.show() |
| 138 | + --------------------------------------------------------- |
| 139 | + """ |
| 140 | + |
140 | 141 | windowInfo = cefpython.WindowInfo() |
141 | | - windowInfo.SetAsChild(int(self.winId())) |
| 142 | + # Need to pass to CEF the GtkWidget* pointer |
| 143 | + windowInfo.SetAsChild(gtkPlugPtr) |
142 | 144 | # Linux requires adding "file://" for local files, |
143 | 145 | # otherwise /home/some will be replaced as http://home/some |
144 | 146 | self.browser = cefpython.CreateBrowserSync(windowInfo, |
145 | 147 | browserSettings={}, |
146 | 148 | navigateUrl="file://"+GetApplicationPath("example.html")) |
| 149 | + |
| 150 | + cefpython.WindowUtils.gtk_widget_show(gtkPlugPtr) |
147 | 151 | self.show() |
148 | 152 |
|
149 | 153 | def moveEvent(self, event): |
150 | | - cefpython.WindowUtils.OnSize(int(self.winId()), 0, 0, 0) |
| 154 | + # cefpython.WindowUtils.OnSize(int(self.winId()), 0, 0, 0) |
| 155 | + pass |
151 | 156 |
|
152 | 157 | def resizeEvent(self, event): |
153 | | - cefpython.WindowUtils.OnSize(int(self.winId()), 0, 0, 0) |
| 158 | + # cefpython.WindowUtils.OnSize(int(self.winId()), 0, 0, 0) |
| 159 | + pass |
154 | 160 |
|
155 | 161 | class CefApplication(QtGui.QApplication): |
156 | 162 | timer = None |
@@ -183,22 +189,39 @@ def stopTimer(self): |
183 | 189 | self.timer.stop() |
184 | 190 |
|
185 | 191 | if __name__ == '__main__': |
186 | | - print("PyQt version: %s" % QtCore.PYQT_VERSION_STR) |
187 | | - print("QtCore version: %s" % QtCore.qVersion()) |
| 192 | + print("[pyqt.py] PyQt version: %s" % QtCore.PYQT_VERSION_STR) |
| 193 | + print("[pyqt.py] QtCore version: %s" % QtCore.qVersion()) |
188 | 194 |
|
| 195 | + # Intercept python exceptions. Exit app immediately when exception |
| 196 | + # happens on any of the threads. |
189 | 197 | sys.excepthook = ExceptHook |
190 | 198 |
|
191 | | - settings = {} |
192 | | - settings["debug"] = True # cefpython messages in console and in log_file |
193 | | - settings["log_file"] = GetApplicationPath("debug.log") |
194 | | - settings["log_severity"] = cefpython.LOGSEVERITY_INFO |
195 | | - settings["release_dcheck_enabled"] = True # Enable only when debugging |
196 | | - settings["locales_dir_path"] = cefpython.GetModuleDirectory()+"/locales" |
197 | | - settings["resources_dir_path"] = cefpython.GetModuleDirectory() |
198 | | - settings["browser_subprocess_path"] = "%s/%s" % ( |
199 | | - cefpython.GetModuleDirectory(), "subprocess") |
200 | | - |
201 | | - cefpython.Initialize(settings) |
| 199 | + # Application settings |
| 200 | + settings = { |
| 201 | + "debug": True, # cefpython debug messages in console and in log_file |
| 202 | + "log_severity": cefpython.LOGSEVERITY_INFO, # LOGSEVERITY_VERBOSE |
| 203 | + "log_file": GetApplicationPath("debug.log"), # Set to "" to disable. |
| 204 | + "release_dcheck_enabled": True, # Enable only when debugging. |
| 205 | + # This directories must be set on Linux |
| 206 | + "locales_dir_path": cefpython.GetModuleDirectory()+"/locales", |
| 207 | + "resources_dir_path": cefpython.GetModuleDirectory(), |
| 208 | + "browser_subprocess_path": "%s/%s" % ( |
| 209 | + cefpython.GetModuleDirectory(), "subprocess"), |
| 210 | + # This option is required for the GetCookieManager callback |
| 211 | + # to work. It affects renderer processes, when this option |
| 212 | + # is set to True. It will force a separate renderer process |
| 213 | + # for each browser created using CreateBrowserSync. |
| 214 | + "unique_request_context_per_browser": True |
| 215 | + } |
| 216 | + |
| 217 | + # Command line switches set programmatically |
| 218 | + switches = { |
| 219 | + # "proxy-server": "socks5://127.0.0.1:8888", |
| 220 | + # "enable-media-stream": "", |
| 221 | + # "--invalid-switch": "" -> Invalid switch name |
| 222 | + } |
| 223 | + |
| 224 | + cefpython.Initialize(settings, switches) |
202 | 225 |
|
203 | 226 | app = CefApplication(sys.argv) |
204 | 227 | mainWindow = MainWindow() |
|
0 commit comments