Greasemonkey: Add greasemonkey hooks for webengine.

For qtwebengine 5.8+ only. This is because as of 5.8 some greasemonkey
script support is in upstream. That is, qtwebenginescript(collection)
parses the greasemonkey metadata block and uses @include/match/exclude
to decide what sites to inject a script onto and @run-at to decide when
to inject it, which saves us the trouble. Notes on doing this in <5.8
are below.

Scripts are currently injected into the main "world", that is the same
world as the javascript from the page. This is good because it means
userscripts can modify more stuff on the page but it would be nice if we
could have more isolation without sacrificing functionality. I'm still
looking into why my more feature-full scripts are not having any effect
on the page while running in a separate world.

Userscripts are added to both the default and private profile because I
that if people have scripts installed they want them to run in private mode
too.

We are grabbing the scripts from the greasemonkey module, as opposed to
reading them directly from disk, because the module adds some GM_* functions
that the scripts may expect, and because that is used for webkit anyway.

I have code to support qtwebengine <5.8 but didn't because I am not
happy with the timing of some of the signals that we are provided
regarding page load state, and the actual load state. While the
difference between document-end and document-idle isn't so bad,
injecting document-start scripts when a urlChanged event is emitted
results in the script being injected into the environment for the page
being navigated away from. Anyway, if anyone wants this for earlier
webengines I can oblige them.
This commit is contained in:
Jimmy 2017-06-07 16:06:50 +12:00
parent be9f8bd0de
commit f26377351c

View File

@ -69,6 +69,10 @@ def init():
download_manager.install(webenginesettings.private_profile)
objreg.register('webengine-download-manager', download_manager)
greasemonkey = objreg.get('greasemonkey')
greasemonkey.scripts_reloaded.connect(inject_userscripts)
inject_userscripts()
# Mapping worlds from usertypes.JsWorld to QWebEngineScript world IDs.
_JS_WORLD_MAP = {
@ -79,6 +83,42 @@ _JS_WORLD_MAP = {
}
def inject_userscripts():
"""Register user javascript files with the global profiles."""
# The greasemonkey metadata block support in qtwebengine only starts at 5.8
# Otherwise have to handle injecting the scripts into the page at very
# early load, probs same place in view as the enableJS check.
if not qtutils.version_check('5.8'):
return
# Since we are inserting scripts into profile.scripts they won't
# just get replaced by new gm scripts like if we were injecting them
# ourselves so we need to remove all gm scripts, while not removing
# any other stuff that might have been added. Like the one for
# stylsheets.
# Could either use a different world for gm scripts, check for gm metadata
# values (would mean no non-gm userscripts), or check the code for
# _qute_script_id
for profile in [webenginesettings.default_profile,
webenginesettings.private_profile]:
scripts = profile.scripts()
for script in scripts.toList():
if script.worldId() == QWebEngineScript.MainWorld:
scripts.remove(script)
# Should we be adding to private profile too?
for profile in [webenginesettings.default_profile,
webenginesettings.private_profile]:
scripts = profile.scripts()
greasemonkey = objreg.get('greasemonkey')
for script in greasemonkey.all_scripts():
new_script = QWebEngineScript()
new_script.setWorldId(QWebEngineScript.MainWorld)
new_script.setSourceCode(script.code())
log.greasemonkey.debug('adding script: %s', new_script.name)
scripts.insert(new_script)
class WebEngineAction(browsertab.AbstractAction):
"""QtWebEngine implementations related to web actions."""