From f391d726c07eb55f1a38f5ce6c51344d0ab43722 Mon Sep 17 00:00:00 2001 From: Jordyn/The Linux Geek Date: Wed, 18 Apr 2018 15:42:15 -0500 Subject: [PATCH 01/19] Add per-domain user stylesheet support --- qutebrowser/browser/shared.py | 4 ++-- qutebrowser/browser/webengine/webenginetab.py | 14 +++++++++----- qutebrowser/config/configdata.yml | 1 + 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/qutebrowser/browser/shared.py b/qutebrowser/browser/shared.py index 8ebbe3926..3876fec6a 100644 --- a/qutebrowser/browser/shared.py +++ b/qutebrowser/browser/shared.py @@ -273,10 +273,10 @@ def get_tab(win_id, target): return tabbed_browser.tabopen(url=None, background=bg_tab) -def get_user_stylesheet(): +def get_user_stylesheet(url=None): """Get the combined user-stylesheet.""" css = '' - stylesheets = config.val.content.user_stylesheets + stylesheets = config.instance.get("content.user_stylesheets", url) for filename in stylesheets: with open(filename, 'r', encoding='utf-8') as f: diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index fdfbc5fb0..5f0952bca 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -18,7 +18,6 @@ # along with qutebrowser. If not, see . """Wrapper over a QWebEngineView.""" - import math import functools import sys @@ -796,11 +795,12 @@ class _WebEngineScripts(QObject): def _on_config_changed(self, option): if option in ['scrolling.bar', 'content.user_stylesheets']: self._init_stylesheet() - self._update_stylesheet() + url = self.url(requested=True) + self._update_stylesheet(url=url) - def _update_stylesheet(self): + def _update_stylesheet(self, url=None): """Update the custom stylesheet in existing tabs.""" - css = shared.get_user_stylesheet() + css = shared.get_user_stylesheet(url=url) code = javascript.assemble('stylesheet', 'set_css', css) self._tab.run_js_async(code) @@ -863,8 +863,9 @@ class _WebEngineScripts(QObject): Partially inspired by QupZilla: https://github.com/QupZilla/qupzilla/blob/v2.0/src/lib/app/mainapplication.cpp#L1063-L1101 """ + self._remove_early_js('stylesheet') - css = shared.get_user_stylesheet() + css = shared.get_user_stylesheet(url=None) js_code = javascript.wrap_global( 'stylesheet', utils.read_file('javascript/stylesheet.js'), @@ -1225,6 +1226,9 @@ class WebEngineTab(browsertab.AbstractTab): # the old icon is still displayed. self.icon_changed.emit(QIcon()) + url = self.url(requested=True) + self._update_stylesheet(url) + @pyqtSlot(QUrl) def _on_predicted_navigation(self, url): """If we know we're going to visit an URL soon, change the settings. diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 49e037538..c83e0d253 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -689,6 +689,7 @@ content.user_stylesheets: valtype: File none_ok: True default: [] + supports_pattern: true desc: List of user stylesheet filenames to use. content.webgl: From b04934c2b32ba05c09df389fed6ba1b4131062fa Mon Sep 17 00:00:00 2001 From: Jordyn/The Linux Geek Date: Fri, 20 Apr 2018 00:27:59 -0500 Subject: [PATCH 02/19] Try to fix intermittent per-domain stylesheets --- qutebrowser/browser/browsertab.py | 3 +++ qutebrowser/browser/webengine/webenginetab.py | 5 +---- qutebrowser/utils/javascript.py | 18 ++++++++++++++++-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py index 7e78b2621..0b1c8d8da 100644 --- a/qutebrowser/browser/browsertab.py +++ b/qutebrowser/browser/browsertab.py @@ -812,6 +812,9 @@ class AbstractTab(QWidget): self.title_changed.emit(url.toDisplayString()) self.url_changed.emit(url) + url = self.url(requested=True) + self._update_stylesheet(url) + @pyqtSlot() def _on_load_started(self): self._progress = 0 diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 5f0952bca..101ad3611 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -801,7 +801,7 @@ class _WebEngineScripts(QObject): def _update_stylesheet(self, url=None): """Update the custom stylesheet in existing tabs.""" css = shared.get_user_stylesheet(url=url) - code = javascript.assemble('stylesheet', 'set_css', css) + code = javascript.assemble('stylesheet', 'set_css', css, delay=True) self._tab.run_js_async(code) def _inject_early_js(self, name, js_code, *, @@ -1226,9 +1226,6 @@ class WebEngineTab(browsertab.AbstractTab): # the old icon is still displayed. self.icon_changed.emit(QIcon()) - url = self.url(requested=True) - self._update_stylesheet(url) - @pyqtSlot(QUrl) def _on_predicted_navigation(self, url): """If we know we're going to visit an URL soon, change the settings. diff --git a/qutebrowser/utils/javascript.py b/qutebrowser/utils/javascript.py index 93df8e70f..e7053736c 100644 --- a/qutebrowser/utils/javascript.py +++ b/qutebrowser/utils/javascript.py @@ -64,14 +64,28 @@ def _convert_js_arg(arg): arg, type(arg).__name__)) -def assemble(module, function, *args): +def assemble(module, function, *args, delay=False): """Assemble a javascript file and a function call.""" js_args = ', '.join(_convert_js_arg(arg) for arg in args) if module == 'window': parts = ['window', function] else: parts = ['window', '_qutebrowser', module, function] - code = '"use strict";\n{}({});'.format('.'.join(parts), js_args) + if delay: + code = ''' + "use strict"; + if (document.readyState !== "loading") {{ + {parts}({args}); + }} else {{ + window.addEventListener("DOMContentLoaded", () => {{ + {parts}({args}); + }}); + }} + ''' + code = code.format(parts='.'.join(parts), args=js_args) + else: + code = '"use strict";\n{}({});'.format('.'.join(parts), js_args) + # print(code) return code From 92211caea462c41675093954e89a2191e2ea72ae Mon Sep 17 00:00:00 2001 From: Jordyn/The Linux Geek Date: Fri, 20 Apr 2018 00:29:48 -0500 Subject: [PATCH 03/19] Ignore blank URLs when applying per-domain stylesheets --- qutebrowser/browser/browsertab.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py index 0b1c8d8da..1e0d62c51 100644 --- a/qutebrowser/browser/browsertab.py +++ b/qutebrowser/browser/browsertab.py @@ -813,6 +813,12 @@ class AbstractTab(QWidget): self.url_changed.emit(url) url = self.url(requested=True) + + # Ignore blank QUrls to avoid crashes. + if not url.isValid(): + log.webview.debug("Not updating per-domain stylesheets due to the QUrl being blank") + return + self._update_stylesheet(url) @pyqtSlot() From 7141f9a2be12cedf780c47529920b0e497c97052 Mon Sep 17 00:00:00 2001 From: Jordyn/The Linux Geek Date: Thu, 3 May 2018 17:54:43 -0500 Subject: [PATCH 04/19] Revert "Try to fix intermittent per-domain stylesheets". This reverts commit 905c863598e7ce08c3e8641921a570fd54275901. --- qutebrowser/browser/webengine/webenginetab.py | 5 ++++- qutebrowser/utils/javascript.py | 18 ++---------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 101ad3611..5f0952bca 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -801,7 +801,7 @@ class _WebEngineScripts(QObject): def _update_stylesheet(self, url=None): """Update the custom stylesheet in existing tabs.""" css = shared.get_user_stylesheet(url=url) - code = javascript.assemble('stylesheet', 'set_css', css, delay=True) + code = javascript.assemble('stylesheet', 'set_css', css) self._tab.run_js_async(code) def _inject_early_js(self, name, js_code, *, @@ -1226,6 +1226,9 @@ class WebEngineTab(browsertab.AbstractTab): # the old icon is still displayed. self.icon_changed.emit(QIcon()) + url = self.url(requested=True) + self._update_stylesheet(url) + @pyqtSlot(QUrl) def _on_predicted_navigation(self, url): """If we know we're going to visit an URL soon, change the settings. diff --git a/qutebrowser/utils/javascript.py b/qutebrowser/utils/javascript.py index e7053736c..93df8e70f 100644 --- a/qutebrowser/utils/javascript.py +++ b/qutebrowser/utils/javascript.py @@ -64,28 +64,14 @@ def _convert_js_arg(arg): arg, type(arg).__name__)) -def assemble(module, function, *args, delay=False): +def assemble(module, function, *args): """Assemble a javascript file and a function call.""" js_args = ', '.join(_convert_js_arg(arg) for arg in args) if module == 'window': parts = ['window', function] else: parts = ['window', '_qutebrowser', module, function] - if delay: - code = ''' - "use strict"; - if (document.readyState !== "loading") {{ - {parts}({args}); - }} else {{ - window.addEventListener("DOMContentLoaded", () => {{ - {parts}({args}); - }}); - }} - ''' - code = code.format(parts='.'.join(parts), args=js_args) - else: - code = '"use strict";\n{}({});'.format('.'.join(parts), js_args) - # print(code) + code = '"use strict";\n{}({});'.format('.'.join(parts), js_args) return code From 394d91a11b373f31f7cae8ebce29b02e131ecdf1 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Wed, 13 Jun 2018 23:32:23 +0200 Subject: [PATCH 05/19] Adjust for _WebEngineScripts move --- qutebrowser/browser/browsertab.py | 9 -------- qutebrowser/browser/webengine/webenginetab.py | 23 +++++++++++++++---- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py index 1e0d62c51..7e78b2621 100644 --- a/qutebrowser/browser/browsertab.py +++ b/qutebrowser/browser/browsertab.py @@ -812,15 +812,6 @@ class AbstractTab(QWidget): self.title_changed.emit(url.toDisplayString()) self.url_changed.emit(url) - url = self.url(requested=True) - - # Ignore blank QUrls to avoid crashes. - if not url.isValid(): - log.webview.debug("Not updating per-domain stylesheets due to the QUrl being blank") - return - - self._update_stylesheet(url) - @pyqtSlot() def _on_load_started(self): self._progress = 0 diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 5f0952bca..05bc843b7 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -790,14 +790,32 @@ class _WebEngineScripts(QObject): def connect_signals(self): config.instance.changed.connect(self._on_config_changed) + self._tab.url_changed.connect(self._update_stylesheet) + self._tab.load_finished.connect(self._on_load_finished) @pyqtSlot(str) def _on_config_changed(self, option): if option in ['scrolling.bar', 'content.user_stylesheets']: self._init_stylesheet() - url = self.url(requested=True) + url = self._tab.url(requested=True) self._update_stylesheet(url=url) + @pyqtSlot() + def _on_url_changed(self): + requested_url = self._tab.url(requested=True) + + # Ignore blank QUrls to avoid crashes. + if not requested_url.isValid(): + log.webview.debug("Not updating per-domain stylesheets due to the QUrl being blank") + return + + self._update_stylesheet(requested_url) + + @pyqtSlot() + def _on_load_finished(self): + url = self._tab.url(requested=True) + self._update_stylesheet(url) + def _update_stylesheet(self, url=None): """Update the custom stylesheet in existing tabs.""" css = shared.get_user_stylesheet(url=url) @@ -1226,9 +1244,6 @@ class WebEngineTab(browsertab.AbstractTab): # the old icon is still displayed. self.icon_changed.emit(QIcon()) - url = self.url(requested=True) - self._update_stylesheet(url) - @pyqtSlot(QUrl) def _on_predicted_navigation(self, url): """If we know we're going to visit an URL soon, change the settings. From 651ed5247be474eb0dcd1018de1cb27ab6782d2a Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 14 Jun 2018 00:08:43 +0200 Subject: [PATCH 06/19] Don't use requested URLs --- qutebrowser/browser/webengine/webenginetab.py | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 05bc843b7..4b9665396 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -797,25 +797,14 @@ class _WebEngineScripts(QObject): def _on_config_changed(self, option): if option in ['scrolling.bar', 'content.user_stylesheets']: self._init_stylesheet() - url = self._tab.url(requested=True) - self._update_stylesheet(url=url) - - @pyqtSlot() - def _on_url_changed(self): - requested_url = self._tab.url(requested=True) - - # Ignore blank QUrls to avoid crashes. - if not requested_url.isValid(): - log.webview.debug("Not updating per-domain stylesheets due to the QUrl being blank") - return - - self._update_stylesheet(requested_url) + self._update_stylesheet(url=self._tab.url()) @pyqtSlot() def _on_load_finished(self): - url = self._tab.url(requested=True) + url = self._tab.url() self._update_stylesheet(url) + @pyqtSlot(QUrl) def _update_stylesheet(self, url=None): """Update the custom stylesheet in existing tabs.""" css = shared.get_user_stylesheet(url=url) From b6703d1189de13eb0f55333ef42cb769d121fd2b Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 14 Jun 2018 00:16:09 +0200 Subject: [PATCH 07/19] Avoid unnecessary CSS updates --- qutebrowser/javascript/stylesheet.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/qutebrowser/javascript/stylesheet.js b/qutebrowser/javascript/stylesheet.js index b1cdeb26e..daa51ca12 100644 --- a/qutebrowser/javascript/stylesheet.js +++ b/qutebrowser/javascript/stylesheet.js @@ -113,14 +113,19 @@ window._qutebrowser.stylesheet = (function() { if (!initialized) { init(); } + + if (css_content === css) { + return; + } + + css_content = css; + if (style_elem) { style_elem.textContent = css; // The browser seems to rewrite the document in same-origin frames // without notifying the mutation observer. Ensure that the // stylesheet is in the current document. watch_root(); - } else { - css_content = css; } // Propagate the new CSS to all child frames. // FIXME:qtwebengine This does not work for cross-origin frames. From 2c8ab580ceff75146d65607cb279808e22871f96 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 14 Jun 2018 12:01:57 +0200 Subject: [PATCH 08/19] Remove blank line --- qutebrowser/browser/webengine/webenginetab.py | 1 - 1 file changed, 1 deletion(-) diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 4b9665396..05fcdd1fb 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -870,7 +870,6 @@ class _WebEngineScripts(QObject): Partially inspired by QupZilla: https://github.com/QupZilla/qupzilla/blob/v2.0/src/lib/app/mainapplication.cpp#L1063-L1101 """ - self._remove_early_js('stylesheet') css = shared.get_user_stylesheet(url=None) js_code = javascript.wrap_global( From 1cf8011eb19fc22d03e91d22e3523d647b1294fc Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 14 Jun 2018 12:04:35 +0200 Subject: [PATCH 09/19] Remove unnecessary _init_stylesheet call The update calls were added in 51d48f6b00c5528b62a2c24ec7973b380c628965 but without removing the init_stylesheet call. --- qutebrowser/browser/webengine/webenginetab.py | 1 - 1 file changed, 1 deletion(-) diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 05fcdd1fb..614af6cc4 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -796,7 +796,6 @@ class _WebEngineScripts(QObject): @pyqtSlot(str) def _on_config_changed(self, option): if option in ['scrolling.bar', 'content.user_stylesheets']: - self._init_stylesheet() self._update_stylesheet(url=self._tab.url()) @pyqtSlot() From 18f4d1d546bcd8c6f1ee924b3d18048ba218bae6 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 14 Jun 2018 12:05:34 +0200 Subject: [PATCH 10/19] Make url mandatory for _update_stylesheet --- qutebrowser/browser/webengine/webenginetab.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 614af6cc4..71562a7b6 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -804,7 +804,7 @@ class _WebEngineScripts(QObject): self._update_stylesheet(url) @pyqtSlot(QUrl) - def _update_stylesheet(self, url=None): + def _update_stylesheet(self, url): """Update the custom stylesheet in existing tabs.""" css = shared.get_user_stylesheet(url=url) code = javascript.assemble('stylesheet', 'set_css', css) From 4f665784f2dce1393ab419e2b40056eee121723d Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 14 Jun 2018 13:24:06 +0200 Subject: [PATCH 11/19] Make it possible to call config.get with fallback=False --- qutebrowser/config/config.py | 25 ++++++++++++++++++++----- tests/unit/config/test_config.py | 12 ++++++++++++ 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/qutebrowser/config/config.py b/qutebrowser/config/config.py index d173eb1e0..1c8ce9f0a 100644 --- a/qutebrowser/config/config.py +++ b/qutebrowser/config/config.py @@ -311,10 +311,19 @@ class Config(QObject): name, deleted=deleted, renamed=renamed) raise exception from None - def get(self, name, url=None): - """Get the given setting converted for Python code.""" + def get(self, name, url=None, *, fallback=True): + """Get the given setting converted for Python code. + + Args: + name: The name of the setting to get. + url: The QUrl to get the setting for. + fallback: If False, return configutils.UNSET when there's no + override for this domain. + """ opt = self.get_opt(name) - obj = self.get_obj(name, url=url) + obj = self.get_obj(name, url=url, fallback=fallback) + if obj is configutils.UNSET: + return obj return opt.typ.to_py(obj) def _maybe_copy(self, value): @@ -328,14 +337,20 @@ class Config(QObject): assert value.__hash__ is not None, value return value - def get_obj(self, name, *, url=None): + def get_obj(self, name, *, url=None, fallback=True): """Get the given setting as object (for YAML/config.py). Note that the returned values are not watched for mutation. If a URL is given, return the value which should be used for that URL. + + Args: + name: The name of the setting to get. + url: The QUrl to get the setting for. + fallback: If False, return configutils.UNSET when there's no + override for this domain. """ self.get_opt(name) # To make sure it exists - value = self._values[name].get_for_url(url) + value = self._values[name].get_for_url(url, fallback=fallback) return self._maybe_copy(value) def get_obj_for_pattern(self, name, *, pattern): diff --git a/tests/unit/config/test_config.py b/tests/unit/config/test_config.py index e1ef7ef94..ba0658810 100644 --- a/tests/unit/config/test_config.py +++ b/tests/unit/config/test_config.py @@ -480,6 +480,18 @@ class TestConfig: conf.set_obj(name, False, pattern=pattern) assert conf.get(name, url=QUrl('https://example.com/')) is False + @pytest.mark.parametrize('fallback', [True, False]) + def test_get_for_url_unset(self, conf, fallback): + """Test config.get() with falling back to a global object.""" + name = 'content.javascript.enabled' + conf.set_obj(name, False) + val = conf.get(name, + url=QUrl('https://example.com/'), + fallback=fallback) + + expected = False if fallback else configutils.UNSET + assert val == expected + @pytest.mark.parametrize('value', [{}, {'normal': {'a': 'nop'}}]) def test_get_bindings(self, config_stub, conf, value): """Test conf.get() with bindings which have missing keys.""" From 6a00877a71b5ba306e5d1b5058f9d5c337e1decc Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 14 Jun 2018 13:24:50 +0200 Subject: [PATCH 12/19] Only update stylesheet if it's overridden per-domain --- qutebrowser/browser/shared.py | 13 +++++++++--- qutebrowser/browser/webengine/webenginetab.py | 21 +++++++++++++------ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/qutebrowser/browser/shared.py b/qutebrowser/browser/shared.py index 3876fec6a..1ccef1b7e 100644 --- a/qutebrowser/browser/shared.py +++ b/qutebrowser/browser/shared.py @@ -25,7 +25,7 @@ import netrc from PyQt5.QtCore import QUrl -from qutebrowser.config import config +from qutebrowser.config import config, configutils from qutebrowser.utils import usertypes, message, log, objreg, jinja, utils from qutebrowser.mainwindow import mainwindow @@ -274,9 +274,16 @@ def get_tab(win_id, target): def get_user_stylesheet(url=None): - """Get the combined user-stylesheet.""" + """Get the combined user-stylesheet. + + If `url` is given and there's no overridden stylesheet, return + `configutils.UNSET`. + """ css = '' - stylesheets = config.instance.get("content.user_stylesheets", url) + stylesheets = config.instance.get("content.user_stylesheets", url, + fallback=url is None) + if stylesheets is configutils.UNSET: + return stylesheets for filename in stylesheets: with open(filename, 'r', encoding='utf-8') as f: diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 71562a7b6..4c8f2a29e 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -32,7 +32,7 @@ from PyQt5.QtNetwork import QAuthenticator from PyQt5.QtWidgets import QApplication from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineScript -from qutebrowser.config import configdata, config +from qutebrowser.config import configdata, config, configutils from qutebrowser.browser import browsertab, mouse, shared from qutebrowser.browser.webengine import (webview, webengineelem, tabhistory, interceptor, webenginequtescheme, @@ -796,7 +796,7 @@ class _WebEngineScripts(QObject): @pyqtSlot(str) def _on_config_changed(self, option): if option in ['scrolling.bar', 'content.user_stylesheets']: - self._update_stylesheet(url=self._tab.url()) + self._update_stylesheet(url=self._tab.url(), force=True) @pyqtSlot() def _on_load_finished(self): @@ -804,11 +804,20 @@ class _WebEngineScripts(QObject): self._update_stylesheet(url) @pyqtSlot(QUrl) - def _update_stylesheet(self, url): - """Update the custom stylesheet in existing tabs.""" + def _update_stylesheet(self, url, force=False): + """Update the custom stylesheet in existing tabs. + + Arguments: + url: The url to get the stylesheet for. + force: Also update the global stylesheet. + """ css = shared.get_user_stylesheet(url=url) - code = javascript.assemble('stylesheet', 'set_css', css) - self._tab.run_js_async(code) + if css is configutils.UNSET and force: + css = shared.get_user_stylesheet(url=None) + + if css is not configutils.UNSET: + code = javascript.assemble('stylesheet', 'set_css', css) + self._tab.run_js_async(code) def _inject_early_js(self, name, js_code, *, world=QWebEngineScript.ApplicationWorld, From 0d4173d31bc107cb6d2495db7eecdb4b3fcad643 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 14 Jun 2018 13:37:31 +0200 Subject: [PATCH 13/19] Use single quotes --- qutebrowser/browser/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qutebrowser/browser/shared.py b/qutebrowser/browser/shared.py index 1ccef1b7e..8e9ab8772 100644 --- a/qutebrowser/browser/shared.py +++ b/qutebrowser/browser/shared.py @@ -280,7 +280,7 @@ def get_user_stylesheet(url=None): `configutils.UNSET`. """ css = '' - stylesheets = config.instance.get("content.user_stylesheets", url, + stylesheets = config.instance.get('content.user_stylesheets', url, fallback=url is None) if stylesheets is configutils.UNSET: return stylesheets From fbbb290e164f747b5f9c432b019b748a84cd95c0 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 14 Jun 2018 13:43:57 +0200 Subject: [PATCH 14/19] Re-add blank line --- qutebrowser/browser/webengine/webenginetab.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 4c8f2a29e..3bcb2950f 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -18,6 +18,7 @@ # along with qutebrowser. If not, see . """Wrapper over a QWebEngineView.""" + import math import functools import sys From 4af58d39ed827b3cb8022684448e9f8da9933f39 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 14 Jun 2018 14:06:00 +0200 Subject: [PATCH 15/19] Move webkitsettings to WebKitSettings object --- qutebrowser/browser/webkit/webkitsettings.py | 84 +++++++++++--------- 1 file changed, 48 insertions(+), 36 deletions(-) diff --git a/qutebrowser/browser/webkit/webkitsettings.py b/qutebrowser/browser/webkit/webkitsettings.py index cce1dcec0..612f0bd0c 100644 --- a/qutebrowser/browser/webkit/webkitsettings.py +++ b/qutebrowser/browser/webkit/webkitsettings.py @@ -120,43 +120,61 @@ class WebKitSettings(websettings.AbstractSettings): QWebSettings.FantasyFont: QFont.Fantasy, } + def _set_user_stylesheet(self): + """Set the generated user-stylesheet.""" + stylesheet = shared.get_user_stylesheet().encode('utf-8') + url = urlutils.data_url('text/css;charset=utf-8', stylesheet) + old = self._settings.userStyleSheetUrl() -def _set_user_stylesheet(settings): - """Set the generated user-stylesheet.""" - stylesheet = shared.get_user_stylesheet().encode('utf-8') - url = urlutils.data_url('text/css;charset=utf-8', stylesheet) - settings.setUserStyleSheetUrl(url) + if old == url: + return False + self._settings.setUserStyleSheetUrl(url) + return True -def _set_cookie_accept_policy(settings): - """Update the content.cookies.accept setting.""" - mapping = { - 'all': QWebSettings.AlwaysAllowThirdPartyCookies, - 'no-3rdparty': QWebSettings.AlwaysBlockThirdPartyCookies, - 'never': QWebSettings.AlwaysBlockThirdPartyCookies, - 'no-unknown-3rdparty': QWebSettings.AllowThirdPartyWithExistingCookies, - } - value = config.val.content.cookies.accept - settings.setThirdPartyCookiePolicy(mapping[value]) + def _set_cookie_accept_policy(self, value): + """Update the content.cookies.accept setting.""" + mapping = { + 'all': QWebSettings.AlwaysAllowThirdPartyCookies, + 'no-3rdparty': QWebSettings.AlwaysBlockThirdPartyCookies, + 'never': QWebSettings.AlwaysBlockThirdPartyCookies, + 'no-unknown-3rdparty': QWebSettings.AllowThirdPartyWithExistingCookies, + } + old = self._settings.thirdPartyCookiePolicy() + new = mapping[value] -def _set_cache_maximum_pages(settings): - """Update the content.cache.maximum_pages setting.""" - value = config.val.content.cache.maximum_pages - settings.setMaximumPagesInCache(value) + if old == new: + return False + self._settings.setThirdPartyCookiePolicy(new) + return True -def _update_settings(option): - """Update global settings when qwebsettings changed.""" - global_settings.update_setting(option) + def _set_cache_maximum_pages(self, value): + """Update the content.cache.maximum_pages setting.""" + old = self._settings.maximumPagesInCache() - settings = QWebSettings.globalSettings() - if option in ['scrollbar.hide', 'content.user_stylesheets']: - _set_user_stylesheet(settings) - elif option == 'content.cookies.accept': - _set_cookie_accept_policy(settings) - elif option == 'content.cache.maximum_pages': - _set_cache_maximum_pages(settings) + if old == value: + return False + + self._settings.setMaximumPagesInCache(value) + return True + + def _update_setting(self, option, value): + if option in ['scrollbar.hide', 'content.user_stylesheets']: + return self._set_user_stylesheet() + elif option == 'content.cookies.accept': + return self._set_cookie_accept_policy(value) + elif option == 'content.cache.maximum_pages': + return self._set_cache_maximum_pages(value) + else: + return super()._update_setting(option, value) + + def init_settings(self): + super().init_settings() + self.update_setting('content.user_stylesheets') + self.update_setting('content.cookies.accept') + self.update_setting('content.cache.maximum_pages') def init(_args): @@ -172,16 +190,10 @@ def init(_args): QWebSettings.setOfflineStoragePath( os.path.join(data_path, 'offline-storage')) - settings = QWebSettings.globalSettings() - _set_user_stylesheet(settings) - _set_cookie_accept_policy(settings) - _set_cache_maximum_pages(settings) - - config.instance.changed.connect(_update_settings) - global global_settings global_settings = WebKitSettings(QWebSettings.globalSettings()) global_settings.init_settings() + config.instance.changed.connect(global_settings.update_setting) def shutdown(): From 39976f543be625c04aa45d3414c7691ceada2522 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 14 Jun 2018 14:22:16 +0200 Subject: [PATCH 16/19] Partially revert moving webkit settings --- qutebrowser/browser/webkit/webkitsettings.py | 44 ++++++-------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/qutebrowser/browser/webkit/webkitsettings.py b/qutebrowser/browser/webkit/webkitsettings.py index 612f0bd0c..3ed9fdf46 100644 --- a/qutebrowser/browser/webkit/webkitsettings.py +++ b/qutebrowser/browser/webkit/webkitsettings.py @@ -124,15 +124,9 @@ class WebKitSettings(websettings.AbstractSettings): """Set the generated user-stylesheet.""" stylesheet = shared.get_user_stylesheet().encode('utf-8') url = urlutils.data_url('text/css;charset=utf-8', stylesheet) - old = self._settings.userStyleSheetUrl() - - if old == url: - return False - self._settings.setUserStyleSheetUrl(url) - return True - def _set_cookie_accept_policy(self, value): + def _set_cookie_accept_policy(self): """Update the content.cookies.accept setting.""" mapping = { 'all': QWebSettings.AlwaysAllowThirdPartyCookies, @@ -140,41 +134,29 @@ class WebKitSettings(websettings.AbstractSettings): 'never': QWebSettings.AlwaysBlockThirdPartyCookies, 'no-unknown-3rdparty': QWebSettings.AllowThirdPartyWithExistingCookies, } + value = config.val.content.cookies.accept + self._settings.setThirdPartyCookiePolicy(mapping[value]) - old = self._settings.thirdPartyCookiePolicy() - new = mapping[value] - - if old == new: - return False - - self._settings.setThirdPartyCookiePolicy(new) - return True - - def _set_cache_maximum_pages(self, value): + def _set_cache_maximum_pages(self): """Update the content.cache.maximum_pages setting.""" - old = self._settings.maximumPagesInCache() - - if old == value: - return False - + value = config.val.content.cache.maximum_pages self._settings.setMaximumPagesInCache(value) - return True - def _update_setting(self, option, value): + def update_setting(self, option): if option in ['scrollbar.hide', 'content.user_stylesheets']: - return self._set_user_stylesheet() + self._set_user_stylesheet() elif option == 'content.cookies.accept': - return self._set_cookie_accept_policy(value) + self._set_cookie_accept_policy() elif option == 'content.cache.maximum_pages': - return self._set_cache_maximum_pages(value) + self._set_cache_maximum_pages() else: - return super()._update_setting(option, value) + super().update_setting(option) def init_settings(self): super().init_settings() - self.update_setting('content.user_stylesheets') - self.update_setting('content.cookies.accept') - self.update_setting('content.cache.maximum_pages') + self._set_user_stylesheet() + self._set_cookie_accept_policy() + self._set_cache_maximum_pages() def init(_args): From fc95fdd59327dfa8de270172e9686217923a7450 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 14 Jun 2018 14:28:07 +0200 Subject: [PATCH 17/19] Update QtWebKit user stylesheets when URL changes --- qutebrowser/browser/webkit/webkitsettings.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/qutebrowser/browser/webkit/webkitsettings.py b/qutebrowser/browser/webkit/webkitsettings.py index 3ed9fdf46..187cb4eab 100644 --- a/qutebrowser/browser/webkit/webkitsettings.py +++ b/qutebrowser/browser/webkit/webkitsettings.py @@ -29,7 +29,7 @@ import os.path from PyQt5.QtGui import QFont from PyQt5.QtWebKit import QWebSettings -from qutebrowser.config import config, websettings +from qutebrowser.config import config, websettings, configutils from qutebrowser.config.websettings import AttributeInfo as Attr from qutebrowser.utils import standarddir, urlutils from qutebrowser.browser import shared @@ -120,10 +120,13 @@ class WebKitSettings(websettings.AbstractSettings): QWebSettings.FantasyFont: QFont.Fantasy, } - def _set_user_stylesheet(self): + def _set_user_stylesheet(self, url=None): """Set the generated user-stylesheet.""" - stylesheet = shared.get_user_stylesheet().encode('utf-8') - url = urlutils.data_url('text/css;charset=utf-8', stylesheet) + stylesheet = shared.get_user_stylesheet(url=url) + if stylesheet is configutils.UNSET: + return + url = urlutils.data_url('text/css;charset=utf-8', + stylesheet.encode('utf-8')) self._settings.setUserStyleSheetUrl(url) def _set_cookie_accept_policy(self): @@ -152,6 +155,10 @@ class WebKitSettings(websettings.AbstractSettings): else: super().update_setting(option) + def update_for_url(self, url): + super().update_for_url(url) + self._set_user_stylesheet(url) + def init_settings(self): super().init_settings() self._set_user_stylesheet() From 8b38e0b900e77f120d2f26f5bf2652f45565041a Mon Sep 17 00:00:00 2001 From: Jay Kamat Date: Sun, 14 Oct 2018 16:09:50 -0700 Subject: [PATCH 18/19] Fix scrolling.bar setting after merge --- qutebrowser/browser/shared.py | 16 ++++++++++------ qutebrowser/browser/webengine/webenginetab.py | 16 +++++++++------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/qutebrowser/browser/shared.py b/qutebrowser/browser/shared.py index 7447fae59..bfcf81e85 100644 --- a/qutebrowser/browser/shared.py +++ b/qutebrowser/browser/shared.py @@ -274,6 +274,14 @@ def get_tab(win_id, target): return tabbed_browser.tabopen(url=None, background=bg_tab) +def _wrap_bar(css: str, searching: bool): + """Wrap the passed css in a bar if needed, depending on settings.""" + if css is not configutils.UNSET and \ + (config.val.scrolling.bar == 'never' or + config.val.scrolling.bar == 'when-searching' and not searching): + css += '\nhtml > ::-webkit-scrollbar { width: 0px; height: 0px; }' + return css + def get_user_stylesheet(searching=False, url=None): """Get the combined user-stylesheet. @@ -284,17 +292,13 @@ def get_user_stylesheet(searching=False, url=None): stylesheets = config.instance.get('content.user_stylesheets', url, fallback=url is None) if stylesheets is configutils.UNSET: - return stylesheets + return _wrap_bar(stylesheets, searching) for filename in stylesheets: with open(filename, 'r', encoding='utf-8') as f: css += f.read() - if (config.val.scrolling.bar == 'never' or - config.val.scrolling.bar == 'when-searching' and not searching): - css += '\nhtml > ::-webkit-scrollbar { width: 0px; height: 0px; }' - - return css + return _wrap_bar(css, searching) def netrc_authentication(url, authenticator): diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 64dd200fd..8ec0004ff 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -855,19 +855,21 @@ class _WebEngineScripts(QObject): self._tab.url_changed.connect(self._update_stylesheet) self._tab.load_finished.connect(self._on_load_finished) - self._tab.search.cleared.connect(functools.partial( - self._update_stylesheet, searching=False)) - self._tab.search.finished.connect(self._on_load_finished) + self._tab.search.cleared.connect( + lambda: self._update_stylesheet(self._tab.url(), searching=False, force=True)) + self._tab.search.finished.connect( + lambda found: self._update_stylesheet(self._tab.url(), searching=found, force=True)) @pyqtSlot(str) def _on_config_changed(self, option): if option in ['scrolling.bar', 'content.user_stylesheets']: - self._update_stylesheet(url=self._tab.url(), force=True) + self._init_stylesheet() + self._update_stylesheet(self._tab.url(), force=True) @pyqtSlot() - def _on_load_finished(self): + def _on_load_finished(self, searching=False): url = self._tab.url() - self._update_stylesheet(url) + self._update_stylesheet(url, searching=searching) @pyqtSlot(QUrl) def _update_stylesheet(self, url, searching=False, force=False): @@ -879,7 +881,7 @@ class _WebEngineScripts(QObject): """ css = shared.get_user_stylesheet(searching=searching, url=url) if css is configutils.UNSET and force: - css = shared.get_user_stylesheet(url=None) + css = shared.get_user_stylesheet(searching=searching, url=None) if css is not configutils.UNSET: code = javascript.assemble('stylesheet', 'set_css', css) From 5a77119ab85290f39132ffe14ed05831dc0c91c8 Mon Sep 17 00:00:00 2001 From: Jay Kamat Date: Fri, 22 Feb 2019 22:25:30 -0800 Subject: [PATCH 19/19] Fix crash when getting an invalid url from url_changed --- qutebrowser/browser/webengine/webenginetab.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 145b6d67d..8577a395f 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -890,6 +890,9 @@ class _WebEngineScripts(QObject): url: The url to get the stylesheet for. force: Also update the global stylesheet. """ + if not url.isValid(): + # FIXME should we be dropping this request completely? + url = None css = shared.get_user_stylesheet(searching=searching, url=url) if css is configutils.UNSET and force: css = shared.get_user_stylesheet(searching=searching, url=None)