source: src/mlx/gui/cef.py@ 682:08e73d58a9e4

cef
Last change on this file since 682:08e73d58a9e4 was 682:08e73d58a9e4, checked in by István Váradi <ivaradi@…>, 7 years ago

CEF is now started from Selenium

File size: 7.9 KB
Line 
1from common import *
2
3from mlx.util import secondaryInstallation
4
5from cefpython3 import cefpython
6from selenium import webdriver
7from selenium.webdriver.chrome.options import Options
8
9import platform
10import json
11import time
12import os
13import re
14import threading
15import tempfile
16import traceback
17
18#------------------------------------------------------------------------------
19
20## @package mlx.gui.cef
21#
22# Some helper stuff related to the Chrome Embedded Framework
23
24#------------------------------------------------------------------------------
25
26# Indicate if we should quit
27_toQuit = False
28
29# The Selenium thread
30_seleniumHandler = None
31
32#------------------------------------------------------------------------------
33
34def getArgsFilePath():
35 """Get the path of the argument file."""
36 if os.name=="nt":
37 return os.path.join(tempfile.gettempdir(),
38 "mlxcef.args" +
39 (".secondary" if secondaryInstallation else ""))
40 else:
41 import pwd
42 return os.path.join(tempfile.gettempdir(),
43 "mlxcef." + pwd.getpwuid(os.getuid())[0] + ".args" +
44 (".secondary" if secondaryInstallation else ""))
45
46#------------------------------------------------------------------------------
47
48class ArgsFileWaiter(threading.Thread):
49 """A thread to wait for the appearance of the arguments file."""
50 def __init__(self, initializedCallback):
51 """Construct the thread."""
52 threading.Thread.__init__(self)
53 self.daemon = True
54
55 self._initializedCallback = initializedCallback
56
57 def run(self):
58 """Repeatedly check for the existence of the arguments file.
59
60 If it is found, read it, extract the arguments and insert a job into
61 the GUI loop to perform the actual initialization of CEF."""
62 argsFilePath = getArgsFilePath()
63 print "Waiting for the arguments file '%s' to appear" % (argsFilePath,)
64
65 while not os.path.exists(argsFilePath):
66 time.sleep(0.1)
67
68 print "Got arguments, reading them."""
69
70 with open(argsFilePath, "rt") as f:
71 args = f.read().split()
72
73 gobject.idle_add(_initializeCEF, args, self._initializedCallback)
74
75#------------------------------------------------------------------------------
76
77class SeleniumHandler(threading.Thread):
78 """Thread to handle Selenium operations."""
79 def __init__(self, programDirectory):
80 """Construct the thread."""
81 threading.Thread.__init__(self)
82 self.daemon = False
83
84 self._programDirectory = programDirectory
85
86 self._commandsCondition = threading.Condition()
87 self._commands = []
88
89 self._toQuit = False
90
91 def run(self):
92 """Create the Selenium driver and the perform any operations
93 requested."""
94 scriptName = "mlx_cef_caller"
95 if secondaryInstallation:
96 scriptName += "_secondary"
97 scriptName += ".bat" if os.name=="nt" else ".sh"
98
99 scriptPath = os.path.join(self._programDirectory, scriptName)
100 print "Creating the Selenium driver to call script", scriptPath
101
102 options = Options()
103 options.binary_location = scriptPath
104 driver = webdriver.Chrome(chrome_options = options)
105 # try:
106 # except:
107 # traceback.print_exc()
108
109 print "Created Selenium driver."
110 while not self._toQuit:
111 with self._commandsCondition:
112 while not self._commands:
113 self._commandsCondition.wait()
114
115 command = self._commands[0]
116 del self._commands[0]
117
118 command()
119
120 driver.quit()
121
122 def quit(self):
123 """Instruct the thread to quit and then join it."""
124 self._enqueue(self._quit)
125 self.join()
126
127 def _enqueue(self, command):
128 """Enqueue the given command.
129
130 command should be a function to be executed in the thread."""
131 with self._commandsCondition:
132 self._commands.append(command)
133 self._commandsCondition.notify()
134
135 def _quit(self):
136 """Set the _toQuit member variable to indicate that the thread should
137 quit."""
138 self._toQuit = True
139
140#------------------------------------------------------------------------------
141
142def initialize(programDirectory, initializedCallback):
143 """Initialize the Chrome Embedded Framework."""
144 global _toQuit, _seleniumHandler
145 _toQuit = False
146
147 gobject.threads_init()
148
149 argsFilePath = getArgsFilePath()
150 try:
151 os.unlink(argsFilePath)
152 except:
153 pass
154
155 _seleniumHandler = SeleniumHandler(programDirectory)
156 _seleniumHandler.start()
157
158 ArgsFileWaiter(initializedCallback).start()
159
160#------------------------------------------------------------------------------
161
162def _initializeCEF(args, initializedCallback):
163 """Perform the actual initialization of CEF using the given arguments."""
164 print "Initializing CEF with args:", args
165
166 settings = {
167 "debug": True, # cefpython debug messages in console and in log_file
168 "log_severity": cefpython.LOGSEVERITY_VERBOSE, # LOGSEVERITY_VERBOSE
169 "log_file": "", # Set to "" to disable
170 "release_dcheck_enabled": True, # Enable only when debugging
171 # This directories must be set on Linux
172 "locales_dir_path": os.path.join(cefpython.GetModuleDirectory(), "locales"),
173 "resources_dir_path": cefpython.GetModuleDirectory(),
174 "browser_subprocess_path": "%s/%s" % \
175 (cefpython.GetModuleDirectory(), "subprocess"),
176 }
177
178 switches={}
179 for arg in args:
180 if arg.startswith("--"):
181 if arg != "--enable-logging":
182 assignIndex = arg.find("=")
183 if assignIndex<0:
184 switches[arg[2:]] = ""
185 else:
186 switches[arg[2:assignIndex]] = arg[assignIndex+1:]
187 else:
188 print "Unhandled switch", arg
189
190 cefpython.Initialize(settings, switches)
191
192 gobject.timeout_add(10, _handleTimeout)
193
194 print "Initialized, executing callback..."
195 initializedCallback()
196
197#------------------------------------------------------------------------------
198
199def getContainer():
200 """Get a container object suitable for running a browser instance
201 within."""
202 if os.name=="nt":
203 container = gtk.DrawingArea()
204 container.set_property("can-focus", True)
205 container.connect("size-allocate", _handleSizeAllocate)
206 else:
207 container = gtk.VBox(True, 0)
208
209 container.show()
210
211 return container
212
213#------------------------------------------------------------------------------
214
215def startInContainer(container, url, browserSettings = {}):
216 """Start a browser instance in the given container with the given URL."""
217 if os.name=="nt":
218 windowID = container.get_window().handle
219 else:
220 m = re.search("GtkVBox at 0x(\w+)", str(container))
221 hexID = m.group(1)
222 windowID = int(hexID, 16)
223
224 windowInfo = cefpython.WindowInfo()
225 windowInfo.SetAsChild(windowID)
226
227 return cefpython.CreateBrowserSync(windowInfo,
228 browserSettings = browserSettings,
229 navigateUrl = url)
230
231#------------------------------------------------------------------------------
232
233def finalize():
234 """Finalize the Chrome Embedded Framework."""
235 global _toQuit, _seleniumHandler
236 toQuit = True
237 _seleniumHandler.quit()
238 cefpython.Shutdown()
239
240#------------------------------------------------------------------------------
241
242def _handleTimeout():
243 """Handle the timeout by running the CEF message loop."""
244 if _toQuit:
245 return False
246 else:
247 cefpython.MessageLoopWork()
248 return True
249
250#------------------------------------------------------------------------------
251
252def _handleSizeAllocate(widget, sizeAlloc):
253 """Handle the size-allocate event."""
254 cefpython.WindowUtils.OnSize(widget.get_window().handle, 0, 0, 0)
Note: See TracBrowser for help on using the repository browser.