Skip to content

Commit 8915d8f

Browse files
committed
Added GTK example on Linux (Issue 95).
1 parent 934937e commit 8915d8f

3 files changed

Lines changed: 387 additions & 0 deletions

File tree

cefpython/AUTHORS.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ Contributors (in order of first commit):
1313
Dominique Burnand <dominique.burnand@@rentouch.ch>
1414
Greg Farrell <gregfarrell.org@@gmail.com>
1515
Finn Hughes <finn.hughes1@@gmail.com>
16+
Marcelo Fernandez <fernandezm@@gmail.com>
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
# An example of embedding the CEF browser in PyGTK on Linux.
2+
# Tested with GTK "2.24.10".
3+
4+
# The official CEF Python binaries come with tcmalloc hook
5+
# disabled. But if you've built custom binaries and kept tcmalloc
6+
# hook enabled, then be aware that in such case it is required
7+
# for the cefpython module to be the very first import in
8+
# python scripts. See Issue 73 in the CEF Python Issue Tracker
9+
# for more details.
10+
11+
import ctypes, os, sys
12+
libcef_so = os.path.join(os.path.dirname(os.path.abspath(__file__)),\
13+
'libcef.so')
14+
if os.path.exists(libcef_so):
15+
# Import local module
16+
ctypes.CDLL(libcef_so, ctypes.RTLD_GLOBAL)
17+
if 0x02070000 <= sys.hexversion < 0x03000000:
18+
import cefpython_py27 as cefpython
19+
else:
20+
raise Exception("Unsupported python version: %s" % sys.version)
21+
else:
22+
# Import from package
23+
from cefpython3 import cefpython
24+
25+
import pygtk
26+
pygtk.require('2.0')
27+
import gtk
28+
import gobject
29+
import re
30+
31+
def GetApplicationPath(file=None):
32+
import re, os, platform
33+
# If file is None return current directory without trailing slash.
34+
if file is None:
35+
file = ""
36+
# Only when relative path.
37+
if not file.startswith("/") and not file.startswith("\\") and (
38+
not re.search(r"^[\w-]+:", file)):
39+
if hasattr(sys, "frozen"):
40+
path = os.path.dirname(sys.executable)
41+
elif "__file__" in globals():
42+
path = os.path.dirname(os.path.realpath(__file__))
43+
else:
44+
path = os.getcwd()
45+
path = path + os.sep + file
46+
if platform.system() == "Windows":
47+
path = re.sub(r"[/\\]+", re.escape(os.sep), path)
48+
path = re.sub(r"[/\\]+$", "", path)
49+
return path
50+
return str(file)
51+
52+
def ExceptHook(excType, excValue, traceObject):
53+
import traceback, os, time, codecs
54+
# This hook does the following: in case of exception write it to
55+
# the "error.log" file, display it to the console, shutdown CEF
56+
# and exit application immediately by ignoring "finally" (_exit()).
57+
errorMsg = "\n".join(traceback.format_exception(excType, excValue,
58+
traceObject))
59+
errorFile = GetApplicationPath("error.log")
60+
try:
61+
appEncoding = cefpython.g_applicationSettings["string_encoding"]
62+
except:
63+
appEncoding = "utf-8"
64+
if type(errorMsg) == bytes:
65+
errorMsg = errorMsg.decode(encoding=appEncoding, errors="replace")
66+
try:
67+
with codecs.open(errorFile, mode="a", encoding=appEncoding) as fp:
68+
fp.write("\n[%s] %s\n" % (
69+
time.strftime("%Y-%m-%d %H:%M:%S"), errorMsg))
70+
except:
71+
print("[pygtk_.py]: WARNING: failed writing to error file: %s" % (
72+
errorFile))
73+
# Convert error message to ascii before printing, otherwise
74+
# you may get error like this:
75+
# | UnicodeEncodeError: 'charmap' codec can't encode characters
76+
errorMsg = errorMsg.encode("ascii", errors="replace")
77+
errorMsg = errorMsg.decode("ascii", errors="replace")
78+
print("\n"+errorMsg+"\n")
79+
cefpython.QuitMessageLoop()
80+
cefpython.Shutdown()
81+
os._exit(1)
82+
83+
class PyGTKExample:
84+
mainWindow = None
85+
container = None
86+
browser = None
87+
exiting = None
88+
searchEntry = None
89+
vbox = None
90+
91+
def __init__(self):
92+
self.mainWindow = gtk.Window(gtk.WINDOW_TOPLEVEL)
93+
self.mainWindow.connect('destroy', self.OnExit)
94+
self.mainWindow.set_size_request(width=800, height=600)
95+
self.mainWindow.set_title('PyGTK CEF example')
96+
self.mainWindow.realize()
97+
98+
self.vbox = gtk.VBox(False, 0)
99+
self.vbox.pack_start(self.CreateMenu(), False, False, 0)
100+
self.mainWindow.add(self.vbox)
101+
102+
m = re.search("GtkVBox at 0x(\w+)", str(self.vbox))
103+
hexID = m.group(1)
104+
windowID = int(hexID, 16)
105+
106+
windowInfo = cefpython.WindowInfo()
107+
windowInfo.SetAsChild(windowID)
108+
# Linux requires adding "file://" for local files,
109+
# otherwise /home/some will be replaced as http://home/some
110+
self.browser = cefpython.CreateBrowserSync(
111+
windowInfo,
112+
browserSettings={},
113+
navigateUrl="file://"+GetApplicationPath("example.html"))
114+
115+
self.vbox.show()
116+
self.mainWindow.show()
117+
gobject.timeout_add(10, self.OnTimer)
118+
119+
def CreateMenu(self):
120+
file = gtk.MenuItem('File')
121+
file.show()
122+
filemenu = gtk.Menu()
123+
item = gtk.MenuItem('Open')
124+
filemenu.append(item)
125+
item.show()
126+
item = gtk.MenuItem('Exit')
127+
filemenu.append(item)
128+
item.show()
129+
file.set_submenu(filemenu)
130+
131+
about = gtk.MenuItem('About')
132+
about.show()
133+
aboutmenu = gtk.Menu()
134+
item = gtk.MenuItem('CEF Python')
135+
aboutmenu.append(item)
136+
item.show()
137+
about.set_submenu(aboutmenu)
138+
139+
menubar = gtk.MenuBar()
140+
menubar.append(file)
141+
menubar.append(about)
142+
menubar.show()
143+
144+
return menubar
145+
146+
def OnWidgetClick(self, widget, data):
147+
self.mainWindow.get_window().focus()
148+
149+
def OnTimer(self):
150+
if self.exiting:
151+
return False
152+
cefpython.MessageLoopWork()
153+
return True
154+
155+
def OnFocusIn(self, widget, data):
156+
# This function is currently not called by any of code,
157+
# but if you would like for browser to have automatic focus
158+
# add such line:
159+
# self.mainWindow.connect('focus-in-event', self.OnFocusIn)
160+
self.browser.SetFocus(True)
161+
162+
def OnExit(self, widget, data=None):
163+
self.exiting = True
164+
gtk.main_quit()
165+
166+
if __name__ == '__main__':
167+
version = '.'.join(map(str, list(gtk.gtk_version)))
168+
print('[pygtk_.py] GTK version: %s' % version)
169+
170+
# Intercept python exceptions. Exit app immediately when exception
171+
# happens on any of the threads.
172+
sys.excepthook = ExceptHook
173+
174+
# Application settings
175+
settings = {
176+
"debug": True, # cefpython debug messages in console and in log_file
177+
"log_severity": cefpython.LOGSEVERITY_INFO, # LOGSEVERITY_VERBOSE
178+
"log_file": GetApplicationPath("debug.log"), # Set to "" to disable
179+
"release_dcheck_enabled": True, # Enable only when debugging
180+
# This directories must be set on Linux
181+
"locales_dir_path": cefpython.GetModuleDirectory()+"/locales",
182+
"resources_dir_path": cefpython.GetModuleDirectory(),
183+
"browser_subprocess_path": "%s/%s" % (
184+
cefpython.GetModuleDirectory(), "subprocess"),
185+
}
186+
187+
cefpython.Initialize(settings)
188+
189+
gobject.threads_init() # Timer for the message loop
190+
PyGTKExample()
191+
gtk.main()
192+
193+
cefpython.Shutdown()
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
# An example of embedding the CEF browser in PyGTK on Linux.
2+
# Tested with GTK "2.24.10".
3+
4+
# The official CEF Python binaries come with tcmalloc hook
5+
# disabled. But if you've built custom binaries and kept tcmalloc
6+
# hook enabled, then be aware that in such case it is required
7+
# for the cefpython module to be the very first import in
8+
# python scripts. See Issue 73 in the CEF Python Issue Tracker
9+
# for more details.
10+
11+
import ctypes, os, sys
12+
libcef_so = os.path.join(os.path.dirname(os.path.abspath(__file__)),\
13+
'libcef.so')
14+
if os.path.exists(libcef_so):
15+
# Import local module
16+
ctypes.CDLL(libcef_so, ctypes.RTLD_GLOBAL)
17+
if 0x02070000 <= sys.hexversion < 0x03000000:
18+
import cefpython_py27 as cefpython
19+
else:
20+
raise Exception("Unsupported python version: %s" % sys.version)
21+
else:
22+
# Import from package
23+
from cefpython3 import cefpython
24+
25+
import pygtk
26+
pygtk.require('2.0')
27+
import gtk
28+
import gobject
29+
import re
30+
31+
def GetApplicationPath(file=None):
32+
import re, os, platform
33+
# If file is None return current directory without trailing slash.
34+
if file is None:
35+
file = ""
36+
# Only when relative path.
37+
if not file.startswith("/") and not file.startswith("\\") and (
38+
not re.search(r"^[\w-]+:", file)):
39+
if hasattr(sys, "frozen"):
40+
path = os.path.dirname(sys.executable)
41+
elif "__file__" in globals():
42+
path = os.path.dirname(os.path.realpath(__file__))
43+
else:
44+
path = os.getcwd()
45+
path = path + os.sep + file
46+
if platform.system() == "Windows":
47+
path = re.sub(r"[/\\]+", re.escape(os.sep), path)
48+
path = re.sub(r"[/\\]+$", "", path)
49+
return path
50+
return str(file)
51+
52+
def ExceptHook(excType, excValue, traceObject):
53+
import traceback, os, time, codecs
54+
# This hook does the following: in case of exception write it to
55+
# the "error.log" file, display it to the console, shutdown CEF
56+
# and exit application immediately by ignoring "finally" (_exit()).
57+
errorMsg = "\n".join(traceback.format_exception(excType, excValue,
58+
traceObject))
59+
errorFile = GetApplicationPath("error.log")
60+
try:
61+
appEncoding = cefpython.g_applicationSettings["string_encoding"]
62+
except:
63+
appEncoding = "utf-8"
64+
if type(errorMsg) == bytes:
65+
errorMsg = errorMsg.decode(encoding=appEncoding, errors="replace")
66+
try:
67+
with codecs.open(errorFile, mode="a", encoding=appEncoding) as fp:
68+
fp.write("\n[%s] %s\n" % (
69+
time.strftime("%Y-%m-%d %H:%M:%S"), errorMsg))
70+
except:
71+
print("[pygtk_.py]: WARNING: failed writing to error file: %s" % (
72+
errorFile))
73+
# Convert error message to ascii before printing, otherwise
74+
# you may get error like this:
75+
# | UnicodeEncodeError: 'charmap' codec can't encode characters
76+
errorMsg = errorMsg.encode("ascii", errors="replace")
77+
errorMsg = errorMsg.decode("ascii", errors="replace")
78+
print("\n"+errorMsg+"\n")
79+
cefpython.QuitMessageLoop()
80+
cefpython.Shutdown()
81+
os._exit(1)
82+
83+
class PyGTKExample:
84+
mainWindow = None
85+
container = None
86+
browser = None
87+
exiting = None
88+
searchEntry = None
89+
vbox = None
90+
91+
def __init__(self):
92+
self.mainWindow = gtk.Window(gtk.WINDOW_TOPLEVEL)
93+
self.mainWindow.connect('destroy', self.OnExit)
94+
self.mainWindow.set_size_request(width=800, height=600)
95+
self.mainWindow.set_title('PyGTK CEF example')
96+
self.mainWindow.realize()
97+
98+
self.vbox = gtk.VBox(False, 0)
99+
self.vbox.pack_start(self.CreateMenu(), False, False, 0)
100+
self.mainWindow.add(self.vbox)
101+
102+
m = re.search("GtkVBox at 0x(\w+)", str(self.vbox))
103+
hexID = m.group(1)
104+
windowID = int(hexID, 16)
105+
106+
windowInfo = cefpython.WindowInfo()
107+
windowInfo.SetAsChild(windowID)
108+
# Linux requires adding "file://" for local files,
109+
# otherwise /home/some will be replaced as http://home/some
110+
self.browser = cefpython.CreateBrowserSync(
111+
windowInfo,
112+
browserSettings={},
113+
navigateUrl="file://"+GetApplicationPath("example.html"))
114+
115+
self.vbox.show()
116+
self.mainWindow.show()
117+
gobject.timeout_add(10, self.OnTimer)
118+
119+
def CreateMenu(self):
120+
file = gtk.MenuItem('File')
121+
file.show()
122+
filemenu = gtk.Menu()
123+
item = gtk.MenuItem('Open')
124+
filemenu.append(item)
125+
item.show()
126+
item = gtk.MenuItem('Exit')
127+
filemenu.append(item)
128+
item.show()
129+
file.set_submenu(filemenu)
130+
131+
about = gtk.MenuItem('About')
132+
about.show()
133+
aboutmenu = gtk.Menu()
134+
item = gtk.MenuItem('CEF Python')
135+
aboutmenu.append(item)
136+
item.show()
137+
about.set_submenu(aboutmenu)
138+
139+
menubar = gtk.MenuBar()
140+
menubar.append(file)
141+
menubar.append(about)
142+
menubar.show()
143+
144+
return menubar
145+
146+
def OnWidgetClick(self, widget, data):
147+
self.mainWindow.get_window().focus()
148+
149+
def OnTimer(self):
150+
if self.exiting:
151+
return False
152+
cefpython.MessageLoopWork()
153+
return True
154+
155+
def OnFocusIn(self, widget, data):
156+
# This function is currently not called by any of code,
157+
# but if you would like for browser to have automatic focus
158+
# add such line:
159+
# self.mainWindow.connect('focus-in-event', self.OnFocusIn)
160+
self.browser.SetFocus(True)
161+
162+
def OnExit(self, widget, data=None):
163+
self.exiting = True
164+
gtk.main_quit()
165+
166+
if __name__ == '__main__':
167+
version = '.'.join(map(str, list(gtk.gtk_version)))
168+
print('[pygtk_.py] GTK version: %s' % version)
169+
170+
# Intercept python exceptions. Exit app immediately when exception
171+
# happens on any of the threads.
172+
sys.excepthook = ExceptHook
173+
174+
# Application settings
175+
settings = {
176+
"debug": True, # cefpython debug messages in console and in log_file
177+
"log_severity": cefpython.LOGSEVERITY_INFO, # LOGSEVERITY_VERBOSE
178+
"log_file": GetApplicationPath("debug.log"), # Set to "" to disable
179+
"release_dcheck_enabled": True, # Enable only when debugging
180+
# This directories must be set on Linux
181+
"locales_dir_path": cefpython.GetModuleDirectory()+"/locales",
182+
"resources_dir_path": cefpython.GetModuleDirectory(),
183+
"browser_subprocess_path": "%s/%s" % (
184+
cefpython.GetModuleDirectory(), "subprocess"),
185+
}
186+
187+
cefpython.Initialize(settings)
188+
189+
gobject.threads_init() # Timer for the message loop
190+
PyGTKExample()
191+
gtk.main()
192+
193+
cefpython.Shutdown()

0 commit comments

Comments
 (0)