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