Merge branch 'new-private-browsing'
This commit is contained in:
commit
086139110d
@ -544,7 +544,8 @@ For `increment` and `decrement`, the number to change the URL by. For `up`, the
|
||||
|
||||
[[open]]
|
||||
=== open
|
||||
Syntax: +:open [*--implicit*] [*--bg*] [*--tab*] [*--window*] [*--secure*] ['url']+
|
||||
Syntax: +:open [*--implicit*] [*--bg*] [*--tab*] [*--window*] [*--secure*] [*--private*]
|
||||
['url']+
|
||||
|
||||
Open a URL in the current/[count]th tab.
|
||||
|
||||
@ -560,6 +561,7 @@ If the URL contains newlines, each line gets opened in its own tab.
|
||||
* +*-t*+, +*--tab*+: Open in a new tab.
|
||||
* +*-w*+, +*--window*+: Open in a new window.
|
||||
* +*-s*+, +*--secure*+: Force HTTPS.
|
||||
* +*-p*+, +*--private*+: Open a new window in private browsing mode.
|
||||
|
||||
==== count
|
||||
The tab index to open the URL in.
|
||||
@ -743,6 +745,7 @@ Load a session.
|
||||
[[session-save]]
|
||||
=== session-save
|
||||
Syntax: +:session-save [*--current*] [*--quiet*] [*--force*] [*--only-active-window*]
|
||||
[*--with-private*]
|
||||
['name']+
|
||||
|
||||
Save a session.
|
||||
@ -756,6 +759,7 @@ Save a session.
|
||||
* +*-q*+, +*--quiet*+: Don't show confirmation message.
|
||||
* +*-f*+, +*--force*+: Force saving internal sessions (starting with an underline).
|
||||
* +*-o*+, +*--only-active-window*+: Saves only tabs of the currently active window.
|
||||
* +*-p*+, +*--with-private*+: Include private windows.
|
||||
|
||||
[[set]]
|
||||
=== set
|
||||
|
@ -18,7 +18,7 @@
|
||||
|<<general-auto-save-interval,auto-save-interval>>|How often (in milliseconds) to auto-save config/cookies/etc.
|
||||
|<<general-editor,editor>>|The editor (and arguments) to use for the `open-editor` command.
|
||||
|<<general-editor-encoding,editor-encoding>>|Encoding to use for editor.
|
||||
|<<general-private-browsing,private-browsing>>|Do not record visited pages in the history or store web page icons.
|
||||
|<<general-private-browsing,private-browsing>>|Open new windows in private browsing mode which does not record visited pages.
|
||||
|<<general-developer-extras,developer-extras>>|Enable extra tools for Web developers.
|
||||
|<<general-print-element-backgrounds,print-element-backgrounds>>|Whether the background color and images are also drawn when the page is printed.
|
||||
|<<general-xss-auditing,xss-auditing>>|Whether load requests should be monitored for cross-site scripting attempts.
|
||||
@ -221,10 +221,14 @@
|
||||
|<<colors-completion.scrollbar.bg,completion.scrollbar.bg>>|Color of the scrollbar in completion view
|
||||
|<<colors-statusbar.fg,statusbar.fg>>|Foreground color of the statusbar.
|
||||
|<<colors-statusbar.bg,statusbar.bg>>|Background color of the statusbar.
|
||||
|<<colors-statusbar.fg.private,statusbar.fg.private>>|Foreground color of the statusbar in private browsing mode.
|
||||
|<<colors-statusbar.bg.private,statusbar.bg.private>>|Background color of the statusbar in private browsing mode.
|
||||
|<<colors-statusbar.fg.insert,statusbar.fg.insert>>|Foreground color of the statusbar in insert mode.
|
||||
|<<colors-statusbar.bg.insert,statusbar.bg.insert>>|Background color of the statusbar in insert mode.
|
||||
|<<colors-statusbar.fg.command,statusbar.fg.command>>|Foreground color of the statusbar in command mode.
|
||||
|<<colors-statusbar.bg.command,statusbar.bg.command>>|Background color of the statusbar in command mode.
|
||||
|<<colors-statusbar.fg.command.private,statusbar.fg.command.private>>|Foreground color of the statusbar in private browsing + command mode.
|
||||
|<<colors-statusbar.bg.command.private,statusbar.bg.command.private>>|Background color of the statusbar in private browsing + command mode.
|
||||
|<<colors-statusbar.fg.caret,statusbar.fg.caret>>|Foreground color of the statusbar in caret mode.
|
||||
|<<colors-statusbar.bg.caret,statusbar.bg.caret>>|Background color of the statusbar in caret mode.
|
||||
|<<colors-statusbar.fg.caret-selection,statusbar.fg.caret-selection>>|Foreground color of the statusbar in caret mode with a selection
|
||||
@ -395,7 +399,7 @@ Default: +pass:[utf-8]+
|
||||
|
||||
[[general-private-browsing]]
|
||||
=== private-browsing
|
||||
Do not record visited pages in the history or store web page icons.
|
||||
Open new windows in private browsing mode which does not record visited pages.
|
||||
|
||||
Valid values:
|
||||
|
||||
@ -404,8 +408,6 @@ Valid values:
|
||||
|
||||
Default: +pass:[false]+
|
||||
|
||||
This setting is only available with the QtWebKit backend.
|
||||
|
||||
[[general-developer-extras]]
|
||||
=== developer-extras
|
||||
Enable extra tools for Web developers.
|
||||
@ -1906,6 +1908,18 @@ Background color of the statusbar.
|
||||
|
||||
Default: +pass:[black]+
|
||||
|
||||
[[colors-statusbar.fg.private]]
|
||||
=== statusbar.fg.private
|
||||
Foreground color of the statusbar in private browsing mode.
|
||||
|
||||
Default: +pass:[${statusbar.fg}]+
|
||||
|
||||
[[colors-statusbar.bg.private]]
|
||||
=== statusbar.bg.private
|
||||
Background color of the statusbar in private browsing mode.
|
||||
|
||||
Default: +pass:[#666666]+
|
||||
|
||||
[[colors-statusbar.fg.insert]]
|
||||
=== statusbar.fg.insert
|
||||
Foreground color of the statusbar in insert mode.
|
||||
@ -1930,6 +1944,18 @@ Background color of the statusbar in command mode.
|
||||
|
||||
Default: +pass:[${statusbar.bg}]+
|
||||
|
||||
[[colors-statusbar.fg.command.private]]
|
||||
=== statusbar.fg.command.private
|
||||
Foreground color of the statusbar in private browsing + command mode.
|
||||
|
||||
Default: +pass:[${statusbar.fg.private}]+
|
||||
|
||||
[[colors-statusbar.bg.command.private]]
|
||||
=== statusbar.bg.command.private
|
||||
Background color of the statusbar in private browsing + command mode.
|
||||
|
||||
Default: +pass:[${statusbar.bg.private}]+
|
||||
|
||||
[[colors-statusbar.fg.caret]]
|
||||
=== statusbar.fg.caret
|
||||
Foreground color of the statusbar in caret mode.
|
||||
|
@ -195,7 +195,7 @@ def _process_args(args):
|
||||
session_manager = objreg.get('session-manager')
|
||||
if not session_manager.did_load:
|
||||
log.init.debug("Initializing main window...")
|
||||
window = mainwindow.MainWindow()
|
||||
window = mainwindow.MainWindow(private=None)
|
||||
if not args.nowindow:
|
||||
window.show()
|
||||
qApp.setActiveWindow(window)
|
||||
|
@ -35,11 +35,12 @@ from qutebrowser.browser import mouse, hints
|
||||
tab_id_gen = itertools.count(0)
|
||||
|
||||
|
||||
def create(win_id, parent=None):
|
||||
def create(win_id, private, parent=None):
|
||||
"""Get a QtWebKit/QtWebEngine tab object.
|
||||
|
||||
Args:
|
||||
win_id: The window ID where the tab will be shown.
|
||||
private: Whether the tab is a private/off the record tab.
|
||||
parent: The Qt parent to set.
|
||||
"""
|
||||
# Importing modules here so we don't depend on QtWebEngine without the
|
||||
@ -51,7 +52,8 @@ def create(win_id, parent=None):
|
||||
else:
|
||||
from qutebrowser.browser.webkit import webkittab
|
||||
tab_class = webkittab.WebKitTab
|
||||
return tab_class(win_id=win_id, mode_manager=mode_manager, parent=parent)
|
||||
return tab_class(win_id=win_id, mode_manager=mode_manager, private=private,
|
||||
parent=parent)
|
||||
|
||||
|
||||
def init():
|
||||
@ -542,6 +544,7 @@ class AbstractTab(QWidget):
|
||||
Attributes:
|
||||
history: The AbstractHistory for the current tab.
|
||||
registry: The ObjectRegistry associated with this tab.
|
||||
private: Whether private browsing is turned on for this tab.
|
||||
|
||||
_load_status: loading status of this page
|
||||
Accessible via load_status() method.
|
||||
@ -581,7 +584,8 @@ class AbstractTab(QWidget):
|
||||
fullscreen_requested = pyqtSignal(bool)
|
||||
renderer_process_terminated = pyqtSignal(TerminationStatus, int)
|
||||
|
||||
def __init__(self, win_id, mode_manager, parent=None):
|
||||
def __init__(self, *, win_id, mode_manager, private, parent=None):
|
||||
self.private = private
|
||||
self.win_id = win_id
|
||||
self.tab_id = next(tab_id_gen)
|
||||
super().__init__(parent)
|
||||
|
@ -67,10 +67,10 @@ class CommandDispatcher:
|
||||
def __repr__(self):
|
||||
return utils.get_repr(self)
|
||||
|
||||
def _new_tabbed_browser(self):
|
||||
def _new_tabbed_browser(self, private):
|
||||
"""Get a tabbed-browser from a new window."""
|
||||
from qutebrowser.mainwindow import mainwindow
|
||||
new_window = mainwindow.MainWindow()
|
||||
new_window = mainwindow.MainWindow(private=private)
|
||||
new_window.show()
|
||||
return new_window.tabbed_browser
|
||||
|
||||
@ -110,7 +110,7 @@ class CommandDispatcher:
|
||||
return widget
|
||||
|
||||
def _open(self, url, tab=False, background=False, window=False,
|
||||
explicit=True):
|
||||
explicit=True, private=None):
|
||||
"""Helper function to open a page.
|
||||
|
||||
Args:
|
||||
@ -118,12 +118,17 @@ class CommandDispatcher:
|
||||
tab: Whether to open in a new tab.
|
||||
background: Whether to open in the background.
|
||||
window: Whether to open in a new window
|
||||
private: If opening a new window, open it in private browsing mode.
|
||||
If not given, inherit the current window's mode.
|
||||
"""
|
||||
urlutils.raise_cmdexc_if_invalid(url)
|
||||
tabbed_browser = self._tabbed_browser
|
||||
cmdutils.check_exclusive((tab, background, window), 'tbw')
|
||||
if window:
|
||||
tabbed_browser = self._new_tabbed_browser()
|
||||
cmdutils.check_exclusive((tab, background, window, private), 'tbwp')
|
||||
if private is None:
|
||||
private = self._tabbed_browser.private
|
||||
|
||||
if window or private:
|
||||
tabbed_browser = self._new_tabbed_browser(private)
|
||||
tabbed_browser.tabopen(url)
|
||||
elif tab:
|
||||
tabbed_browser.tabopen(url, background=False, explicit=explicit)
|
||||
@ -228,7 +233,8 @@ class CommandDispatcher:
|
||||
@cmdutils.argument('url', completion=usertypes.Completion.url)
|
||||
@cmdutils.argument('count', count=True)
|
||||
def openurl(self, url=None, implicit=False,
|
||||
bg=False, tab=False, window=False, count=None, secure=False):
|
||||
bg=False, tab=False, window=False, count=None, secure=False,
|
||||
private=False):
|
||||
"""Open a URL in the current/[count]th tab.
|
||||
|
||||
If the URL contains newlines, each line gets opened in its own tab.
|
||||
@ -242,6 +248,7 @@ class CommandDispatcher:
|
||||
clicking on a link).
|
||||
count: The tab index to open the URL in, or None.
|
||||
secure: Force HTTPS.
|
||||
private: Open a new window in private browsing mode.
|
||||
"""
|
||||
if url is None:
|
||||
urls = [config.get('general', 'default-page')]
|
||||
@ -254,8 +261,10 @@ class CommandDispatcher:
|
||||
if not window and i > 0:
|
||||
tab = False
|
||||
bg = True
|
||||
if tab or bg or window:
|
||||
self._open(cur_url, tab, bg, window, not implicit)
|
||||
|
||||
if tab or bg or window or private:
|
||||
self._open(cur_url, tab, bg, window, explicit=not implicit,
|
||||
private=private)
|
||||
else:
|
||||
curtab = self._cntwidget(count)
|
||||
if curtab is None:
|
||||
@ -430,7 +439,8 @@ class CommandDispatcher:
|
||||
# The new tab could be in a new tabbed_browser (e.g. because of
|
||||
# tabs-are-windows being set)
|
||||
if window:
|
||||
new_tabbed_browser = self._new_tabbed_browser()
|
||||
new_tabbed_browser = self._new_tabbed_browser(
|
||||
private=self._tabbed_browser.private)
|
||||
else:
|
||||
new_tabbed_browser = self._tabbed_browser
|
||||
newtab = new_tabbed_browser.tabopen(background=bg)
|
||||
|
@ -27,7 +27,6 @@ from PyQt5.QtCore import pyqtSignal, pyqtSlot, QUrl, QObject
|
||||
from qutebrowser.commands import cmdutils
|
||||
from qutebrowser.utils import (utils, objreg, standarddir, log, qtutils,
|
||||
usertypes, message)
|
||||
from qutebrowser.config import config
|
||||
from qutebrowser.misc import lineparser, objects
|
||||
|
||||
|
||||
@ -280,8 +279,6 @@ class WebHistory(QObject):
|
||||
(hidden in completion)
|
||||
atime: Override the atime used to add the entry
|
||||
"""
|
||||
if config.get('general', 'private-browsing'):
|
||||
return
|
||||
if not url.isValid(): # pragma: no cover
|
||||
# the no cover pragma is a WORKAROUND for this not being covered in
|
||||
# old Qt versions.
|
||||
|
@ -127,17 +127,19 @@ def prevnext(*, browsertab, win_id, baseurl, prev=False,
|
||||
return
|
||||
qtutils.ensure_valid(url)
|
||||
|
||||
cur_tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||
window=win_id)
|
||||
|
||||
if window:
|
||||
from qutebrowser.mainwindow import mainwindow
|
||||
new_window = mainwindow.MainWindow()
|
||||
new_window = mainwindow.MainWindow(
|
||||
private=cur_tabbed_browser.private)
|
||||
new_window.show()
|
||||
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||
window=new_window.win_id)
|
||||
tabbed_browser.tabopen(url, background=False)
|
||||
elif tab:
|
||||
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||
window=win_id)
|
||||
tabbed_browser.tabopen(url, background=background)
|
||||
cur_tabbed_browser.tabopen(url, background=background)
|
||||
else:
|
||||
browsertab.openurl(url)
|
||||
|
||||
|
@ -366,7 +366,7 @@ class DownloadManager(downloads.AbstractDownloadManager):
|
||||
def __init__(self, win_id, parent=None):
|
||||
super().__init__(parent)
|
||||
self._networkmanager = networkmanager.NetworkManager(
|
||||
win_id, None, self)
|
||||
win_id=win_id, tab_id=None, private=False, parent=self)
|
||||
|
||||
@pyqtSlot('QUrl')
|
||||
def get(self, url, *, user_agent=None, **kwargs):
|
||||
|
@ -216,8 +216,10 @@ def get_tab(win_id, target):
|
||||
win_id = win_id
|
||||
bg_tab = True
|
||||
elif target == usertypes.ClickTarget.window:
|
||||
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||
window=win_id)
|
||||
from qutebrowser.mainwindow import mainwindow
|
||||
window = mainwindow.MainWindow()
|
||||
window = mainwindow.MainWindow(private=tabbed_browser.private)
|
||||
window.show()
|
||||
win_id = window.win_id
|
||||
bg_tab = False
|
||||
|
@ -364,15 +364,16 @@ class AbstractWebElement(collections.abc.MutableMapping):
|
||||
self._click_fake_event(click_target)
|
||||
return
|
||||
|
||||
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||
window=self._tab.win_id)
|
||||
|
||||
if click_target in [usertypes.ClickTarget.tab,
|
||||
usertypes.ClickTarget.tab_bg]:
|
||||
background = click_target == usertypes.ClickTarget.tab_bg
|
||||
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||
window=self._tab.win_id)
|
||||
tabbed_browser.tabopen(url, background=background)
|
||||
elif click_target == usertypes.ClickTarget.window:
|
||||
from qutebrowser.mainwindow import mainwindow
|
||||
window = mainwindow.MainWindow()
|
||||
window = mainwindow.MainWindow(private=tabbed_browser.private)
|
||||
window.show()
|
||||
window.tabbed_browser.tabopen(url)
|
||||
else:
|
||||
|
@ -38,6 +38,12 @@ from qutebrowser.utils import (objreg, utils, standarddir, javascript, log,
|
||||
qtutils)
|
||||
|
||||
|
||||
# The default QWebEngineProfile
|
||||
default_profile = None
|
||||
# The QWebEngineProfile used for private (off-the-record) windows
|
||||
private_profile = None
|
||||
|
||||
|
||||
class Attribute(websettings.Attribute):
|
||||
|
||||
"""A setting set via QWebEngineSettings::setAttribute."""
|
||||
@ -67,7 +73,7 @@ class StaticSetter(websettings.StaticSetter):
|
||||
GLOBAL_SETTINGS = QWebEngineSettings.globalSettings
|
||||
|
||||
|
||||
class ProfileSetter(websettings.Base):
|
||||
class DefaultProfileSetter(websettings.Base):
|
||||
|
||||
"""A setting set on the QWebEngineProfile."""
|
||||
|
||||
@ -78,16 +84,16 @@ class ProfileSetter(websettings.Base):
|
||||
|
||||
def get(self, settings=None):
|
||||
utils.unused(settings)
|
||||
getter = getattr(QWebEngineProfile.defaultProfile(), self._getter)
|
||||
getter = getattr(default_profile, self._getter)
|
||||
return getter()
|
||||
|
||||
def _set(self, value, settings=None):
|
||||
utils.unused(settings)
|
||||
setter = getattr(QWebEngineProfile.defaultProfile(), self._setter)
|
||||
setter = getattr(default_profile, self._setter)
|
||||
setter(value)
|
||||
|
||||
|
||||
class PersistentCookiePolicy(ProfileSetter):
|
||||
class PersistentCookiePolicy(DefaultProfileSetter):
|
||||
|
||||
"""The cookies -> store setting is different from other settings."""
|
||||
|
||||
@ -141,19 +147,27 @@ def _init_stylesheet(profile):
|
||||
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):
|
||||
"""Update global settings when qwebsettings changed."""
|
||||
websettings.update_mappings(MAPPINGS, section, option)
|
||||
profile = QWebEngineProfile.defaultProfile()
|
||||
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):
|
||||
@ -173,9 +187,7 @@ def init(args):
|
||||
else:
|
||||
log.misc.debug("Imported PyOpenGL as workaround")
|
||||
|
||||
profile = QWebEngineProfile.defaultProfile()
|
||||
_init_profile(profile)
|
||||
_init_stylesheet(profile)
|
||||
_init_profiles()
|
||||
# We need to do this here as a WORKAROUND for
|
||||
# https://bugreports.qt.io/browse/QTBUG-58650
|
||||
if not qtutils.version_check('5.9'):
|
||||
@ -282,8 +294,8 @@ MAPPINGS = {
|
||||
'local-storage':
|
||||
Attribute(QWebEngineSettings.LocalStorageEnabled),
|
||||
'cache-size':
|
||||
ProfileSetter(getter='httpCacheMaximumSize',
|
||||
setter='setHttpCacheMaximumSize')
|
||||
DefaultProfileSetter(getter='httpCacheMaximumSize',
|
||||
setter='setHttpCacheMaximumSize')
|
||||
},
|
||||
'general': {
|
||||
'xss-auditing':
|
||||
|
@ -27,14 +27,14 @@ from PyQt5.QtGui import QKeyEvent
|
||||
from PyQt5.QtNetwork import QAuthenticator
|
||||
# pylint: disable=no-name-in-module,import-error,useless-suppression
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
from PyQt5.QtWebEngineWidgets import (QWebEnginePage, QWebEngineScript,
|
||||
QWebEngineProfile)
|
||||
from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineScript
|
||||
# pylint: enable=no-name-in-module,import-error,useless-suppression
|
||||
|
||||
from qutebrowser.browser import browsertab, mouse, shared
|
||||
from qutebrowser.browser.webengine import (webview, webengineelem, tabhistory,
|
||||
interceptor, webenginequtescheme,
|
||||
webenginedownloads)
|
||||
webenginedownloads,
|
||||
webenginesettings)
|
||||
from qutebrowser.misc import miscwidgets
|
||||
from qutebrowser.utils import (usertypes, qtutils, log, javascript, utils,
|
||||
objreg, jinja, debug)
|
||||
@ -50,21 +50,23 @@ def init():
|
||||
# https://www.riverbankcomputing.com/pipermail/pyqt/2016-September/038075.html
|
||||
global _qute_scheme_handler
|
||||
app = QApplication.instance()
|
||||
profile = QWebEngineProfile.defaultProfile()
|
||||
|
||||
log.init.debug("Initializing qute://* handler...")
|
||||
_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...")
|
||||
host_blocker = objreg.get('host-blocker')
|
||||
req_interceptor = interceptor.RequestInterceptor(
|
||||
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...")
|
||||
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)
|
||||
|
||||
|
||||
@ -521,10 +523,11 @@ class WebEngineTab(browsertab.AbstractTab):
|
||||
|
||||
"""A QtWebEngine tab in the browser."""
|
||||
|
||||
def __init__(self, win_id, mode_manager, parent=None):
|
||||
def __init__(self, *, win_id, mode_manager, private, parent=None):
|
||||
super().__init__(win_id=win_id, mode_manager=mode_manager,
|
||||
parent=parent)
|
||||
widget = webview.WebEngineView(tabdata=self.data, win_id=win_id)
|
||||
private=private, parent=parent)
|
||||
widget = webview.WebEngineView(tabdata=self.data, win_id=win_id,
|
||||
private=private)
|
||||
self.history = WebEngineHistory(self)
|
||||
self.scroller = WebEngineScroller(self, parent=self)
|
||||
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
|
||||
|
||||
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.utils import (log, debug, usertypes, jinja, urlutils, message,
|
||||
objreg)
|
||||
@ -38,13 +38,19 @@ class WebEngineView(QWebEngineView):
|
||||
|
||||
"""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)
|
||||
self._win_id = win_id
|
||||
self._tabdata = tabdata
|
||||
|
||||
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)
|
||||
|
||||
def shutdown(self):
|
||||
@ -124,8 +130,8 @@ class WebEnginePage(QWebEnginePage):
|
||||
certificate_error = pyqtSignal()
|
||||
shutting_down = pyqtSignal()
|
||||
|
||||
def __init__(self, theme_color, parent=None):
|
||||
super().__init__(parent)
|
||||
def __init__(self, *, theme_color, profile, parent=None):
|
||||
super().__init__(profile, parent)
|
||||
self._is_shutting_down = False
|
||||
self.featurePermissionRequested.connect(
|
||||
self._on_feature_permission_requested)
|
||||
|
@ -21,8 +21,7 @@
|
||||
|
||||
import os.path
|
||||
|
||||
from PyQt5.QtCore import pyqtSlot
|
||||
from PyQt5.QtNetwork import QNetworkDiskCache, QNetworkCacheMetaData
|
||||
from PyQt5.QtNetwork import QNetworkDiskCache
|
||||
|
||||
from qutebrowser.config import config
|
||||
from qutebrowser.utils import utils, objreg, qtutils
|
||||
@ -30,24 +29,21 @@ from qutebrowser.utils import utils, objreg, qtutils
|
||||
|
||||
class DiskCache(QNetworkDiskCache):
|
||||
|
||||
"""Disk cache which sets correct cache dir and size.
|
||||
|
||||
Attributes:
|
||||
_activated: Whether the cache should be used.
|
||||
_cache_dir: The base directory for cache files (standarddir.cache())
|
||||
"""
|
||||
"""Disk cache which sets correct cache dir and size."""
|
||||
|
||||
def __init__(self, cache_dir, parent=None):
|
||||
super().__init__(parent)
|
||||
self._cache_dir = cache_dir
|
||||
self._maybe_activate()
|
||||
objreg.get('config').changed.connect(self.on_config_changed)
|
||||
assert not config.get('general', 'private-browsing')
|
||||
self.setCacheDirectory(os.path.join(cache_dir, 'http'))
|
||||
self._set_cache_size()
|
||||
objreg.get('config').changed.connect(self._set_cache_size)
|
||||
|
||||
def __repr__(self):
|
||||
return utils.get_repr(self, size=self.cacheSize(),
|
||||
maxsize=self.maximumCacheSize(),
|
||||
path=self.cacheDirectory())
|
||||
|
||||
@config.change_filter('storage', 'cache-size')
|
||||
def _set_cache_size(self):
|
||||
"""Set the cache size based on the config."""
|
||||
size = config.get('storage', 'cache-size')
|
||||
@ -58,128 +54,3 @@ class DiskCache(QNetworkDiskCache):
|
||||
not qtutils.version_check('5.9')): # pragma: no cover
|
||||
size = 0
|
||||
self.setMaximumCacheSize(size)
|
||||
|
||||
def _maybe_activate(self):
|
||||
"""Activate/deactivate the cache based on the config."""
|
||||
if config.get('general', 'private-browsing'):
|
||||
self._activated = False
|
||||
else:
|
||||
self._activated = True
|
||||
self.setCacheDirectory(os.path.join(self._cache_dir, 'http'))
|
||||
self._set_cache_size()
|
||||
|
||||
@pyqtSlot(str, str)
|
||||
def on_config_changed(self, section, option):
|
||||
"""Update cache size/activated if the config was changed."""
|
||||
if (section, option) == ('storage', 'cache-size'):
|
||||
self._set_cache_size()
|
||||
elif (section, option) == ('general', # pragma: no branch
|
||||
'private-browsing'):
|
||||
self._maybe_activate()
|
||||
|
||||
def cacheSize(self):
|
||||
"""Return the current size taken up by the cache.
|
||||
|
||||
Return:
|
||||
An int.
|
||||
"""
|
||||
if self._activated:
|
||||
return super().cacheSize()
|
||||
else:
|
||||
return 0
|
||||
|
||||
def fileMetaData(self, filename):
|
||||
"""Return the QNetworkCacheMetaData for the cache file filename.
|
||||
|
||||
Args:
|
||||
filename: The file name as a string.
|
||||
|
||||
Return:
|
||||
A QNetworkCacheMetaData object.
|
||||
"""
|
||||
if self._activated:
|
||||
return super().fileMetaData(filename)
|
||||
else:
|
||||
return QNetworkCacheMetaData()
|
||||
|
||||
def data(self, url):
|
||||
"""Return the data associated with url.
|
||||
|
||||
Args:
|
||||
url: A QUrl.
|
||||
|
||||
return:
|
||||
A QIODevice or None.
|
||||
"""
|
||||
if self._activated:
|
||||
return super().data(url)
|
||||
else:
|
||||
return None
|
||||
|
||||
def insert(self, device):
|
||||
"""Insert the data in device and the prepared meta data into the cache.
|
||||
|
||||
Args:
|
||||
device: A QIODevice.
|
||||
"""
|
||||
if self._activated:
|
||||
super().insert(device)
|
||||
else:
|
||||
return None
|
||||
|
||||
def metaData(self, url):
|
||||
"""Return the meta data for the url url.
|
||||
|
||||
Args:
|
||||
url: A QUrl.
|
||||
|
||||
Return:
|
||||
A QNetworkCacheMetaData object.
|
||||
"""
|
||||
if self._activated:
|
||||
return super().metaData(url)
|
||||
else:
|
||||
return QNetworkCacheMetaData()
|
||||
|
||||
def prepare(self, meta_data):
|
||||
"""Return the device that should be populated with the data.
|
||||
|
||||
Args:
|
||||
meta_data: A QNetworkCacheMetaData object.
|
||||
|
||||
Return:
|
||||
A QIODevice or None.
|
||||
"""
|
||||
if self._activated:
|
||||
return super().prepare(meta_data)
|
||||
else:
|
||||
return None
|
||||
|
||||
def remove(self, url):
|
||||
"""Remove the cache entry for url.
|
||||
|
||||
Return:
|
||||
True on success, False otherwise.
|
||||
"""
|
||||
if self._activated:
|
||||
return super().remove(url)
|
||||
else:
|
||||
return False
|
||||
|
||||
def updateMetaData(self, meta_data):
|
||||
"""Update the cache meta date for the meta_data's url to meta_data.
|
||||
|
||||
Args:
|
||||
meta_data: A QNetworkCacheMetaData object.
|
||||
"""
|
||||
if self._activated:
|
||||
super().updateMetaData(meta_data)
|
||||
else:
|
||||
return
|
||||
|
||||
def clear(self):
|
||||
"""Remove all items from the cache."""
|
||||
if self._activated:
|
||||
super().clear()
|
||||
else:
|
||||
return
|
||||
|
@ -128,6 +128,7 @@ class NetworkManager(QNetworkAccessManager):
|
||||
_tab_id: The tab ID this NetworkManager is associated with.
|
||||
_rejected_ssl_errors: A {QUrl: [SslError]} dict of rejected errors.
|
||||
_accepted_ssl_errors: A {QUrl: [SslError]} dict of accepted errors.
|
||||
_private: Whether we're in private browsing mode.
|
||||
|
||||
Signals:
|
||||
shutting_down: Emitted when the QNAM is shutting down.
|
||||
@ -135,7 +136,7 @@ class NetworkManager(QNetworkAccessManager):
|
||||
|
||||
shutting_down = pyqtSignal()
|
||||
|
||||
def __init__(self, win_id, tab_id, parent=None):
|
||||
def __init__(self, *, win_id, tab_id, private, parent=None):
|
||||
log.init.debug("Initializing NetworkManager")
|
||||
with log.disable_qt_msghandler():
|
||||
# WORKAROUND for a hang when a message is printed - See:
|
||||
@ -146,11 +147,12 @@ class NetworkManager(QNetworkAccessManager):
|
||||
self._win_id = win_id
|
||||
self._tab_id = tab_id
|
||||
self._requests = []
|
||||
self._private = private
|
||||
self._scheme_handlers = {
|
||||
'qute': webkitqutescheme.QuteSchemeHandler(win_id),
|
||||
'file': filescheme.FileSchemeHandler(win_id),
|
||||
}
|
||||
self._set_cookiejar(private=config.get('general', 'private-browsing'))
|
||||
self._set_cookiejar()
|
||||
self._set_cache()
|
||||
self.sslErrors.connect(self.on_ssl_errors)
|
||||
self._rejected_ssl_errors = collections.defaultdict(list)
|
||||
@ -158,15 +160,10 @@ class NetworkManager(QNetworkAccessManager):
|
||||
self.authenticationRequired.connect(self.on_authentication_required)
|
||||
self.proxyAuthenticationRequired.connect(
|
||||
self.on_proxy_authentication_required)
|
||||
objreg.get('config').changed.connect(self.on_config_changed)
|
||||
|
||||
def _set_cookiejar(self, private=False):
|
||||
"""Set the cookie jar of the NetworkManager correctly.
|
||||
|
||||
Args:
|
||||
private: Whether we're currently in private browsing mode.
|
||||
"""
|
||||
if private:
|
||||
def _set_cookiejar(self):
|
||||
"""Set the cookie jar of the NetworkManager correctly."""
|
||||
if self._private:
|
||||
cookie_jar = objreg.get('ram-cookie-jar')
|
||||
else:
|
||||
cookie_jar = objreg.get('cookie-jar')
|
||||
@ -178,11 +175,9 @@ class NetworkManager(QNetworkAccessManager):
|
||||
cookie_jar.setParent(app)
|
||||
|
||||
def _set_cache(self):
|
||||
"""Set the cache of the NetworkManager correctly.
|
||||
|
||||
We can't switch the whole cache in private mode because QNAM would
|
||||
delete the old cache.
|
||||
"""
|
||||
"""Set the cache of the NetworkManager correctly."""
|
||||
if self._private:
|
||||
return
|
||||
# We have a shared cache - we restore its parent so we don't take
|
||||
# ownership of it.
|
||||
app = QCoreApplication.instance()
|
||||
@ -324,17 +319,6 @@ class NetworkManager(QNetworkAccessManager):
|
||||
authenticator.setPassword(answer.password)
|
||||
_proxy_auth_cache[proxy_id] = answer
|
||||
|
||||
@config.change_filter('general', 'private-browsing')
|
||||
def on_config_changed(self):
|
||||
"""Set cookie jar when entering/leaving private browsing mode."""
|
||||
private_browsing = config.get('general', 'private-browsing')
|
||||
if private_browsing:
|
||||
# switched from normal mode to private mode
|
||||
self._set_cookiejar(private=True)
|
||||
else:
|
||||
# switched from private mode to normal mode
|
||||
self._set_cookiejar()
|
||||
|
||||
@pyqtSlot()
|
||||
def on_adopted_download_destroyed(self):
|
||||
"""Check if we can clean up if an adopted download was destroyed.
|
||||
|
@ -29,7 +29,7 @@ import os.path
|
||||
from PyQt5.QtWebKit import QWebSettings
|
||||
|
||||
from qutebrowser.config import config, websettings
|
||||
from qutebrowser.utils import standarddir, objreg, urlutils, qtutils, message
|
||||
from qutebrowser.utils import standarddir, objreg, urlutils, qtutils
|
||||
from qutebrowser.browser import shared
|
||||
|
||||
|
||||
@ -88,21 +88,9 @@ def _set_user_stylesheet():
|
||||
QWebSettings.globalSettings().setUserStyleSheetUrl(url)
|
||||
|
||||
|
||||
def _init_private_browsing():
|
||||
if config.get('general', 'private-browsing'):
|
||||
if qtutils.is_qtwebkit_ng():
|
||||
message.warning("Private browsing is not fully implemented by "
|
||||
"QtWebKit-NG!")
|
||||
QWebSettings.setIconDatabasePath('')
|
||||
else:
|
||||
QWebSettings.setIconDatabasePath(standarddir.cache())
|
||||
|
||||
|
||||
def update_settings(section, option):
|
||||
"""Update global settings when qwebsettings changed."""
|
||||
if (section, option) == ('general', 'private-browsing'):
|
||||
_init_private_browsing()
|
||||
elif section == 'ui' and option in ['hide-scrollbar', 'user-stylesheet']:
|
||||
if section == 'ui' and option in ['hide-scrollbar', 'user-stylesheet']:
|
||||
_set_user_stylesheet()
|
||||
|
||||
websettings.update_mappings(MAPPINGS, section, option)
|
||||
@ -113,8 +101,7 @@ def init(_args):
|
||||
cache_path = standarddir.cache()
|
||||
data_path = standarddir.data()
|
||||
|
||||
_init_private_browsing()
|
||||
|
||||
QWebSettings.setIconDatabasePath(standarddir.cache())
|
||||
QWebSettings.setOfflineWebApplicationCachePath(
|
||||
os.path.join(cache_path, 'application-cache'))
|
||||
QWebSettings.globalSettings().setLocalStoragePath(
|
||||
@ -122,6 +109,13 @@ def init(_args):
|
||||
QWebSettings.setOfflineStoragePath(
|
||||
os.path.join(data_path, 'offline-storage'))
|
||||
|
||||
if (config.get('general', 'private-browsing') and
|
||||
not qtutils.version_check('5.4.2')):
|
||||
# WORKAROUND for https://codereview.qt-project.org/#/c/108936/
|
||||
# Won't work when private browsing is not enabled globally, but that's
|
||||
# the best we can do...
|
||||
QWebSettings.setIconDatabasePath('')
|
||||
|
||||
websettings.init_mappings(MAPPINGS)
|
||||
_set_user_stylesheet()
|
||||
objreg.get('config').changed.connect(update_settings)
|
||||
@ -254,8 +248,6 @@ MAPPINGS = {
|
||||
setter=QWebSettings.setOfflineWebApplicationCacheQuota),
|
||||
},
|
||||
'general': {
|
||||
'private-browsing':
|
||||
Attribute(QWebSettings.PrivateBrowsingEnabled),
|
||||
'developer-extras':
|
||||
Attribute(QWebSettings.DeveloperExtrasEnabled),
|
||||
'print-element-backgrounds':
|
||||
|
@ -629,10 +629,13 @@ class WebKitTab(browsertab.AbstractTab):
|
||||
|
||||
"""A QtWebKit tab in the browser."""
|
||||
|
||||
def __init__(self, win_id, mode_manager, parent=None):
|
||||
def __init__(self, *, win_id, mode_manager, private, parent=None):
|
||||
super().__init__(win_id=win_id, mode_manager=mode_manager,
|
||||
parent=parent)
|
||||
widget = webview.WebView(win_id, self.tab_id, tab=self)
|
||||
private=private, parent=parent)
|
||||
widget = webview.WebView(win_id=win_id, tab_id=self.tab_id,
|
||||
private=private, tab=self)
|
||||
if private:
|
||||
self._make_private(widget)
|
||||
self.history = WebKitHistory(self)
|
||||
self.scroller = WebKitScroller(self, parent=self)
|
||||
self.caret = WebKitCaret(win_id=win_id, mode_manager=mode_manager,
|
||||
@ -649,6 +652,10 @@ class WebKitTab(browsertab.AbstractTab):
|
||||
def _install_event_filter(self):
|
||||
self._widget.installEventFilter(self._mouse_event_filter)
|
||||
|
||||
def _make_private(self, widget):
|
||||
settings = widget.settings()
|
||||
settings.setAttribute(QWebSettings.PrivateBrowsingEnabled, True)
|
||||
|
||||
def openurl(self, url):
|
||||
self._openurl_prepare(url)
|
||||
self._widget.openurl(url)
|
||||
|
@ -59,7 +59,7 @@ class BrowserPage(QWebPage):
|
||||
shutting_down = pyqtSignal()
|
||||
reloading = pyqtSignal(QUrl)
|
||||
|
||||
def __init__(self, win_id, tab_id, tabdata, parent=None):
|
||||
def __init__(self, win_id, tab_id, tabdata, private, parent=None):
|
||||
super().__init__(parent)
|
||||
self._win_id = win_id
|
||||
self._tabdata = tabdata
|
||||
@ -72,7 +72,7 @@ class BrowserPage(QWebPage):
|
||||
self.error_occurred = False
|
||||
self.open_target = usertypes.ClickTarget.normal
|
||||
self._networkmanager = networkmanager.NetworkManager(
|
||||
win_id, tab_id, self)
|
||||
win_id=win_id, tab_id=tab_id, private=private, parent=self)
|
||||
self.setNetworkAccessManager(self._networkmanager)
|
||||
self.setForwardUnsupportedContent(True)
|
||||
self.reloading.connect(self._networkmanager.clear_rejected_ssl_errors)
|
||||
|
@ -55,7 +55,7 @@ class WebView(QWebView):
|
||||
scroll_pos_changed = pyqtSignal(int, int)
|
||||
shutting_down = pyqtSignal()
|
||||
|
||||
def __init__(self, win_id, tab_id, tab, parent=None):
|
||||
def __init__(self, *, win_id, tab_id, tab, private, parent=None):
|
||||
super().__init__(parent)
|
||||
if sys.platform == 'darwin' and qtutils.version_check('5.4'):
|
||||
# WORKAROUND for https://bugreports.qt.io/browse/QTBUG-42948
|
||||
@ -71,7 +71,8 @@ class WebView(QWebView):
|
||||
self._set_bg_color()
|
||||
self._tab_id = tab_id
|
||||
|
||||
page = webpage.BrowserPage(self.win_id, self._tab_id, tab.data,
|
||||
page = webpage.BrowserPage(win_id=self.win_id, tab_id=self._tab_id,
|
||||
tabdata=tab.data, private=private,
|
||||
parent=self)
|
||||
|
||||
try:
|
||||
|
@ -185,10 +185,9 @@ def data(readonly=False):
|
||||
"Encoding to use for editor."),
|
||||
|
||||
('private-browsing',
|
||||
SettingValue(typ.Bool(), 'false',
|
||||
backends=[usertypes.Backend.QtWebKit]),
|
||||
"Do not record visited pages in the history or store web page "
|
||||
"icons."),
|
||||
SettingValue(typ.Bool(), 'false'),
|
||||
"Open new windows in private browsing mode which does not record "
|
||||
"visited pages."),
|
||||
|
||||
('developer-extras',
|
||||
SettingValue(typ.Bool(), 'false',
|
||||
@ -1125,6 +1124,14 @@ def data(readonly=False):
|
||||
SettingValue(typ.QssColor(), 'black'),
|
||||
"Background color of the statusbar."),
|
||||
|
||||
('statusbar.fg.private',
|
||||
SettingValue(typ.QssColor(), '${statusbar.fg}'),
|
||||
"Foreground color of the statusbar in private browsing mode."),
|
||||
|
||||
('statusbar.bg.private',
|
||||
SettingValue(typ.QssColor(), '#666666'),
|
||||
"Background color of the statusbar in private browsing mode."),
|
||||
|
||||
('statusbar.fg.insert',
|
||||
SettingValue(typ.QssColor(), '${statusbar.fg}'),
|
||||
"Foreground color of the statusbar in insert mode."),
|
||||
@ -1141,6 +1148,16 @@ def data(readonly=False):
|
||||
SettingValue(typ.QssColor(), '${statusbar.bg}'),
|
||||
"Background color of the statusbar in command mode."),
|
||||
|
||||
('statusbar.fg.command.private',
|
||||
SettingValue(typ.QssColor(), '${statusbar.fg.private}'),
|
||||
"Foreground color of the statusbar in private browsing + command "
|
||||
"mode."),
|
||||
|
||||
('statusbar.bg.command.private',
|
||||
SettingValue(typ.QssColor(), '${statusbar.bg.private}'),
|
||||
"Background color of the statusbar in private browsing + command "
|
||||
"mode."),
|
||||
|
||||
('statusbar.fg.caret',
|
||||
SettingValue(typ.QssColor(), '${statusbar.fg}'),
|
||||
"Foreground color of the statusbar in caret mode."),
|
||||
|
@ -81,7 +81,7 @@ def get_window(via_ipc, force_window=False, force_tab=False,
|
||||
|
||||
# Otherwise, or if no window was found, create a new one
|
||||
if window is None:
|
||||
window = MainWindow()
|
||||
window = MainWindow(private=None)
|
||||
window.show()
|
||||
raise_window = True
|
||||
|
||||
@ -127,13 +127,15 @@ class MainWindow(QWidget):
|
||||
_vbox: The main QVBoxLayout.
|
||||
_commandrunner: The main CommandRunner instance.
|
||||
_overlays: Widgets shown as overlay for the current webpage.
|
||||
_private: Whether the window is in private browsing mode.
|
||||
"""
|
||||
|
||||
def __init__(self, geometry=None, parent=None):
|
||||
def __init__(self, *, private, geometry=None, parent=None):
|
||||
"""Create a new main window.
|
||||
|
||||
Args:
|
||||
geometry: The geometry to load, as a bytes-object (or None).
|
||||
private: Whether the window is in private browsing mode.
|
||||
parent: The parent the window should get.
|
||||
"""
|
||||
super().__init__(parent)
|
||||
@ -161,7 +163,14 @@ class MainWindow(QWidget):
|
||||
self._init_downloadmanager()
|
||||
self._downloadview = downloadview.DownloadView(self.win_id)
|
||||
|
||||
self.tabbed_browser = tabbedbrowser.TabbedBrowser(self.win_id)
|
||||
if config.get('general', 'private-browsing'):
|
||||
# This setting always trumps what's passed in.
|
||||
private = True
|
||||
else:
|
||||
private = bool(private)
|
||||
self._private = private
|
||||
self.tabbed_browser = tabbedbrowser.TabbedBrowser(win_id=self.win_id,
|
||||
private=private)
|
||||
objreg.register('tabbed-browser', self.tabbed_browser, scope='window',
|
||||
window=self.win_id)
|
||||
self._init_command_dispatcher()
|
||||
@ -169,7 +178,8 @@ class MainWindow(QWidget):
|
||||
# We need to set an explicit parent for StatusBar because it does some
|
||||
# show/hide magic immediately which would mean it'd show up as a
|
||||
# window.
|
||||
self.status = bar.StatusBar(self.win_id, parent=self)
|
||||
self.status = bar.StatusBar(win_id=self.win_id, private=private,
|
||||
parent=self)
|
||||
|
||||
self._add_widgets()
|
||||
self._downloadview.show()
|
||||
@ -196,15 +206,7 @@ class MainWindow(QWidget):
|
||||
self._messageview = messageview.MessageView(parent=self)
|
||||
self._add_overlay(self._messageview, self._messageview.update_geometry)
|
||||
|
||||
if geometry is not None:
|
||||
self._load_geometry(geometry)
|
||||
elif self.win_id == 0:
|
||||
self._load_state_geometry()
|
||||
else:
|
||||
self._set_default_geometry()
|
||||
log.init.debug("Initial main window geometry: {}".format(
|
||||
self.geometry()))
|
||||
|
||||
self._init_geometry(geometry)
|
||||
self._connect_signals()
|
||||
|
||||
# When we're here the statusbar might not even really exist yet, so
|
||||
@ -215,6 +217,17 @@ class MainWindow(QWidget):
|
||||
|
||||
objreg.get("app").new_window.emit(self)
|
||||
|
||||
def _init_geometry(self, geometry):
|
||||
"""Initialize the window geometry or load it from disk."""
|
||||
if geometry is not None:
|
||||
self._load_geometry(geometry)
|
||||
elif self.win_id == 0:
|
||||
self._load_state_geometry()
|
||||
else:
|
||||
self._set_default_geometry()
|
||||
log.init.debug("Initial main window geometry: {}".format(
|
||||
self.geometry()))
|
||||
|
||||
def _add_overlay(self, widget, signal, *, centered=False, padding=0):
|
||||
self._overlays.append((widget, signal, centered, padding))
|
||||
|
||||
@ -446,17 +459,15 @@ class MainWindow(QWidget):
|
||||
message_bridge.s_maybe_reset_text.connect(status.txt.maybe_reset_text)
|
||||
|
||||
# statusbar
|
||||
tabs.current_tab_changed.connect(status.prog.on_tab_changed)
|
||||
tabs.current_tab_changed.connect(status.on_tab_changed)
|
||||
|
||||
tabs.cur_progress.connect(status.prog.setValue)
|
||||
tabs.cur_load_finished.connect(status.prog.hide)
|
||||
tabs.cur_load_started.connect(status.prog.on_load_started)
|
||||
|
||||
tabs.current_tab_changed.connect(status.percentage.on_tab_changed)
|
||||
tabs.cur_scroll_perc_changed.connect(status.percentage.set_perc)
|
||||
|
||||
tabs.tab_index_changed.connect(status.tabindex.on_tab_index_changed)
|
||||
|
||||
tabs.current_tab_changed.connect(status.url.on_tab_changed)
|
||||
tabs.cur_url_changed.connect(status.url.set_url)
|
||||
tabs.cur_link_hovered.connect(status.url.set_hover_url)
|
||||
tabs.cur_load_status_changed.connect(status.url.on_load_status_changed)
|
||||
|
@ -22,6 +22,7 @@
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot, pyqtProperty, Qt, QSize, QTimer
|
||||
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QStackedLayout, QSizePolicy
|
||||
|
||||
from qutebrowser.browser import browsertab
|
||||
from qutebrowser.config import config, style
|
||||
from qutebrowser.utils import usertypes, log, objreg, utils
|
||||
from qutebrowser.mainwindow.statusbar import (command, progress, keystring,
|
||||
@ -29,7 +30,85 @@ from qutebrowser.mainwindow.statusbar import (command, progress, keystring,
|
||||
from qutebrowser.mainwindow.statusbar import text as textwidget
|
||||
|
||||
|
||||
CaretMode = usertypes.enum('CaretMode', ['off', 'on', 'selection'])
|
||||
class ColorFlags:
|
||||
|
||||
"""Flags which change the appearance of the statusbar.
|
||||
|
||||
Attributes:
|
||||
prompt: If we're currently in prompt-mode.
|
||||
insert: If we're currently in insert mode.
|
||||
command: If we're currently in command mode.
|
||||
mode: The current caret mode (CaretMode.off/.on/.selection).
|
||||
private: Whether this window is in private browsing mode.
|
||||
"""
|
||||
|
||||
CaretMode = usertypes.enum('CaretMode', ['off', 'on', 'selection'])
|
||||
|
||||
def __init__(self):
|
||||
self.prompt = False
|
||||
self.insert = False
|
||||
self.command = False
|
||||
self.caret = self.CaretMode.off
|
||||
self.private = False
|
||||
|
||||
def to_stringlist(self):
|
||||
"""Get a string list of set flags used in the stylesheet.
|
||||
|
||||
This also combines flags in ways they're used in the sheet.
|
||||
"""
|
||||
strings = []
|
||||
if self.prompt:
|
||||
strings.append('prompt')
|
||||
if self.insert:
|
||||
strings.append('insert')
|
||||
if self.command:
|
||||
strings.append('command')
|
||||
if self.private:
|
||||
strings.append('private')
|
||||
|
||||
if self.private and self.command:
|
||||
strings.append('private-command')
|
||||
|
||||
if self.caret == self.CaretMode.on:
|
||||
strings.append('caret')
|
||||
elif self.caret == self.CaretMode.selection:
|
||||
strings.append('caret-selection')
|
||||
else:
|
||||
assert self.caret == self.CaretMode.off
|
||||
|
||||
return strings
|
||||
|
||||
|
||||
def _generate_stylesheet():
|
||||
flags = [
|
||||
('private', 'statusbar.{}.private'),
|
||||
('caret', 'statusbar.{}.caret'),
|
||||
('caret-selection', 'statusbar.{}.caret-selection'),
|
||||
('prompt', 'prompts.{}'),
|
||||
('insert', 'statusbar.{}.insert'),
|
||||
('command', 'statusbar.{}.command'),
|
||||
('private-command', 'statusbar.{}.command.private'),
|
||||
]
|
||||
stylesheet = """
|
||||
QWidget#StatusBar,
|
||||
QWidget#StatusBar QLabel,
|
||||
QWidget#StatusBar QLineEdit {
|
||||
font: {{ font['statusbar'] }};
|
||||
background-color: {{ color['statusbar.bg'] }};
|
||||
color: {{ color['statusbar.fg'] }};
|
||||
}
|
||||
"""
|
||||
for flag, option in flags:
|
||||
stylesheet += """
|
||||
QWidget#StatusBar[color_flags~="%s"],
|
||||
QWidget#StatusBar[color_flags~="%s"] QLabel,
|
||||
QWidget#StatusBar[color_flags~="%s"] QLineEdit {
|
||||
color: {{ color['%s'] }};
|
||||
background-color: {{ color['%s'] }};
|
||||
}
|
||||
""" % (flag, flag, flag, # flake8: disable=S001
|
||||
option.format('fg'), option.format('bg'))
|
||||
return stylesheet
|
||||
|
||||
|
||||
class StatusBar(QWidget):
|
||||
@ -49,27 +128,6 @@ class StatusBar(QWidget):
|
||||
_page_fullscreen: Whether the webpage (e.g. a video) is shown
|
||||
fullscreen.
|
||||
|
||||
Class attributes:
|
||||
_prompt_active: If we're currently in prompt-mode.
|
||||
|
||||
For some reason we need to have this as class attribute
|
||||
so pyqtProperty works correctly.
|
||||
|
||||
_insert_active: If we're currently in insert mode.
|
||||
|
||||
For some reason we need to have this as class attribute
|
||||
so pyqtProperty works correctly.
|
||||
|
||||
_command_active: If we're currently in command mode.
|
||||
|
||||
For some reason we need to have this as class
|
||||
attribute so pyqtProperty works correctly.
|
||||
|
||||
_caret_mode: The current caret mode (off/on/selection).
|
||||
|
||||
For some reason we need to have this as class attribute
|
||||
so pyqtProperty works correctly.
|
||||
|
||||
Signals:
|
||||
resized: Emitted when the statusbar has resized, so the completion
|
||||
widget can adjust its size to it.
|
||||
@ -82,59 +140,11 @@ class StatusBar(QWidget):
|
||||
resized = pyqtSignal('QRect')
|
||||
moved = pyqtSignal('QPoint')
|
||||
_severity = None
|
||||
_prompt_active = False
|
||||
_insert_active = False
|
||||
_command_active = False
|
||||
_caret_mode = CaretMode.off
|
||||
_color_flags = []
|
||||
|
||||
STYLESHEET = """
|
||||
STYLESHEET = _generate_stylesheet()
|
||||
|
||||
QWidget#StatusBar,
|
||||
QWidget#StatusBar QLabel,
|
||||
QWidget#StatusBar QLineEdit {
|
||||
font: {{ font['statusbar'] }};
|
||||
background-color: {{ color['statusbar.bg'] }};
|
||||
color: {{ color['statusbar.fg'] }};
|
||||
}
|
||||
|
||||
QWidget#StatusBar[caret_mode="on"],
|
||||
QWidget#StatusBar[caret_mode="on"] QLabel,
|
||||
QWidget#StatusBar[caret_mode="on"] QLineEdit {
|
||||
color: {{ color['statusbar.fg.caret'] }};
|
||||
background-color: {{ color['statusbar.bg.caret'] }};
|
||||
}
|
||||
|
||||
QWidget#StatusBar[caret_mode="selection"],
|
||||
QWidget#StatusBar[caret_mode="selection"] QLabel,
|
||||
QWidget#StatusBar[caret_mode="selection"] QLineEdit {
|
||||
color: {{ color['statusbar.fg.caret-selection'] }};
|
||||
background-color: {{ color['statusbar.bg.caret-selection'] }};
|
||||
}
|
||||
|
||||
QWidget#StatusBar[prompt_active="true"],
|
||||
QWidget#StatusBar[prompt_active="true"] QLabel,
|
||||
QWidget#StatusBar[prompt_active="true"] QLineEdit {
|
||||
color: {{ color['prompts.fg'] }};
|
||||
background-color: {{ color['prompts.bg'] }};
|
||||
}
|
||||
|
||||
QWidget#StatusBar[insert_active="true"],
|
||||
QWidget#StatusBar[insert_active="true"] QLabel,
|
||||
QWidget#StatusBar[insert_active="true"] QLineEdit {
|
||||
color: {{ color['statusbar.fg.insert'] }};
|
||||
background-color: {{ color['statusbar.bg.insert'] }};
|
||||
}
|
||||
|
||||
QWidget#StatusBar[command_active="true"],
|
||||
QWidget#StatusBar[command_active="true"] QLabel,
|
||||
QWidget#StatusBar[command_active="true"] QLineEdit {
|
||||
color: {{ color['statusbar.fg.command'] }};
|
||||
background-color: {{ color['statusbar.bg.command'] }};
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, win_id, parent=None):
|
||||
def __init__(self, *, win_id, private, parent=None):
|
||||
super().__init__(parent)
|
||||
objreg.register('statusbar', self, scope='window', window=win_id)
|
||||
self.setObjectName(self.__class__.__name__)
|
||||
@ -146,6 +156,8 @@ class StatusBar(QWidget):
|
||||
self._win_id = win_id
|
||||
self._option = None
|
||||
self._page_fullscreen = False
|
||||
self._color_flags = ColorFlags()
|
||||
self._color_flags.private = private
|
||||
|
||||
self._hbox = QHBoxLayout(self)
|
||||
self.set_hbox_padding()
|
||||
@ -156,7 +168,7 @@ class StatusBar(QWidget):
|
||||
self._hbox.addLayout(self._stack)
|
||||
self._stack.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
self.cmd = command.Command(win_id)
|
||||
self.cmd = command.Command(private=private, win_id=win_id)
|
||||
self._stack.addWidget(self.cmd)
|
||||
objreg.register('status-command', self.cmd, scope='window',
|
||||
window=win_id)
|
||||
@ -206,25 +218,10 @@ class StatusBar(QWidget):
|
||||
padding = config.get('ui', 'statusbar-padding')
|
||||
self._hbox.setContentsMargins(padding.left, 0, padding.right, 0)
|
||||
|
||||
@pyqtProperty(bool)
|
||||
def prompt_active(self):
|
||||
"""Getter for self.prompt_active, so it can be used as Qt property."""
|
||||
return self._prompt_active
|
||||
|
||||
@pyqtProperty(bool)
|
||||
def command_active(self):
|
||||
"""Getter for self.command_active, so it can be used as Qt property."""
|
||||
return self._command_active
|
||||
|
||||
@pyqtProperty(bool)
|
||||
def insert_active(self):
|
||||
"""Getter for self.insert_active, so it can be used as Qt property."""
|
||||
return self._insert_active
|
||||
|
||||
@pyqtProperty(str)
|
||||
def caret_mode(self):
|
||||
"""Getter for self._caret_mode, so it can be used as Qt property."""
|
||||
return self._caret_mode.name
|
||||
@pyqtProperty('QStringList')
|
||||
def color_flags(self):
|
||||
"""Getter for self.color_flags, so it can be used as Qt property."""
|
||||
return self._color_flags.to_stringlist()
|
||||
|
||||
def set_mode_active(self, mode, val):
|
||||
"""Setter for self.{insert,command,caret}_active.
|
||||
@ -233,28 +230,28 @@ class StatusBar(QWidget):
|
||||
updated by Qt properly.
|
||||
"""
|
||||
if mode == usertypes.KeyMode.insert:
|
||||
log.statusbar.debug("Setting insert_active to {}".format(val))
|
||||
self._insert_active = val
|
||||
log.statusbar.debug("Setting insert flag to {}".format(val))
|
||||
self._color_flags.insert = val
|
||||
if mode == usertypes.KeyMode.command:
|
||||
log.statusbar.debug("Setting command_active to {}".format(val))
|
||||
self._command_active = val
|
||||
log.statusbar.debug("Setting command flag to {}".format(val))
|
||||
self._color_flags.command = val
|
||||
elif mode in [usertypes.KeyMode.prompt, usertypes.KeyMode.yesno]:
|
||||
log.statusbar.debug("Setting prompt_active to {}".format(val))
|
||||
self._prompt_active = val
|
||||
log.statusbar.debug("Setting prompt flag to {}".format(val))
|
||||
self._color_flags.prompt = val
|
||||
elif mode == usertypes.KeyMode.caret:
|
||||
tab = objreg.get('tabbed-browser', scope='window',
|
||||
window=self._win_id).currentWidget()
|
||||
log.statusbar.debug("Setting caret_mode - val {}, selection "
|
||||
log.statusbar.debug("Setting caret flag - val {}, selection "
|
||||
"{}".format(val, tab.caret.selection_enabled))
|
||||
if val:
|
||||
if tab.caret.selection_enabled:
|
||||
self._set_mode_text("{} selection".format(mode.name))
|
||||
self._caret_mode = CaretMode.selection
|
||||
self._color_flags.caret = ColorFlags.CaretMode.selection
|
||||
else:
|
||||
self._set_mode_text(mode.name)
|
||||
self._caret_mode = CaretMode.on
|
||||
self._color_flags.caret = ColorFlags.CaretMode.on
|
||||
else:
|
||||
self._caret_mode = CaretMode.off
|
||||
self._color_flags.caret = ColorFlags.CaretMode.off
|
||||
self.setStyleSheet(style.get_stylesheet(self.STYLESHEET))
|
||||
|
||||
def _set_mode_text(self, mode):
|
||||
@ -314,6 +311,14 @@ class StatusBar(QWidget):
|
||||
self._page_fullscreen = on
|
||||
self.maybe_hide()
|
||||
|
||||
@pyqtSlot(browsertab.AbstractTab)
|
||||
def on_tab_changed(self, tab):
|
||||
"""Notify sub-widgets when the tab has been changed."""
|
||||
self.url.on_tab_changed(tab)
|
||||
self.prog.on_tab_changed(tab)
|
||||
self.percentage.on_tab_changed(tab)
|
||||
assert tab.private == self._color_flags.private
|
||||
|
||||
def resizeEvent(self, e):
|
||||
"""Extend resizeEvent of QWidget to emit a resized signal afterwards.
|
||||
|
||||
|
@ -54,14 +54,14 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
||||
show_cmd = pyqtSignal()
|
||||
hide_cmd = pyqtSignal()
|
||||
|
||||
def __init__(self, win_id, parent=None):
|
||||
misc.CommandLineEdit.__init__(self, parent)
|
||||
def __init__(self, *, win_id, private, parent=None):
|
||||
misc.CommandLineEdit.__init__(self, parent=parent)
|
||||
misc.MinimalLineEditMixin.__init__(self)
|
||||
self._win_id = win_id
|
||||
command_history = objreg.get('command-history')
|
||||
self.history.handle_private_mode = True
|
||||
self.history.history = command_history.data
|
||||
self.history.changed.connect(command_history.changed)
|
||||
if not private:
|
||||
command_history = objreg.get('command-history')
|
||||
self.history.history = command_history.data
|
||||
self.history.changed.connect(command_history.changed)
|
||||
self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Ignored)
|
||||
self.cursorPositionChanged.connect(self.update_completion)
|
||||
self.textChanged.connect(self.update_completion)
|
||||
|
@ -21,7 +21,6 @@
|
||||
|
||||
from PyQt5.QtCore import pyqtSlot
|
||||
|
||||
from qutebrowser.browser import browsertab
|
||||
from qutebrowser.mainwindow.statusbar import textbase
|
||||
|
||||
|
||||
@ -51,7 +50,6 @@ class Percentage(textbase.TextBase):
|
||||
else:
|
||||
self.setText('[{:2}%]'.format(y))
|
||||
|
||||
@pyqtSlot(browsertab.AbstractTab)
|
||||
def on_tab_changed(self, tab):
|
||||
"""Update scroll position when tab changed."""
|
||||
self.set_perc(*tab.scroller.pos_perc())
|
||||
|
@ -22,7 +22,6 @@
|
||||
from PyQt5.QtCore import pyqtSlot, QSize
|
||||
from PyQt5.QtWidgets import QProgressBar, QSizePolicy
|
||||
|
||||
from qutebrowser.browser import browsertab
|
||||
from qutebrowser.config import style
|
||||
from qutebrowser.utils import utils, usertypes
|
||||
|
||||
@ -60,7 +59,6 @@ class Progress(QProgressBar):
|
||||
self.setValue(0)
|
||||
self.show()
|
||||
|
||||
@pyqtSlot(browsertab.AbstractTab)
|
||||
def on_tab_changed(self, tab):
|
||||
"""Set the correct value when the current tab changed."""
|
||||
if self is None: # pragma: no branch
|
||||
|
@ -21,7 +21,6 @@
|
||||
|
||||
from PyQt5.QtCore import pyqtSlot, pyqtProperty, Qt, QUrl
|
||||
|
||||
from qutebrowser.browser import browsertab
|
||||
from qutebrowser.mainwindow.statusbar import textbase
|
||||
from qutebrowser.config import style
|
||||
from qutebrowser.utils import usertypes, urlutils
|
||||
@ -165,7 +164,6 @@ class UrlText(textbase.TextBase):
|
||||
self._hover_url = None
|
||||
self._update_url()
|
||||
|
||||
@pyqtSlot(browsertab.AbstractTab)
|
||||
def on_tab_changed(self, tab):
|
||||
"""Update URL if the tab changed."""
|
||||
self._hover_url = None
|
||||
|
@ -68,6 +68,7 @@ class TabbedBrowser(tabwidget.TabWidget):
|
||||
_local_marks: Jump markers local to each page
|
||||
_global_marks: Jump markers used across all pages
|
||||
default_window_icon: The qutebrowser window icon
|
||||
private: Whether private browsing is on for this window.
|
||||
|
||||
Signals:
|
||||
cur_progress: Progress of the current tab changed (load_progress).
|
||||
@ -100,7 +101,7 @@ class TabbedBrowser(tabwidget.TabWidget):
|
||||
new_tab = pyqtSignal(browsertab.AbstractTab, int)
|
||||
page_fullscreen_requested = pyqtSignal(bool)
|
||||
|
||||
def __init__(self, win_id, parent=None):
|
||||
def __init__(self, *, win_id, private, parent=None):
|
||||
super().__init__(win_id, parent)
|
||||
self._win_id = win_id
|
||||
self._tab_insert_idx_left = 0
|
||||
@ -118,6 +119,7 @@ class TabbedBrowser(tabwidget.TabWidget):
|
||||
self._local_marks = {}
|
||||
self._global_marks = {}
|
||||
self.default_window_icon = self.window().windowIcon()
|
||||
self.private = private
|
||||
objreg.get('config').changed.connect(self.update_favicons)
|
||||
objreg.get('config').changed.connect(self.update_window_title)
|
||||
objreg.get('config').changed.connect(self.update_tab_titles)
|
||||
@ -205,7 +207,9 @@ class TabbedBrowser(tabwidget.TabWidget):
|
||||
tab.renderer_process_terminated.connect(
|
||||
functools.partial(self._on_renderer_process_terminated, tab))
|
||||
tab.new_tab_requested.connect(self.tabopen)
|
||||
tab.add_history_item.connect(objreg.get('web-history').add_from_tab)
|
||||
if not self.private:
|
||||
web_history = objreg.get('web-history')
|
||||
tab.add_history_item.connect(web_history.add_from_tab)
|
||||
tab.fullscreen_requested.connect(self.page_fullscreen_requested)
|
||||
tab.fullscreen_requested.connect(
|
||||
self.tabBar().on_page_fullscreen_requested)
|
||||
@ -399,13 +403,14 @@ class TabbedBrowser(tabwidget.TabWidget):
|
||||
if (config.get('tabs', 'tabs-are-windows') and self.count() > 0 and
|
||||
not ignore_tabs_are_windows):
|
||||
from qutebrowser.mainwindow import mainwindow
|
||||
window = mainwindow.MainWindow()
|
||||
window = mainwindow.MainWindow(private=self.private)
|
||||
window.show()
|
||||
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||
window=window.win_id)
|
||||
return tabbed_browser.tabopen(url, background, explicit)
|
||||
|
||||
tab = browsertab.create(win_id=self._win_id, parent=self)
|
||||
tab = browsertab.create(win_id=self._win_id, private=self.private,
|
||||
parent=self)
|
||||
self._connect_tab_signals(tab)
|
||||
|
||||
if idx is None:
|
||||
|
@ -21,7 +21,6 @@
|
||||
|
||||
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject
|
||||
|
||||
from qutebrowser.config import config
|
||||
from qutebrowser.utils import usertypes, log
|
||||
|
||||
|
||||
@ -44,7 +43,6 @@ class History(QObject):
|
||||
"""Command history.
|
||||
|
||||
Attributes:
|
||||
handle_private_mode: Whether to ignore history in private mode.
|
||||
history: A list of executed commands, with newer commands at the end.
|
||||
_tmphist: Temporary history for history browsing (as NeighborList)
|
||||
|
||||
@ -54,14 +52,13 @@ class History(QObject):
|
||||
|
||||
changed = pyqtSignal()
|
||||
|
||||
def __init__(self, history=None, parent=None):
|
||||
def __init__(self, *, history=None, parent=None):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
history: The initial history to set.
|
||||
"""
|
||||
super().__init__(parent)
|
||||
self.handle_private_mode = False
|
||||
self._tmphist = None
|
||||
if history is None:
|
||||
self.history = []
|
||||
@ -129,9 +126,6 @@ class History(QObject):
|
||||
Args:
|
||||
text: The text to append.
|
||||
"""
|
||||
if (self.handle_private_mode and
|
||||
config.get('general', 'private-browsing')):
|
||||
return
|
||||
if not self.history or text != self.history[-1]:
|
||||
self.history.append(text)
|
||||
self.changed.emit()
|
||||
|
@ -50,7 +50,7 @@ class ConsoleLineEdit(miscwidgets.CommandLineEdit):
|
||||
Args:
|
||||
_namespace: The local namespace of the interpreter.
|
||||
"""
|
||||
super().__init__(parent)
|
||||
super().__init__(parent=parent)
|
||||
self.update_font()
|
||||
objreg.get('config').changed.connect(self.update_font)
|
||||
self._history = cmdhistory.History(parent=self)
|
||||
|
@ -69,7 +69,7 @@ class CommandLineEdit(QLineEdit):
|
||||
_promptlen: The length of the current prompt.
|
||||
"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
def __init__(self, *, parent=None):
|
||||
super().__init__(parent)
|
||||
self.history = cmdhistory.History(parent=self)
|
||||
self._validator = _CommandValidator(self)
|
||||
|
@ -213,7 +213,7 @@ class SessionManager(QObject):
|
||||
data['history'].append(item_data)
|
||||
return data
|
||||
|
||||
def _save_all(self, *, only_window=None):
|
||||
def _save_all(self, *, only_window=None, with_private=False):
|
||||
"""Get a dict with data for all windows/tabs."""
|
||||
data = {'windows': []}
|
||||
if only_window is not None:
|
||||
@ -221,7 +221,7 @@ class SessionManager(QObject):
|
||||
else:
|
||||
winlist = objreg.window_registry
|
||||
|
||||
for win_id in winlist:
|
||||
for win_id in sorted(winlist):
|
||||
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||
window=win_id)
|
||||
main_window = objreg.get('main-window', scope='window',
|
||||
@ -231,12 +231,17 @@ class SessionManager(QObject):
|
||||
if sip.isdeleted(main_window):
|
||||
continue
|
||||
|
||||
if tabbed_browser.private and not with_private:
|
||||
continue
|
||||
|
||||
win_data = {}
|
||||
active_window = QApplication.instance().activeWindow()
|
||||
if getattr(active_window, 'win_id', None) == win_id:
|
||||
win_data['active'] = True
|
||||
win_data['geometry'] = bytes(main_window.saveGeometry())
|
||||
win_data['tabs'] = []
|
||||
if tabbed_browser.private:
|
||||
win_data['private'] = True
|
||||
for i, tab in enumerate(tabbed_browser.widgets()):
|
||||
active = i == tabbed_browser.currentIndex()
|
||||
win_data['tabs'].append(self._save_tab(tab, active))
|
||||
@ -260,7 +265,7 @@ class SessionManager(QObject):
|
||||
return name
|
||||
|
||||
def save(self, name, last_window=False, load_next_time=False,
|
||||
only_window=None):
|
||||
only_window=None, with_private=False):
|
||||
"""Save a named session.
|
||||
|
||||
Args:
|
||||
@ -270,6 +275,7 @@ class SessionManager(QObject):
|
||||
instead of the currently open state.
|
||||
load_next_time: If set, prepares this session to be load next time.
|
||||
only_window: If set, only tabs in the specified window is saved.
|
||||
with_private: Include private windows.
|
||||
|
||||
Return:
|
||||
The name of the saved session.
|
||||
@ -284,7 +290,8 @@ class SessionManager(QObject):
|
||||
log.sessions.error("last_window_session is None while saving!")
|
||||
return
|
||||
else:
|
||||
data = self._save_all(only_window=only_window)
|
||||
data = self._save_all(only_window=only_window,
|
||||
with_private=with_private)
|
||||
log.sessions.vdebug("Saving data: {}".format(data))
|
||||
try:
|
||||
with qtutils.savefile_open(path) as f:
|
||||
@ -379,7 +386,8 @@ class SessionManager(QObject):
|
||||
raise SessionError(e)
|
||||
log.sessions.debug("Loading session {} from {}...".format(name, path))
|
||||
for win in data['windows']:
|
||||
window = mainwindow.MainWindow(geometry=win['geometry'])
|
||||
window = mainwindow.MainWindow(geometry=win['geometry'],
|
||||
private=win.get('private', None))
|
||||
window.show()
|
||||
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||
window=window.win_id)
|
||||
@ -443,8 +451,10 @@ class SessionManager(QObject):
|
||||
@cmdutils.register(name=['session-save', 'w'], instance='session-manager')
|
||||
@cmdutils.argument('name', completion=usertypes.Completion.sessions)
|
||||
@cmdutils.argument('win_id', win_id=True)
|
||||
@cmdutils.argument('with_private', flag='p')
|
||||
def session_save(self, name: str = default, current=False, quiet=False,
|
||||
force=False, only_active_window=False, win_id=None):
|
||||
force=False, only_active_window=False, with_private=False,
|
||||
win_id=None):
|
||||
"""Save a session.
|
||||
|
||||
Args:
|
||||
@ -454,6 +464,7 @@ class SessionManager(QObject):
|
||||
quiet: Don't show confirmation message.
|
||||
force: Force saving internal sessions (starting with an underline).
|
||||
only_active_window: Saves only tabs of the currently active window.
|
||||
with_private: Include private windows.
|
||||
"""
|
||||
if name is not default and name.startswith('_') and not force:
|
||||
raise cmdexc.CommandError("{} is an internal session, use --force "
|
||||
@ -465,9 +476,10 @@ class SessionManager(QObject):
|
||||
assert not name.startswith('_')
|
||||
try:
|
||||
if only_active_window:
|
||||
name = self.save(name, only_window=win_id)
|
||||
name = self.save(name, only_window=win_id,
|
||||
with_private=with_private)
|
||||
else:
|
||||
name = self.save(name)
|
||||
name = self.save(name, with_private=with_private)
|
||||
except SessionError as e:
|
||||
raise cmdexc.CommandError("Error while saving session: {}"
|
||||
.format(e))
|
||||
|
@ -54,9 +54,7 @@ def whitelist_generator():
|
||||
attr)
|
||||
|
||||
# PyQt properties
|
||||
for attr in ['prompt_active', 'command_active', 'insert_active',
|
||||
'caret_mode']:
|
||||
yield 'qutebrowser.mainwindow.statusbar.bar.StatusBar.' + attr
|
||||
yield 'qutebrowser.mainwindow.statusbar.bar.StatusBar.color_flags'
|
||||
yield 'qutebrowser.mainwindow.statusbar.url.UrlText.urltype'
|
||||
|
||||
# Not used yet, but soon (or when debugging)
|
||||
|
@ -177,21 +177,25 @@ def pdfjs_available():
|
||||
def open_path(quteproc, httpbin, path):
|
||||
"""Open a URL.
|
||||
|
||||
If used like "When I open ... in a new tab", the URL is opened in a new
|
||||
tab. With "... in a new window", it's opened in a new window. With
|
||||
"... as a URL", it's opened according to new-instance-open-target.
|
||||
- If used like "When I open ... in a new tab", the URL is opened in a new
|
||||
tab.
|
||||
- With "... in a new window", it's opened in a new window.
|
||||
- With "... in a private window" it's opened in a new private window.
|
||||
- With "... as a URL", it's opened according to new-instance-open-target.
|
||||
"""
|
||||
path = path.replace('(port)', str(httpbin.port))
|
||||
|
||||
new_tab = False
|
||||
new_bg_tab = False
|
||||
new_window = False
|
||||
private = False
|
||||
as_url = False
|
||||
wait = True
|
||||
|
||||
new_tab_suffix = ' in a new tab'
|
||||
new_bg_tab_suffix = ' in a new background tab'
|
||||
new_window_suffix = ' in a new window'
|
||||
private_suffix = ' in a private window'
|
||||
do_not_wait_suffix = ' without waiting'
|
||||
as_url_suffix = ' as a URL'
|
||||
|
||||
@ -205,6 +209,9 @@ def open_path(quteproc, httpbin, path):
|
||||
elif path.endswith(new_window_suffix):
|
||||
path = path[:-len(new_window_suffix)]
|
||||
new_window = True
|
||||
elif path.endswith(private_suffix):
|
||||
path = path[:-len(private_suffix)]
|
||||
private = True
|
||||
elif path.endswith(as_url_suffix):
|
||||
path = path[:-len(as_url_suffix)]
|
||||
as_url = True
|
||||
@ -215,7 +222,8 @@ def open_path(quteproc, httpbin, path):
|
||||
break
|
||||
|
||||
quteproc.open_path(path, new_tab=new_tab, new_bg_tab=new_bg_tab,
|
||||
new_window=new_window, as_url=as_url, wait=wait)
|
||||
new_window=new_window, private=private, as_url=as_url,
|
||||
wait=wait)
|
||||
|
||||
|
||||
@bdd.when(bdd.parsers.parse("I set {sect} -> {opt} to {value}"))
|
||||
|
@ -569,26 +569,6 @@ Feature: Various utility commands.
|
||||
And I run :command-accept
|
||||
Then the message "Hello World" should be shown
|
||||
|
||||
## https://github.com/qutebrowser/qutebrowser/issues/1219
|
||||
|
||||
@qtwebengine_todo: private browsing is not implemented yet @qtwebkit_ng_skip: private browsing is not implemented yet
|
||||
Scenario: Sharing cookies with private browsing
|
||||
When I set general -> private-browsing to true
|
||||
And I open cookies/set?qute-test=42 without waiting
|
||||
And I wait until cookies is loaded
|
||||
And I open cookies in a new tab
|
||||
And I set general -> private-browsing to false
|
||||
Then the cookie qute-test should be set to 42
|
||||
|
||||
## https://github.com/qutebrowser/qutebrowser/issues/1742
|
||||
|
||||
@qtwebengine_todo: private browsing is not implemented yet @qtwebkit_ng_xfail: private browsing is not implemented yet
|
||||
Scenario: Private browsing is activated in QtWebKit without restart
|
||||
When I set general -> private-browsing to true
|
||||
And I open data/javascript/localstorage.html
|
||||
And I set general -> private-browsing to false
|
||||
Then the page should contain the plaintext "Local storage status: not working"
|
||||
|
||||
@no_xvfb
|
||||
Scenario: :window-only
|
||||
Given I run :tab-only
|
||||
@ -681,20 +661,6 @@ Feature: Various utility commands.
|
||||
And I run :command-accept
|
||||
Then the error "No command given" should be shown
|
||||
|
||||
@qtwebengine_todo: private browsing is not implemented yet @qtwebkit_ng_skip: private browsing is not implemented yet
|
||||
Scenario: Calling previous command with private-browsing mode
|
||||
When I run :set-cmd-text :message-info blah
|
||||
And I run :command-accept
|
||||
And I set general -> private-browsing to true
|
||||
And I run :set-cmd-text :message-error "This should only be shown once"
|
||||
And I run :command-accept
|
||||
And I wait for the error "This should only be shown once"
|
||||
And I run :set-cmd-text :
|
||||
And I run :command-history-prev
|
||||
And I run :command-accept
|
||||
And I set general -> private-browsing to false
|
||||
Then the message "blah" should be shown
|
||||
|
||||
## Modes blacklisted for :enter-mode
|
||||
|
||||
Scenario: Trying to enter command mode with :enter-mode
|
||||
|
@ -33,7 +33,7 @@ Feature: Opening pages
|
||||
|
||||
Scenario: :open with -t and -b
|
||||
When I run :open -t -b foo.bar
|
||||
Then the error "Only one of -t/-b/-w can be given!" should be shown
|
||||
Then the error "Only one of -t/-b/-w/-p can be given!" should be shown
|
||||
|
||||
Scenario: Searching with :open
|
||||
When I set general -> auto-search to naive
|
||||
|
118
tests/end2end/features/private.feature
Normal file
118
tests/end2end/features/private.feature
Normal file
@ -0,0 +1,118 @@
|
||||
# vim: ft=cucumber fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
Feature: Using private browsing
|
||||
|
||||
Background:
|
||||
Given I open about:blank
|
||||
And I clean up open tabs
|
||||
|
||||
@qtwebkit_ng_xfail: private browsing is not implemented yet
|
||||
Scenario: Opening new tab in private window
|
||||
When I open about:blank in a private window
|
||||
And I run :window-only
|
||||
And I open data/javascript/localstorage.html in a new tab
|
||||
Then the page should contain the plaintext "Local storage status: not working"
|
||||
|
||||
@qtwebkit_ng_xfail: private browsing is not implemented yet
|
||||
Scenario: Opening new tab in private window with :navigate next
|
||||
When I open data/navigate in a private window
|
||||
And I run :window-only
|
||||
And I run :navigate -t next
|
||||
And I wait until data/navigate/next.html is loaded
|
||||
And I open data/javascript/localstorage.html
|
||||
Then the page should contain the plaintext "Local storage status: not working"
|
||||
|
||||
Scenario: Using command history in a new private browsing window
|
||||
When I run :set-cmd-text :message-info "Hello World"
|
||||
And I run :command-accept
|
||||
And I open about:blank in a private window
|
||||
And I run :set-cmd-text :message-error "This should only be shown once"
|
||||
And I run :command-accept
|
||||
And I wait for the error "This should only be shown once"
|
||||
And I run :close
|
||||
And I run :set-cmd-text :
|
||||
And I run :command-history-prev
|
||||
And I run :command-accept
|
||||
# Then the error should not be shown again
|
||||
|
||||
## https://github.com/qutebrowser/qutebrowser/issues/1219
|
||||
|
||||
@qtwebkit_ng_skip: private browsing is not implemented yet
|
||||
Scenario: Sharing cookies with private browsing
|
||||
When I open cookies/set?qute-test=42 without waiting in a private window
|
||||
And I wait until cookies is loaded
|
||||
And I open cookies in a new tab
|
||||
And I set general -> private-browsing to false
|
||||
Then the cookie qute-test should be set to 42
|
||||
|
||||
Scenario: Opening private window with :navigate increment
|
||||
# Private window handled in commands.py
|
||||
When I open data/numbers/1.txt in a private window
|
||||
And I run :window-only
|
||||
And I run :navigate -w increment
|
||||
And I wait until data/numbers/2.txt is loaded
|
||||
Then the session should look like:
|
||||
windows:
|
||||
- private: True
|
||||
tabs:
|
||||
- history:
|
||||
- url: http://localhost:*/data/numbers/1.txt
|
||||
- private: True
|
||||
tabs:
|
||||
- history:
|
||||
- url: http://localhost:*/data/numbers/2.txt
|
||||
|
||||
Scenario: Opening private window with :navigate next
|
||||
# Private window handled in navigate.py
|
||||
When I open data/navigate in a private window
|
||||
And I run :window-only
|
||||
And I run :navigate -w next
|
||||
And I wait until data/navigate/next.html is loaded
|
||||
Then the session should look like:
|
||||
windows:
|
||||
- private: True
|
||||
tabs:
|
||||
- history:
|
||||
- url: http://localhost:*/data/navigate
|
||||
- private: True
|
||||
tabs:
|
||||
- history:
|
||||
- url: http://localhost:*/data/navigate/next.html
|
||||
|
||||
Scenario: Opening private window with :tab-clone
|
||||
When I open data/hello.txt in a private window
|
||||
And I run :window-only
|
||||
And I run :tab-clone -w
|
||||
And I wait until data/hello.txt is loaded
|
||||
Then the session should look like:
|
||||
windows:
|
||||
- private: True
|
||||
tabs:
|
||||
- history:
|
||||
- url: http://localhost:*/data/hello.txt
|
||||
- private: True
|
||||
tabs:
|
||||
- history:
|
||||
- url: http://localhost:*/data/hello.txt
|
||||
|
||||
Scenario: Opening private window via :click-element
|
||||
When I open data/click_element.html in a private window
|
||||
And I run :window-only
|
||||
And I run :click-element --target window id link
|
||||
And I wait until data/hello.txt is loaded
|
||||
Then the session should look like:
|
||||
windows:
|
||||
- private: True
|
||||
tabs:
|
||||
- history:
|
||||
- url: http://localhost:*/data/click_element.html
|
||||
- private: True
|
||||
tabs:
|
||||
- history:
|
||||
- url: http://localhost:*/data/hello.txt
|
||||
|
||||
Scenario: Skipping private window when saving session
|
||||
When I open data/hello.txt in a private window
|
||||
And I run :session-save (tmpdir)/session.yml
|
||||
And I wait for "Saved session */session.yml." in the log
|
||||
Then the file session.yml should not contain "hello.txt"
|
@ -18,7 +18,6 @@
|
||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
import json
|
||||
import os.path
|
||||
import subprocess
|
||||
|
||||
@ -57,18 +56,6 @@ def update_documentation():
|
||||
subprocess.call([sys.executable, update_script])
|
||||
|
||||
|
||||
@bdd.then(bdd.parsers.parse('the cookie {name} should be set to {value}'))
|
||||
def check_cookie(quteproc, name, value):
|
||||
"""Check if a given cookie is set correctly.
|
||||
|
||||
This assumes we're on the httpbin cookies page.
|
||||
"""
|
||||
content = quteproc.get_content()
|
||||
data = json.loads(content)
|
||||
print(data)
|
||||
assert data['cookies'][name] == value
|
||||
|
||||
|
||||
@bdd.then(bdd.parsers.parse('the PDF {filename} should exist in the tmpdir'))
|
||||
def pdf_exists(quteproc, tmpdir, filename):
|
||||
path = tmpdir / filename
|
||||
|
41
tests/end2end/features/test_private_bdd.py
Normal file
41
tests/end2end/features/test_private_bdd.py
Normal file
@ -0,0 +1,41 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
# qutebrowser is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# qutebrowser is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import json
|
||||
|
||||
import pytest_bdd as bdd
|
||||
bdd.scenarios('private.feature')
|
||||
|
||||
|
||||
@bdd.then(bdd.parsers.parse('the cookie {name} should be set to {value}'))
|
||||
def check_cookie(quteproc, name, value):
|
||||
"""Check if a given cookie is set correctly.
|
||||
|
||||
This assumes we're on the httpbin cookies page.
|
||||
"""
|
||||
content = quteproc.get_content()
|
||||
data = json.loads(content)
|
||||
print(data)
|
||||
assert data['cookies'][name] == value
|
||||
|
||||
|
||||
@bdd.then(bdd.parsers.parse('the file {name} should not contain "{text}"'))
|
||||
def check_not_contain(tmpdir, name, text):
|
||||
path = tmpdir / name
|
||||
assert text not in path.read()
|
@ -76,7 +76,7 @@ Feature: quickmarks and bookmarks
|
||||
|
||||
Scenario: Loading a bookmark with -t and -b
|
||||
When I run :bookmark-load -t -b about:blank
|
||||
Then the error "Only one of -t/-b/-w can be given!" should be shown
|
||||
Then the error "Only one of -t/-b/-w/-p can be given!" should be shown
|
||||
|
||||
Scenario: Deleting a bookmark which does not exist
|
||||
When I run :bookmark-del doesnotexist
|
||||
@ -200,7 +200,7 @@ Feature: quickmarks and bookmarks
|
||||
Scenario: Loading a quickmark with -t and -b
|
||||
When I run :quickmark-add http://localhost:(port)/data/numbers/17.txt seventeen
|
||||
When I run :quickmark-load -t -b seventeen
|
||||
Then the error "Only one of -t/-b/-w can be given!" should be shown
|
||||
Then the error "Only one of -t/-b/-w/-p can be given!" should be shown
|
||||
|
||||
Scenario: Deleting a quickmark which does not exist
|
||||
When I run :quickmark-del doesnotexist
|
||||
|
@ -498,18 +498,20 @@ class QuteProc(testprocess.Process):
|
||||
self.set_setting(sect, opt, old_value)
|
||||
|
||||
def open_path(self, path, *, new_tab=False, new_bg_tab=False,
|
||||
new_window=False, as_url=False, port=None, https=False,
|
||||
wait=True):
|
||||
new_window=False, private=False, as_url=False, port=None,
|
||||
https=False, wait=True):
|
||||
"""Open the given path on the local webserver in qutebrowser."""
|
||||
url = self.path_to_url(path, port=port, https=https)
|
||||
self.open_url(url, new_tab=new_tab, new_bg_tab=new_bg_tab,
|
||||
new_window=new_window, as_url=as_url, wait=wait)
|
||||
new_window=new_window, private=private, as_url=as_url,
|
||||
wait=wait)
|
||||
|
||||
def open_url(self, url, *, new_tab=False, new_bg_tab=False,
|
||||
new_window=False, as_url=False, wait=True):
|
||||
new_window=False, private=False, as_url=False, wait=True):
|
||||
"""Open the given url in qutebrowser."""
|
||||
if new_tab and new_window:
|
||||
raise ValueError("new_tab and new_window given!")
|
||||
if sum(1 for opt in [new_tab, new_bg_tab, new_window, private, as_url]
|
||||
if opt) > 1:
|
||||
raise ValueError("Conflicting options given!")
|
||||
|
||||
if as_url:
|
||||
self.send_cmd(url, invalid=True)
|
||||
@ -519,6 +521,8 @@ class QuteProc(testprocess.Process):
|
||||
self.send_cmd(':open -b ' + url)
|
||||
elif new_window:
|
||||
self.send_cmd(':open -w ' + url)
|
||||
elif private:
|
||||
self.send_cmd(':open -p ' + url)
|
||||
else:
|
||||
self.send_cmd(':open ' + url)
|
||||
|
||||
@ -577,7 +581,7 @@ class QuteProc(testprocess.Process):
|
||||
"""Save the session and get the parsed session data."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
session = os.path.join(tmpdir, 'session.yml')
|
||||
self.send_cmd(':session-save "{}"'.format(session))
|
||||
self.send_cmd(':session-save --with-private "{}"'.format(session))
|
||||
self.wait_for(category='message', loglevel=logging.INFO,
|
||||
message='Saved session {}.'.format(session))
|
||||
with open(session, encoding='utf-8') as f:
|
||||
|
@ -78,8 +78,8 @@ class Line:
|
||||
def _render_log(data, threshold=100):
|
||||
"""Shorten the given log without -v and convert to a string."""
|
||||
data = [str(d) for d in data]
|
||||
is_exception = any('Traceback (most recent call last):' in line
|
||||
for line in data)
|
||||
is_exception = any('Traceback (most recent call last):' in line or
|
||||
'Uncaught exception' in line for line in data)
|
||||
verbose = pytest.config.getoption('--verbose')
|
||||
if len(data) > threshold and not verbose and not is_exception:
|
||||
msg = '[{} lines suppressed, use -v to show]'.format(
|
||||
|
@ -267,3 +267,21 @@ def test_launching_with_python2():
|
||||
assert proc.returncode == 1
|
||||
error = "At least Python 3.4 is required to run qutebrowser"
|
||||
assert stderr.decode('ascii').startswith(error)
|
||||
|
||||
|
||||
def test_initial_private_browsing(request, quteproc_new):
|
||||
"""Make sure the initial window is private when the setting is set."""
|
||||
args = (_base_args(request.config) +
|
||||
['--temp-basedir', '-s', 'general', 'private-browsing', 'true'])
|
||||
quteproc_new.start(args)
|
||||
|
||||
quteproc_new.compare_session("""
|
||||
windows:
|
||||
- private: True
|
||||
tabs:
|
||||
- history:
|
||||
- url: about:blank
|
||||
""")
|
||||
|
||||
quteproc_new.send_cmd(':quit')
|
||||
quteproc_new.wait_for_quit()
|
||||
|
@ -230,7 +230,7 @@ class FakeWebTab(browsertab.AbstractTab):
|
||||
scroll_pos_perc=(0, 0),
|
||||
load_status=usertypes.LoadStatus.success,
|
||||
progress=0):
|
||||
super().__init__(win_id=0, mode_manager=None)
|
||||
super().__init__(win_id=0, mode_manager=None, private=False)
|
||||
self._load_status = load_status
|
||||
self._title = title
|
||||
self._url = url
|
||||
|
@ -22,20 +22,11 @@ import pytest
|
||||
from qutebrowser.browser.webkit.network import networkmanager
|
||||
from qutebrowser.browser.webkit import cookies
|
||||
|
||||
|
||||
pytestmark = pytest.mark.usefixtures('cookiejar_and_cache')
|
||||
|
||||
|
||||
class TestPrivateMode:
|
||||
|
||||
def test_init_with_private_mode(self, config_stub):
|
||||
config_stub.data = {'general': {'private-browsing': True}}
|
||||
nam = networkmanager.NetworkManager(0, 0)
|
||||
assert isinstance(nam.cookieJar(), cookies.RAMCookieJar)
|
||||
|
||||
def test_setting_private_mode_later(self, config_stub):
|
||||
config_stub.data = {'general': {'private-browsing': False}}
|
||||
nam = networkmanager.NetworkManager(0, 0)
|
||||
assert not isinstance(nam.cookieJar(), cookies.RAMCookieJar)
|
||||
config_stub.data = {'general': {'private-browsing': True}}
|
||||
nam.on_config_changed()
|
||||
assert isinstance(nam.cookieJar(), cookies.RAMCookieJar)
|
||||
def test_init_with_private_mode(config_stub):
|
||||
nam = networkmanager.NetworkManager(win_id=0, tab_id=0, private=True)
|
||||
assert isinstance(nam.cookieJar(), cookies.RAMCookieJar)
|
||||
assert nam.cache() is None
|
||||
|
@ -54,41 +54,6 @@ def test_cache_config_change_cache_size(config_stub, tmpdir):
|
||||
assert disk_cache.maximumCacheSize() == max_cache_size * 2
|
||||
|
||||
|
||||
def test_cache_config_enable_private_browsing(config_stub, tmpdir):
|
||||
"""Change private-browsing config to True and emit signal."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': False}
|
||||
}
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
assert disk_cache.cacheSize() == 0
|
||||
preload_cache(disk_cache)
|
||||
assert disk_cache.cacheSize() > 0
|
||||
|
||||
config_stub.set('general', 'private-browsing', True)
|
||||
assert disk_cache.cacheSize() == 0
|
||||
|
||||
|
||||
def test_cache_config_disable_private_browsing(config_stub, tmpdir):
|
||||
"""Change private-browsing config to False and emit signal."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': True}
|
||||
}
|
||||
url = 'http://qutebrowser.org'
|
||||
metadata = QNetworkCacheMetaData()
|
||||
metadata.setUrl(QUrl(url))
|
||||
assert metadata.isValid()
|
||||
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
assert disk_cache.prepare(metadata) is None
|
||||
|
||||
config_stub.set('general', 'private-browsing', False)
|
||||
content = b'cute'
|
||||
preload_cache(disk_cache, url, content)
|
||||
assert disk_cache.data(QUrl(url)).readAll() == content
|
||||
|
||||
|
||||
def test_cache_size_leq_max_cache_size(config_stub, tmpdir):
|
||||
"""Test cacheSize <= MaximumCacheSize when cache is activated."""
|
||||
limit = 100
|
||||
@ -108,16 +73,6 @@ def test_cache_size_leq_max_cache_size(config_stub, tmpdir):
|
||||
assert disk_cache.cacheSize() < limit + 100
|
||||
|
||||
|
||||
def test_cache_size_deactivated(config_stub, tmpdir):
|
||||
"""Confirm that the cache size returns 0 when deactivated."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': True}
|
||||
}
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
assert disk_cache.cacheSize() == 0
|
||||
|
||||
|
||||
def test_cache_existing_metadata_file(config_stub, tmpdir):
|
||||
"""Test querying existing meta data file from activated cache."""
|
||||
config_stub.data = {
|
||||
@ -155,42 +110,6 @@ def test_cache_nonexistent_metadata_file(config_stub, tmpdir):
|
||||
assert not cache_file.isValid()
|
||||
|
||||
|
||||
def test_cache_deactivated_metadata_file(config_stub, tmpdir):
|
||||
"""Test querying meta data file when cache is deactivated."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': True}
|
||||
}
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
assert disk_cache.fileMetaData("foo") == QNetworkCacheMetaData()
|
||||
|
||||
|
||||
def test_cache_deactivated_private_browsing(config_stub, tmpdir):
|
||||
"""Test if cache is deactivated in private-browsing mode."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': True}
|
||||
}
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
|
||||
metadata = QNetworkCacheMetaData()
|
||||
metadata.setUrl(QUrl('http://www.example.com/'))
|
||||
assert metadata.isValid()
|
||||
assert disk_cache.prepare(metadata) is None
|
||||
|
||||
|
||||
def test_cache_deactivated_get_data(config_stub, tmpdir):
|
||||
"""Query some data from a deactivated cache."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': True}
|
||||
}
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
|
||||
url = QUrl('http://www.example.com/')
|
||||
assert disk_cache.data(url) is None
|
||||
|
||||
|
||||
def test_cache_get_nonexistent_data(config_stub, tmpdir):
|
||||
"""Test querying some data that was never inserted."""
|
||||
config_stub.data = {
|
||||
@ -203,18 +122,6 @@ def test_cache_get_nonexistent_data(config_stub, tmpdir):
|
||||
assert disk_cache.data(QUrl('http://qutebrowser.org')) is None
|
||||
|
||||
|
||||
def test_cache_deactivated_remove_data(config_stub, tmpdir):
|
||||
"""Test removing some data from a deactivated cache."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': True}
|
||||
}
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
|
||||
url = QUrl('http://www.example.com/')
|
||||
assert not disk_cache.remove(url)
|
||||
|
||||
|
||||
def test_cache_insert_data(config_stub, tmpdir):
|
||||
"""Test if entries inserted into the cache are actually there."""
|
||||
config_stub.data = {
|
||||
@ -232,28 +139,6 @@ def test_cache_insert_data(config_stub, tmpdir):
|
||||
assert disk_cache.data(QUrl(url)).readAll() == content
|
||||
|
||||
|
||||
def test_cache_deactivated_insert_data(config_stub, tmpdir):
|
||||
"""Insert data when cache is deactivated."""
|
||||
# First create QNetworkDiskCache just to get a valid QIODevice from it
|
||||
url = 'http://qutebrowser.org'
|
||||
disk_cache = QNetworkDiskCache()
|
||||
disk_cache.setCacheDirectory(str(tmpdir))
|
||||
metadata = QNetworkCacheMetaData()
|
||||
metadata.setUrl(QUrl(url))
|
||||
device = disk_cache.prepare(metadata)
|
||||
assert device is not None
|
||||
|
||||
# Now create a deactivated DiskCache and insert the valid device created
|
||||
# above (there probably is a better way to get a valid QIODevice...)
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': True}
|
||||
}
|
||||
|
||||
deactivated_cache = cache.DiskCache(str(tmpdir))
|
||||
assert deactivated_cache.insert(device) is None
|
||||
|
||||
|
||||
def test_cache_remove_data(config_stub, tmpdir):
|
||||
"""Test if a previously inserted entry can be removed from the cache."""
|
||||
config_stub.data = {
|
||||
@ -285,16 +170,6 @@ def test_cache_clear_activated(config_stub, tmpdir):
|
||||
assert disk_cache.cacheSize() == 0
|
||||
|
||||
|
||||
def test_cache_clear_deactivated(config_stub, tmpdir):
|
||||
"""Test method clear() on deactivated cache."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': True}
|
||||
}
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
assert disk_cache.clear() is None
|
||||
|
||||
|
||||
def test_cache_metadata(config_stub, tmpdir):
|
||||
"""Ensure that DiskCache.metaData() returns exactly what was inserted."""
|
||||
config_stub.data = {
|
||||
@ -313,18 +188,6 @@ def test_cache_metadata(config_stub, tmpdir):
|
||||
assert disk_cache.metaData(QUrl(url)) == metadata
|
||||
|
||||
|
||||
def test_cache_deactivated_metadata(config_stub, tmpdir):
|
||||
"""Test querying metaData() on not activated cache."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': True}
|
||||
}
|
||||
url = 'http://qutebrowser.org'
|
||||
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
assert disk_cache.metaData(QUrl(url)) == QNetworkCacheMetaData()
|
||||
|
||||
|
||||
def test_cache_update_metadata(config_stub, tmpdir):
|
||||
"""Test updating the meta data for an existing cache entry."""
|
||||
config_stub.data = {
|
||||
@ -343,21 +206,6 @@ def test_cache_update_metadata(config_stub, tmpdir):
|
||||
assert disk_cache.metaData(QUrl(url)) == metadata
|
||||
|
||||
|
||||
def test_cache_deactivated_update_metadata(config_stub, tmpdir):
|
||||
"""Test updating the meta data when cache is not activated."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': True}
|
||||
}
|
||||
url = 'http://qutebrowser.org'
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
|
||||
metadata = QNetworkCacheMetaData()
|
||||
metadata.setUrl(QUrl(url))
|
||||
assert metadata.isValid()
|
||||
assert disk_cache.updateMetaData(metadata) is None
|
||||
|
||||
|
||||
def test_cache_full(config_stub, tmpdir):
|
||||
"""Do a sanity test involving everything."""
|
||||
config_stub.data = {
|
||||
@ -385,3 +233,10 @@ def test_cache_full(config_stub, tmpdir):
|
||||
|
||||
assert disk_cache.metaData(QUrl(url)).lastModified() == soon
|
||||
assert disk_cache.data(QUrl(url)).readAll() == content
|
||||
|
||||
|
||||
def test_private_browsing(config_stub, tmpdir):
|
||||
"""Make sure the cache asserts with private browsing."""
|
||||
config_stub.data = {'general': {'private-browsing': True}}
|
||||
with pytest.raises(AssertionError):
|
||||
cache.DiskCache(str(tmpdir))
|
||||
|
@ -38,18 +38,13 @@ class FakeWebHistory:
|
||||
self.history_dict = history_dict
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def prerequisites(config_stub, fake_save_manager):
|
||||
"""Make sure everything is ready to initialize a WebHistory."""
|
||||
config_stub.data = {'general': {'private-browsing': False}}
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def hist(tmpdir):
|
||||
def hist(tmpdir, fake_save_manager):
|
||||
return history.WebHistory(hist_dir=str(tmpdir), hist_name='history')
|
||||
|
||||
|
||||
def test_async_read_twice(monkeypatch, qtbot, tmpdir, caplog):
|
||||
def test_async_read_twice(monkeypatch, qtbot, tmpdir, caplog,
|
||||
fake_save_manager):
|
||||
(tmpdir / 'filled-history').write('\n'.join([
|
||||
'12345 http://example.com/ title',
|
||||
'67890 http://example.com/',
|
||||
@ -88,34 +83,6 @@ def test_adding_item_during_async_read(qtbot, hist, redirect):
|
||||
assert list(hist.history_dict.values()) == [expected]
|
||||
|
||||
|
||||
def test_private_browsing(qtbot, tmpdir, fake_save_manager, config_stub):
|
||||
"""Make sure no data is saved at all with private browsing."""
|
||||
config_stub.data = {'general': {'private-browsing': True}}
|
||||
private_hist = history.WebHistory(hist_dir=str(tmpdir),
|
||||
hist_name='history')
|
||||
|
||||
# Before initial read
|
||||
with qtbot.assertNotEmitted(private_hist.add_completion_item), \
|
||||
qtbot.assertNotEmitted(private_hist.item_added):
|
||||
private_hist.add_url(QUrl('http://www.example.com/'))
|
||||
assert not private_hist._temp_history
|
||||
|
||||
# read
|
||||
with qtbot.assertNotEmitted(private_hist.add_completion_item), \
|
||||
qtbot.assertNotEmitted(private_hist.item_added):
|
||||
with qtbot.waitSignals([private_hist.async_read_done], order='strict'):
|
||||
list(private_hist.async_read())
|
||||
|
||||
# after read
|
||||
with qtbot.assertNotEmitted(private_hist.add_completion_item), \
|
||||
qtbot.assertNotEmitted(private_hist.item_added):
|
||||
private_hist.add_url(QUrl('http://www.example.com/'))
|
||||
|
||||
assert not private_hist._temp_history
|
||||
assert not private_hist._new_history
|
||||
assert not private_hist.history_dict
|
||||
|
||||
|
||||
def test_iter(hist):
|
||||
list(hist.async_read())
|
||||
|
||||
@ -257,7 +224,7 @@ def test_add_item_redirect(qtbot, hist):
|
||||
assert hist.history_dict[url] == entry
|
||||
|
||||
|
||||
def test_add_item_redirect_update(qtbot, tmpdir):
|
||||
def test_add_item_redirect_update(qtbot, tmpdir, fake_save_manager):
|
||||
"""A redirect update added should override a non-redirect one."""
|
||||
url = 'http://www.example.com/'
|
||||
|
||||
|
@ -146,7 +146,7 @@ def test_previtem_index_error(hist):
|
||||
|
||||
def test_append_private_mode(hist, config_stub):
|
||||
"""Test append in private mode."""
|
||||
hist.handle_private_mode = True
|
||||
hist._private = True
|
||||
# We want general.private-browsing set to True
|
||||
config_stub.data = CONFIG_PRIVATE
|
||||
hist.append('new item')
|
||||
|
@ -34,7 +34,7 @@ class TestCommandLineEdit:
|
||||
@pytest.fixture
|
||||
def cmd_edit(self, qtbot):
|
||||
"""Fixture to initialize a CommandLineEdit."""
|
||||
cmd_edit = miscwidgets.CommandLineEdit(None)
|
||||
cmd_edit = miscwidgets.CommandLineEdit()
|
||||
cmd_edit.set_prompt(':')
|
||||
qtbot.add_widget(cmd_edit)
|
||||
assert cmd_edit.text() == ''
|
||||
|
Loading…
Reference in New Issue
Block a user