From 5e50824042b5a60c47ef3f70aaf2f7d5b1456967 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 15 Feb 2018 22:54:22 +0100 Subject: [PATCH] Broken per-URL proof-of-concept --- .../browser/webengine/webenginesettings.py | 4 ++ qutebrowser/browser/webengine/webenginetab.py | 3 + qutebrowser/browser/webkit/webkitsettings.py | 4 ++ qutebrowser/browser/webkit/webkittab.py | 3 + qutebrowser/config/config.py | 56 ++++++++++++++++++- qutebrowser/config/websettings.py | 7 ++- 6 files changed, 71 insertions(+), 6 deletions(-) diff --git a/qutebrowser/browser/webengine/webenginesettings.py b/qutebrowser/browser/webengine/webenginesettings.py index 607499401..cf734d78b 100644 --- a/qutebrowser/browser/webengine/webenginesettings.py +++ b/qutebrowser/browser/webengine/webenginesettings.py @@ -298,6 +298,10 @@ def init(args): config.instance.changed.connect(_update_settings) +def update_for_tab(tab, url): + websettings.update_mappings(MAPPINGS, option, url, tab.settings()) + + def shutdown(): # FIXME:qtwebengine do we need to do something for a clean shutdown here? pass diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index ed6697f03..197fa03bd 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -906,5 +906,8 @@ class WebEngineTab(browsertab.AbstractTab): page.loadFinished.connect(self._restore_zoom) page.loadFinished.connect(self._on_load_finished) + self.on_url_changed.connect( + functools.partial(webenginesettings.update_for_tab, self)) + def event_target(self): return self._widget.focusProxy() diff --git a/qutebrowser/browser/webkit/webkitsettings.py b/qutebrowser/browser/webkit/webkitsettings.py index ee01c40db..4b51177bb 100644 --- a/qutebrowser/browser/webkit/webkitsettings.py +++ b/qutebrowser/browser/webkit/webkitsettings.py @@ -118,6 +118,10 @@ def _update_settings(option): websettings.update_mappings(MAPPINGS, option) +def update_for_tab(tab, url, option): + websettings.update_mappings(MAPPINGS, option, url, tab.settings()) + + def init(_args): """Initialize the global QWebSettings.""" cache_path = standarddir.cache() diff --git a/qutebrowser/browser/webkit/webkittab.py b/qutebrowser/browser/webkit/webkittab.py index 9395630db..414b0f16a 100644 --- a/qutebrowser/browser/webkit/webkittab.py +++ b/qutebrowser/browser/webkit/webkittab.py @@ -780,5 +780,8 @@ class WebKitTab(browsertab.AbstractTab): frame.contentsSizeChanged.connect(self._on_contents_size_changed) frame.initialLayoutCompleted.connect(self._on_history_trigger) + self.on_url_changed.connect( + functools.partial(webkitsettings.update_for_tab, self)) + def event_target(self): return self._widget diff --git a/qutebrowser/config/config.py b/qutebrowser/config/config.py index ec6a36176..af0fe28a7 100644 --- a/qutebrowser/config/config.py +++ b/qutebrowser/config/config.py @@ -38,6 +38,9 @@ key_instance = None # Keeping track of all change filters to validate them later. change_filters = [] +# Sentinel +UNSET = object() + class change_filter: # noqa: N801,N806 pylint: disable=invalid-name @@ -279,7 +282,7 @@ class Config(QObject): """ self._yaml.init_save_manager(save_manager) - def _get_values(self, pattern=None, create=False): + def _get_values(self, pattern=None, *, create=False): """Get the appropriate _values instance for the given pattern. With create=True, create a new one instead of returning an empty dict. @@ -295,6 +298,24 @@ class Config(QObject): else: return {} + def _get_values_for_url(self, url): + """Get a temporary values container which merges all matching values. + + Note that this does *not* include global values. + + Currently, this iterates linearly over all patterns. This could probably + be optimized by storing patterns based on their scheme/host/port and + then searching all possible matches in a dict before doing a full match. + """ + # FIXME We could avoid the copy if there's no per-url match. + # values = self._values.copy() + values = {} + # FIXME:conf what order? + for options in self._per_url_values.values(): + if options.pattern.matches(url): + values.update(options.values) + return values + def _set_value(self, opt, value, pattern=None): """Set the given option to the given value.""" if not isinstance(objects.backend, objects.NoBackend): @@ -327,10 +348,10 @@ class Config(QObject): name, deleted=deleted, renamed=renamed) raise exception from None - def get(self, name, pattern=None): + def get(self, name): """Get the given setting converted for Python code.""" opt = self.get_opt(name) - obj = self.get_obj(name, mutable=False, pattern=pattern) + obj = self.get_obj(name, mutable=False) return opt.typ.to_py(obj) def get_obj(self, name, *, mutable=True, pattern=None): @@ -351,6 +372,7 @@ class Config(QObject): # internal value can never be changed by mutating the object returned. else: values = self._get_values(pattern) + obj = copy.deepcopy(values.get(name, opt.default)) # Then we watch the returned object for changes. if isinstance(obj, (dict, list)): @@ -361,6 +383,34 @@ class Config(QObject): assert obj.__hash__ is not None, obj return obj + def get_for_url(self, name, url, *, maybe_unset=True): + """Get the given per-url setting converted for Python code. + + With maybe_unset=True, if the value isn't overridden for a given domain, + return UNSET. + + With maybe_unset=False, return the global/default value instead. + """ + opt = self.get_opt(name) + obj = self._get_obj_for_url(opt, url=url, maybe_unset=maybe_unset) + return opt.typ.to_py(obj) + + def _get_obj_for_url(self, opt, url, *, maybe_unset=True): + """Get the given setting as object (for YAML/config.py). + + With maybe_unset=True, if the value isn't overridden for a given domain, + return UNSET. + + With maybe_unset=False, return the global/default value instead. + """ + values = self._get_values_for_url(url) + if opt in values: + return values[opt] + elif maybe_unset: + return UNSET + else: + return self.get_obj(opt.name, mutable=False) + def get_str(self, name, *, pattern=None): """Get the given setting as string.""" opt = self.get_opt(name) diff --git a/qutebrowser/config/websettings.py b/qutebrowser/config/websettings.py index fa8abb76f..1d29c28a5 100644 --- a/qutebrowser/config/websettings.py +++ b/qutebrowser/config/websettings.py @@ -198,14 +198,15 @@ def init_mappings(mappings): mapping.set(value) -def update_mappings(mappings, option): +def update_mappings(mappings, option, url=None, settings=None): """Update global settings when QWeb(Engine)Settings changed.""" try: mapping = mappings[option] except KeyError: return - value = config.instance.get(option) - mapping.set(value) + value = config.instance.get(option, url=url) + # FIXME:conf handle settings != None with global/static setters + mapping.set(value, settings=settings) def init(args):