Implement private browsing for QtWebEngine
This commit is contained in:
parent
1c50377c0a
commit
f4d3f97cb7
@ -38,6 +38,12 @@ from qutebrowser.utils import (objreg, utils, standarddir, javascript, log,
|
|||||||
qtutils)
|
qtutils)
|
||||||
|
|
||||||
|
|
||||||
|
# The default QWebEngineProfile
|
||||||
|
default_profile = None
|
||||||
|
# The QWebEngineProfile used for private (off-the-record) windows
|
||||||
|
private_profile = None
|
||||||
|
|
||||||
|
|
||||||
class Attribute(websettings.Attribute):
|
class Attribute(websettings.Attribute):
|
||||||
|
|
||||||
"""A setting set via QWebEngineSettings::setAttribute."""
|
"""A setting set via QWebEngineSettings::setAttribute."""
|
||||||
@ -67,7 +73,7 @@ class StaticSetter(websettings.StaticSetter):
|
|||||||
GLOBAL_SETTINGS = QWebEngineSettings.globalSettings
|
GLOBAL_SETTINGS = QWebEngineSettings.globalSettings
|
||||||
|
|
||||||
|
|
||||||
class ProfileSetter(websettings.Base):
|
class DefaultProfileSetter(websettings.Base):
|
||||||
|
|
||||||
"""A setting set on the QWebEngineProfile."""
|
"""A setting set on the QWebEngineProfile."""
|
||||||
|
|
||||||
@ -78,16 +84,16 @@ class ProfileSetter(websettings.Base):
|
|||||||
|
|
||||||
def get(self, settings=None):
|
def get(self, settings=None):
|
||||||
utils.unused(settings)
|
utils.unused(settings)
|
||||||
getter = getattr(QWebEngineProfile.defaultProfile(), self._getter)
|
getter = getattr(default_profile, self._getter)
|
||||||
return getter()
|
return getter()
|
||||||
|
|
||||||
def _set(self, value, settings=None):
|
def _set(self, value, settings=None):
|
||||||
utils.unused(settings)
|
utils.unused(settings)
|
||||||
setter = getattr(QWebEngineProfile.defaultProfile(), self._setter)
|
setter = getattr(default_profile, self._setter)
|
||||||
setter(value)
|
setter(value)
|
||||||
|
|
||||||
|
|
||||||
class PersistentCookiePolicy(ProfileSetter):
|
class PersistentCookiePolicy(DefaultProfileSetter):
|
||||||
|
|
||||||
"""The cookies -> store setting is different from other settings."""
|
"""The cookies -> store setting is different from other settings."""
|
||||||
|
|
||||||
@ -141,19 +147,27 @@ def _init_stylesheet(profile):
|
|||||||
profile.scripts().insert(script)
|
profile.scripts().insert(script)
|
||||||
|
|
||||||
|
|
||||||
def _init_profile(profile):
|
|
||||||
"""Initialize settings set on the QWebEngineProfile."""
|
|
||||||
profile.setCachePath(os.path.join(standarddir.cache(), 'webengine'))
|
|
||||||
profile.setPersistentStoragePath(
|
|
||||||
os.path.join(standarddir.data(), 'webengine'))
|
|
||||||
|
|
||||||
|
|
||||||
def update_settings(section, option):
|
def update_settings(section, option):
|
||||||
"""Update global settings when qwebsettings changed."""
|
"""Update global settings when qwebsettings changed."""
|
||||||
websettings.update_mappings(MAPPINGS, section, option)
|
websettings.update_mappings(MAPPINGS, section, option)
|
||||||
profile = QWebEngineProfile.defaultProfile()
|
|
||||||
if section == 'ui' and option in ['hide-scrollbar', 'user-stylesheet']:
|
if section == 'ui' and option in ['hide-scrollbar', 'user-stylesheet']:
|
||||||
_init_stylesheet(profile)
|
_init_stylesheet(default_profile)
|
||||||
|
_init_stylesheet(private_profile)
|
||||||
|
|
||||||
|
|
||||||
|
def _init_profiles():
|
||||||
|
"""Init the two used QWebEngineProfiles"""
|
||||||
|
global default_profile, private_profile
|
||||||
|
default_profile = QWebEngineProfile.defaultProfile()
|
||||||
|
default_profile.setCachePath(
|
||||||
|
os.path.join(standarddir.cache(), 'webengine'))
|
||||||
|
default_profile.setPersistentStoragePath(
|
||||||
|
os.path.join(standarddir.data(), 'webengine'))
|
||||||
|
_init_stylesheet(default_profile)
|
||||||
|
|
||||||
|
private_profile = QWebEngineProfile()
|
||||||
|
assert private_profile.isOffTheRecord()
|
||||||
|
_init_stylesheet(private_profile)
|
||||||
|
|
||||||
|
|
||||||
def init(args):
|
def init(args):
|
||||||
@ -173,9 +187,7 @@ def init(args):
|
|||||||
else:
|
else:
|
||||||
log.misc.debug("Imported PyOpenGL as workaround")
|
log.misc.debug("Imported PyOpenGL as workaround")
|
||||||
|
|
||||||
profile = QWebEngineProfile.defaultProfile()
|
_init_profiles()
|
||||||
_init_profile(profile)
|
|
||||||
_init_stylesheet(profile)
|
|
||||||
# We need to do this here as a WORKAROUND for
|
# We need to do this here as a WORKAROUND for
|
||||||
# https://bugreports.qt.io/browse/QTBUG-58650
|
# https://bugreports.qt.io/browse/QTBUG-58650
|
||||||
if not qtutils.version_check('5.9'):
|
if not qtutils.version_check('5.9'):
|
||||||
@ -282,7 +294,7 @@ MAPPINGS = {
|
|||||||
'local-storage':
|
'local-storage':
|
||||||
Attribute(QWebEngineSettings.LocalStorageEnabled),
|
Attribute(QWebEngineSettings.LocalStorageEnabled),
|
||||||
'cache-size':
|
'cache-size':
|
||||||
ProfileSetter(getter='httpCacheMaximumSize',
|
DefaultProfileSetter(getter='httpCacheMaximumSize',
|
||||||
setter='setHttpCacheMaximumSize')
|
setter='setHttpCacheMaximumSize')
|
||||||
},
|
},
|
||||||
'general': {
|
'general': {
|
||||||
|
@ -34,7 +34,8 @@ from PyQt5.QtWebEngineWidgets import (QWebEnginePage, QWebEngineScript,
|
|||||||
from qutebrowser.browser import browsertab, mouse, shared
|
from qutebrowser.browser import browsertab, mouse, shared
|
||||||
from qutebrowser.browser.webengine import (webview, webengineelem, tabhistory,
|
from qutebrowser.browser.webengine import (webview, webengineelem, tabhistory,
|
||||||
interceptor, webenginequtescheme,
|
interceptor, webenginequtescheme,
|
||||||
webenginedownloads)
|
webenginedownloads,
|
||||||
|
webenginesettings)
|
||||||
from qutebrowser.misc import miscwidgets
|
from qutebrowser.misc import miscwidgets
|
||||||
from qutebrowser.utils import (usertypes, qtutils, log, javascript, utils,
|
from qutebrowser.utils import (usertypes, qtutils, log, javascript, utils,
|
||||||
objreg, jinja, debug)
|
objreg, jinja, debug)
|
||||||
@ -50,21 +51,23 @@ def init():
|
|||||||
# https://www.riverbankcomputing.com/pipermail/pyqt/2016-September/038075.html
|
# https://www.riverbankcomputing.com/pipermail/pyqt/2016-September/038075.html
|
||||||
global _qute_scheme_handler
|
global _qute_scheme_handler
|
||||||
app = QApplication.instance()
|
app = QApplication.instance()
|
||||||
profile = QWebEngineProfile.defaultProfile()
|
|
||||||
|
|
||||||
log.init.debug("Initializing qute://* handler...")
|
log.init.debug("Initializing qute://* handler...")
|
||||||
_qute_scheme_handler = webenginequtescheme.QuteSchemeHandler(parent=app)
|
_qute_scheme_handler = webenginequtescheme.QuteSchemeHandler(parent=app)
|
||||||
_qute_scheme_handler.install(profile)
|
_qute_scheme_handler.install(webenginesettings.default_profile)
|
||||||
|
_qute_scheme_handler.install(webenginesettings.private_profile)
|
||||||
|
|
||||||
log.init.debug("Initializing request interceptor...")
|
log.init.debug("Initializing request interceptor...")
|
||||||
host_blocker = objreg.get('host-blocker')
|
host_blocker = objreg.get('host-blocker')
|
||||||
req_interceptor = interceptor.RequestInterceptor(
|
req_interceptor = interceptor.RequestInterceptor(
|
||||||
host_blocker, parent=app)
|
host_blocker, parent=app)
|
||||||
req_interceptor.install(profile)
|
req_interceptor.install(webenginesettings.default_profile)
|
||||||
|
req_interceptor.install(webenginesettings.private_profile)
|
||||||
|
|
||||||
log.init.debug("Initializing QtWebEngine downloads...")
|
log.init.debug("Initializing QtWebEngine downloads...")
|
||||||
download_manager = webenginedownloads.DownloadManager(parent=app)
|
download_manager = webenginedownloads.DownloadManager(parent=app)
|
||||||
download_manager.install(profile)
|
download_manager.install(webenginesettings.default_profile)
|
||||||
|
download_manager.install(webenginesettings.private_profile)
|
||||||
objreg.register('webengine-download-manager', download_manager)
|
objreg.register('webengine-download-manager', download_manager)
|
||||||
|
|
||||||
|
|
||||||
@ -522,11 +525,10 @@ class WebEngineTab(browsertab.AbstractTab):
|
|||||||
"""A QtWebEngine tab in the browser."""
|
"""A QtWebEngine tab in the browser."""
|
||||||
|
|
||||||
def __init__(self, *, win_id, mode_manager, private, parent=None):
|
def __init__(self, *, win_id, mode_manager, private, parent=None):
|
||||||
# FIXME
|
|
||||||
assert not private
|
|
||||||
super().__init__(win_id=win_id, mode_manager=mode_manager,
|
super().__init__(win_id=win_id, mode_manager=mode_manager,
|
||||||
private=private, parent=parent)
|
private=private, parent=parent)
|
||||||
widget = webview.WebEngineView(tabdata=self.data, win_id=win_id)
|
widget = webview.WebEngineView(tabdata=self.data, win_id=win_id,
|
||||||
|
private=private)
|
||||||
self.history = WebEngineHistory(self)
|
self.history = WebEngineHistory(self)
|
||||||
self.scroller = WebEngineScroller(self, parent=self)
|
self.scroller = WebEngineScroller(self, parent=self)
|
||||||
self.caret = WebEngineCaret(win_id=win_id, mode_manager=mode_manager,
|
self.caret = WebEngineCaret(win_id=win_id, mode_manager=mode_manager,
|
||||||
|
@ -28,7 +28,7 @@ from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
|
|||||||
# pylint: enable=no-name-in-module,import-error,useless-suppression
|
# pylint: enable=no-name-in-module,import-error,useless-suppression
|
||||||
|
|
||||||
from qutebrowser.browser import shared
|
from qutebrowser.browser import shared
|
||||||
from qutebrowser.browser.webengine import certificateerror
|
from qutebrowser.browser.webengine import certificateerror, webenginesettings
|
||||||
from qutebrowser.config import config
|
from qutebrowser.config import config
|
||||||
from qutebrowser.utils import (log, debug, usertypes, jinja, urlutils, message,
|
from qutebrowser.utils import (log, debug, usertypes, jinja, urlutils, message,
|
||||||
objreg)
|
objreg)
|
||||||
@ -38,13 +38,19 @@ class WebEngineView(QWebEngineView):
|
|||||||
|
|
||||||
"""Custom QWebEngineView subclass with qutebrowser-specific features."""
|
"""Custom QWebEngineView subclass with qutebrowser-specific features."""
|
||||||
|
|
||||||
def __init__(self, tabdata, win_id, parent=None):
|
def __init__(self, *, tabdata, win_id, private, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._win_id = win_id
|
self._win_id = win_id
|
||||||
self._tabdata = tabdata
|
self._tabdata = tabdata
|
||||||
|
|
||||||
theme_color = self.style().standardPalette().color(QPalette.Base)
|
theme_color = self.style().standardPalette().color(QPalette.Base)
|
||||||
page = WebEnginePage(theme_color=theme_color, parent=self)
|
if private:
|
||||||
|
profile = webenginesettings.private_profile
|
||||||
|
assert profile.isOffTheRecord()
|
||||||
|
else:
|
||||||
|
profile = webenginesettings.default_profile
|
||||||
|
page = WebEnginePage(theme_color=theme_color, profile=profile,
|
||||||
|
parent=self)
|
||||||
self.setPage(page)
|
self.setPage(page)
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
@ -124,8 +130,8 @@ class WebEnginePage(QWebEnginePage):
|
|||||||
certificate_error = pyqtSignal()
|
certificate_error = pyqtSignal()
|
||||||
shutting_down = pyqtSignal()
|
shutting_down = pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, theme_color, parent=None):
|
def __init__(self, *, theme_color, profile, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(profile, parent)
|
||||||
self._is_shutting_down = False
|
self._is_shutting_down = False
|
||||||
self.featurePermissionRequested.connect(
|
self.featurePermissionRequested.connect(
|
||||||
self._on_feature_permission_requested)
|
self._on_feature_permission_requested)
|
||||||
|
@ -185,8 +185,7 @@ def data(readonly=False):
|
|||||||
"Encoding to use for editor."),
|
"Encoding to use for editor."),
|
||||||
|
|
||||||
('private-browsing',
|
('private-browsing',
|
||||||
SettingValue(typ.Bool(), 'false',
|
SettingValue(typ.Bool(), 'false'),
|
||||||
backends=[usertypes.Backend.QtWebKit]),
|
|
||||||
"Do not record visited pages in the history or store web page "
|
"Do not record visited pages in the history or store web page "
|
||||||
"icons."),
|
"icons."),
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user