Merge remote-tracking branch 'upstream/master' into really_complete

This commit is contained in:
Ryan Roden-Corrent 2017-07-05 08:45:57 -04:00
commit dc4472470e
51 changed files with 556 additions and 281 deletions

View File

@ -1,6 +1,7 @@
sudo: required
dist: trusty
language: generic
group: edge
matrix:
include:
@ -15,9 +16,6 @@ matrix:
- os: linux
env: DOCKER=archlinux-webengine QUTE_BDD_WEBENGINE=true
services: docker
- os: linux
env: DOCKER=archlinux-ng
services: docker
- os: linux
env: DOCKER=ubuntu-xenial
services: docker
@ -25,14 +23,18 @@ matrix:
language: python
python: 3.6
env: TESTENV=py36-pyqt571
- os: linux
language: python
python: 3.6
env: TESTENV=py36-pyqt58
- os: linux
language: python
python: 3.5
env: TESTENV=py35-pyqt58
env: TESTENV=py35-pyqt59
- os: linux
language: python
python: 3.6
env: TESTENV=py36-pyqt58
env: TESTENV=py36-pyqt59
- os: osx
env: TESTENV=py36 OSX=elcapitan
osx_image: xcode7.3

View File

@ -14,8 +14,8 @@ This project adheres to http://semver.org/[Semantic Versioning].
// `Fixed` for any bug fixes.
// `Security` to invite users to upgrade in case of vulnerabilities.
v0.11.0 (unreleased)
--------------------
v0.11.0
-------
New dependencies
~~~~~~~~~~~~~~~~
@ -23,13 +23,15 @@ New dependencies
- New dependency on `PyQt5.QtOpenGL` if QtWebEngine is used. QtWebEngine depends
on QtOpenGL already, but on distributions packaging split PyQt5 wrappers, the
wrappers for QtOpenGL are now required.
- New optional (but recommended) `PyOpenGL` dependency with QtWebEngine to work
around a bug where a black screen is shown with some setups.
- New dependency on `PyOpenGL` if QtWebEngine is used.
Added
~~~~~
- New `-p` flag for `:open` to open a private window.
- Private browsing is now implemented for QtWebEngine, *and changed its
behavior*: The `general -> private-browsing` setting now only applies to newly
opened windows, and you can use the `-p` flag to `:open` to open a private
window.
- New "pinned tabs" feature, with a new `:tab-pin` command (bound
to `<Ctrl-p>` by default).
- (QtWebEngine) Implemented `:follow-selected`.
@ -46,6 +48,8 @@ Added
customize statusbar colors for private windows.
- New `{private}` field displaying `[Private Mode]` for
`ui -> window-title-format` and `tabs -> title-format`.
- (QtWebEngine) Proxy support with Qt 5.7.1 (already was supported for 5.8 and
newer)
Changed
~~~~~~~
@ -53,60 +57,51 @@ Changed
- To prevent elaborate phishing attacks, the Punycode version (`xn--*`) is now
shown in addition to the decoded version for international domain names
(IDN).
- Private browsing is now implemented for QtWebEngine, and changed it's
behavior: The `general -> private-browsing` setting now only applies to newly
opened windows, and you can use the `-p` flag to `:open` to open a private
window.
- Improved `qute://history` page (with lazy loading)
- Starting with legacy QtWebKit now shows a warning message once.
- Crash reports are not public anymore.
- Paths like `C:` are now treated as absolute paths on Windows for downloads,
and invalid paths are handled properly.
- PAC on QtWebKit now supports SOCKS5 as type.
- Comments in the config file are now before the individual options instead of
being before sections.
- Messages are now hidden when clicked.
- stdin is now closed immediately for processes spawned from qutebrowser.
- When `ui -> message-timeout` is set to 0, messages are now never cleared.
- Middle/right-clicking the blank parts of the tab bar (when vertical) now
closes the current tab.
- (QtWebEngine) With Qt 5.9, `content -> cookies-store` can now be set without
a restart.
- (QtWebEngine) With Qt 5.9, better error messages are now shown for failed
downloads.
- The adblocker now also blocks non-GET requests (e.g. POST).
- `javascript:` links can now be hinted.
- `:view-source`, `:tab-clone` and `:navigate --tab` now don't open the tab as
"explicit" anymore, i.e. (with the default settings) open it next to the
active tab.
- (QtWebEngine) The underlying Chromium version is now shown in the version
info.
- `qute:*` pages now use `qute://*` instead (e.g. `qute://version` instead of
`qute:version`), but the old versions are automatically redirected.
- Starting with legacy QtWebKit now shows a warning message.
*With the next release, support for it will be removed.*
- The Windows releases are redone from scratch, which means:
- They now use the new QtWebEngine backend
- The bundled Qt is updated from 5.5 to 5.9
- The bundled Python is updated from 3.4 to 3.6
- They are now generated with PyInstaller instead of cx_Freeze
- The installer is now generated using NSIS instead of being a MSI
- Improved `qute://history` page (with lazy loading)
- Crash reports are not public anymore.
- Paths like `C:` are now treated as absolute paths on Windows for downloads,
and invalid paths are handled properly.
- Comments in the config file are now placed before the individual options
instead of being before sections.
- Messages are now hidden when clicked.
- stdin is now closed immediately for processes spawned from qutebrowser.
- When `ui -> message-timeout` is set to 0, messages are now never cleared.
- Middle/right-clicking the blank parts of the tab bar (when vertical) now
closes the current tab.
- The adblocker now also blocks non-GET requests (e.g. POST).
- `javascript:` links can now be hinted.
- `:view-source`, `:tab-clone` and `:navigate --tab` now don't open the tab as
"explicit" anymore, i.e. (with the default settings) open it next to the
active tab.
- `qute:*` pages now use `qute://*` instead (e.g. `qute://version` instead of
`qute:version`), but the old versions are automatically redirected.
- Texts in prompts are now selectable.
- Renderer process crashes now show an error page.
- (QtWebKit) storage -> offline-web-application-storage` got renamed to `...-cache`
- The default level for `:messages` is now `info`, not `error`
- Trying to focus the currently focused tab with `:tab-focus` now focuses the
last viewed tab.
- (QtWebEngine) With Qt 5.9, `content -> cookies-store` can now be set without
a restart.
- (QtWebEngine) With Qt 5.9, better error messages are now shown for failed
downloads.
- (QtWebEngine) The underlying Chromium version is now shown in the version
info.
- (QtWebKit) Renderer process crashes now show an error page on Qt 5.9 or newer.
- (QtWebKit) storage -> offline-web-application-storage` got renamed to `...-cache`
- (QtWebKit) PAC now supports SOCKS5 as type.
Fixed
~~~~~
- The macOS .dmg is now built against Qt 5.9 which fixes various
important issues (such as not being able to type dead keys).
- (QtWebEngine) Added a workaround for a black screen with some setups
(the workaround requires PyOpenGL to be installed, but it's optional)
- (QtWebEngine) Starting with Nouveau graphics now shows an error message
instead of crashing in Qt. This adds a new dependency on `PyQt5.QtOpenGL`.
- (QtWebEngine) Retrying downloads now shows an error instead of crashing.
- (QtWebEngine) Cloning a view-source tab now doesn't crash anymore.
- (QtWebKit) The HTTP cache is disabled on Qt 5.7.1 and 5.8 now as it leads to
frequent crashes due to a Qt bug.
- Fixed crash with `:download` on PyQt 5.9.
- Cloning a page without history doesn't crash anymore.
- When a download results in a HTTP error, it now shows the error correctly
@ -116,7 +111,6 @@ Fixed
- Fixed crash when unbinding an unbound key in the key config.
- Fixed crash when using `:debug-log-filter` when `--filter` wasn't given on startup.
- Fixed crash with some invalid setting values.
- (QtWebKit) Fixed Crash when a PAC file returns an invalid value.
- Continuing a search after clearing it now works correctly.
- The tabbar and completion should now be more consistently and correctly
styled with various system styles.
@ -124,18 +118,27 @@ Fixed
- The validation for colors in stylesheets is now less strict,
allowing for all valid Qt values.
- `data:` URLs now aren't added to the history anymore.
- (QtWebEngine) `window.navigator.userAgent` is now set correctly when
customizing the user agent.
- Accidentally starting with Python 2 now shows a proper error message again.
- (QtWebEngine) HTML fullscreen is now tracked for each tab separately, which
means it's not possible anymore to accidentally get stuck in fullscreen state
by closing a tab with a fullscreen video.
- For some people, running some userscripts crashed - this should now be fixed.
- Various other rare crashes should now be fixed.
- The settings documentation was truncated with v0.10.1 which should now be
fixed.
- Scrolling to an anchor in a background tab now works correctly, and javascript
gets the correct window size for background tabs.
- (QtWebEngine) Added a workaround for a black screen with some setups
- (QtWebEngine) Starting with Nouveau graphics now shows an error message
instead of crashing in Qt.
- (QtWebEngine) Retrying downloads now shows an error instead of crashing.
- (QtWebEngine) Cloning a view-source tab now doesn't crash anymore.
- (QtWebEngine) `window.navigator.userAgent` is now set correctly when
customizing the user agent.
- (QtWebEngine) HTML fullscreen is now tracked for each tab separately, which
means it's not possible anymore to accidentally get stuck in fullscreen state
by closing a tab with a fullscreen video.
- (QtWebEngine) `:scroll-page` with `--bottom-navigate` now works correctly.
- (QtWebKit) The HTTP cache is disabled on Qt 5.7.1 and 5.8 now as it leads to
frequent crashes due to a Qt bug.
- (QtWebKit) Fixed Crash when a PAC file returns an invalid value.
v0.10.1
-------

View File

@ -682,8 +682,9 @@ qutebrowser release
* Add newest config to `tests/unit/config/old_configs` and update `test_upgrade_version`
- `python -m qutebrowser --basedir conf :quit`
- `sed '/^#/d' conf/config/qutebrowser.conf > tests/unit/config/old_configs/qutebrowser-v0.x.y.conf`
- `sed '/^#/d' conf/config/qutebrowser.conf > tests/unit/config/old_configs/qutebrowser-v0.$x.$y.conf`
- `rm -r conf`
- git add
- commit
* Adjust `__version_info__` in `qutebrowser/__init__.py`.
* Update changelog (remove *(unreleased)*)
@ -698,7 +699,7 @@ qutebrowser release
as closed.
* Linux: Run `python3 scripts/dev/build_release.py --upload v0.$x.$y`
* Windows: Run `C:\Python34_x32\python scripts\dev\build_release.py --asciidoc C:\Python27\python C:\asciidoc-8.6.9\asciidoc.py --upload v0.X.Y` (replace X/Y by hand)
* Windows: Run `C:\Python36-32\python scripts\dev\build_release.py --asciidoc C:\Python27\python C:\asciidoc-8.6.9\asciidoc.py --upload v0.X.Y` (replace X/Y by hand)
* OS X: Run `python3 scripts/dev/build_release.py --upload v0.X.Y` (replace X/Y by hand)
* On server: Run `python3 scripts/dev/download_release.py v0.X.Y` (replace X/Y by hand)
* Update `qutebrowser-git` PKGBUILD if dependencies/install changed

View File

@ -97,8 +97,9 @@ qutebrowser is available in the official [community] repository.
# pacman -S qutebrowser
----
It's also recommended to install `qt5-webkit-ng` or `qt5-webengine` (and start
with `--backend webengine`) to use an up-to-date backend.
Archlinux packages an updated `qt5-webkit` package by default. If you want to
use the QtWebEngine backend instead, install `qt5-webengine` and start with
`--backend webengine`.
There is also a -git version available in the AUR:
https://aur.archlinux.org/packages/qutebrowser-git/[qutebrowser-git].
@ -370,14 +371,6 @@ your `$PATH` (e.g. `/usr/local/bin/qutebrowser` or `~/bin/qutebrowser`):
~/path/to/qutebrowser/.venv/bin/python3 -m qutebrowser "$@"
----
If you are developing on qutebrowser, you may want to redirect it to a local
config:
----
#!/bin/bash
~/path/to/qutebrowser/.venv/bin/python3 -m qutebrowser -c .qutebrowser-local "$@"
----
Updating
~~~~~~~~

View File

@ -99,15 +99,16 @@ Requirements
The following software and libraries are required to run qutebrowser:
* http://www.python.org/[Python] 3.4 or newer (3.5 recommended)
* http://qt.io/[Qt] 5.2.0 or newer (5.9.0 recommended)
* http://qt.io/[Qt] 5.2.0 or newer (5.9 recommended)
* QtWebKit (old or link:https://github.com/annulen/webkit/wiki[reloaded]/NG) or QtWebEngine
* http://www.riverbankcomputing.com/software/pyqt/intro[PyQt] 5.2.0 or newer
(5.8.1 recommended) for Python 3
(5.9 recommended) for Python 3
* https://pypi.python.org/pypi/setuptools/[pkg_resources/setuptools]
* http://fdik.org/pyPEG/[pyPEG2]
* http://jinja.pocoo.org/[jinja2]
* http://pygments.org/[pygments]
* http://pyyaml.org/wiki/PyYAML[PyYAML]
* http://pyopengl.sourceforge.net/[PyOpenGL] when using QtWebEngine
The following libraries are optional and provide a better user experience:
@ -237,6 +238,7 @@ Contributors, sorted by the number of commits in descending order:
* Johannes Altmanninger
* Jeremy Kaplan
* Ismail
* Iordanis Grigoriou
* Edgar Hipp
* Daryl Finlay
* arza
@ -279,6 +281,7 @@ Contributors, sorted by the number of commits in descending order:
* Lazlow Carmichael
* Kevin Wang
* Ján Kobezda
* Justin Partain
* Johannes Martinsson
* Jean-Christophe Petkovich
* Helen Sherwood-Taylor

View File

@ -34,6 +34,7 @@ TODO: people with t-shirts or higher pledge levels
- Benedikt Steindorf
- Bernardo Kuri
- Blaise Duszynski
- Bostan
- Bruno Oliveira
- Colin Jacobs
- Daniel Andersson

View File

@ -85,7 +85,7 @@ It is possible to run or bind multiple commands by separating them with `;;`.
|<<tab-pin,tab-pin>>|Pin/Unpin the current/[count]th tab.
|<<tab-prev,tab-prev>>|Switch to the previous tab, or switch [count] tabs back.
|<<unbind,unbind>>|Unbind a keychain.
|<<undo,undo>>|Re-open a closed tab (optionally skipping [count] closed tabs).
|<<undo,undo>>|Re-open a closed tab.
|<<view-source,view-source>>|Show the source of the current page in a new tab.
|<<window-only,window-only>>|Close all windows except for the current one.
|<<wq,wq>>|Save open pages and quit.
@ -936,7 +936,7 @@ Unbind a keychain.
[[undo]]
=== undo
Re-open a closed tab (optionally skipping [count] closed tabs).
Re-open a closed tab.
[[view-source]]
=== view-source

View File

@ -789,8 +789,6 @@ The proxy to use.
In addition to the listed values, you can use a `socks://...` or `http://...` URL.
This setting only works with Qt 5.8 or newer when using the QtWebEngine backend.
Valid values:
* +system+: Use the system wide proxy.

View File

@ -57,7 +57,7 @@ show it.
How URLs should be opened if there is already a qutebrowser instance running.
*--backend* '{webkit,webengine}'::
Which backend to use (webengine backend is EXPERIMENTAL!).
Which backend to use.
*--enable-webengine-inspector*::
Enable the web inspector for QtWebEngine. Note that this is a SECURITY RISK and you should not visit untrusted websites with the inspector turned on. See https://bugreports.qt.io/browse/QTBUG-50725 for more details.

View File

@ -41,7 +41,7 @@ a = Analysis(['../qutebrowser/__main__.py'],
pathex=['misc'],
binaries=None,
datas=get_data_files(),
hiddenimports=['PyQt5.QtOpenGL'],
hiddenimports=['PyQt5.QtOpenGL', 'PyQt5._QOpenGLFunctions_2_0'],
hookspath=[],
runtime_hooks=[],
excludes=['tkinter'],

View File

@ -5,5 +5,5 @@ chardet==3.0.4
codecov==2.0.9
coverage==4.4.1
idna==2.5
requests==2.17.3
requests==2.18.1
urllib3==1.21.1

View File

@ -10,7 +10,7 @@ lazy-object-proxy==1.3.1
mccabe==0.6.1
-e git+https://github.com/PyCQA/pylint.git#egg=pylint
./scripts/dev/pylint_checkers
requests==2.17.3
requests==2.18.1
six==1.10.0
uritemplate==3.0.0
uritemplate.py==3.0.2

View File

@ -8,9 +8,9 @@ idna==2.5
isort==4.2.15
lazy-object-proxy==1.3.1
mccabe==0.6.1
pylint==1.7.1
pylint==1.7.2
./scripts/dev/pylint_checkers
requests==2.17.3
requests==2.18.1
six==1.10.0
uritemplate==3.0.0
uritemplate.py==3.0.2

View File

@ -1,4 +1,4 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
PyQt5==5.8.2
sip==4.19.2
PyQt5==5.9
sip==4.19.3

View File

@ -1,7 +1,7 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
beautifulsoup4==4.6.0
cheroot==5.5.0
cheroot==5.7.0
click==6.7
# colorama==0.3.9
coverage==4.4.1
@ -12,7 +12,7 @@ Flask==0.12.2
glob2==0.5
httpbin==0.5.0
hunter==1.4.1
hypothesis==3.11.3
hypothesis==3.11.6
itsdangerous==0.24
# Jinja2==2.9.6
Mako==1.0.6
@ -30,7 +30,7 @@ pytest-instafail==0.3.0
pytest-mock==1.6.0
pytest-qt==2.1.0
pytest-repeat==0.4.1
pytest-rerunfailures==2.1.0
pytest-rerunfailures==2.2
pytest-travis-fold==1.2.0
pytest-xvfb==1.0.0
PyVirtualDisplay==0.2.1

View File

@ -45,6 +45,7 @@ qt_log_ignore =
^QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to .*
^QGeoclueMaster error creating GeoclueMasterClient\.
^Geoclue error: Process org\.freedesktop\.Geoclue\.Master exited with status 127
^QDBusConnection: name 'org.freedesktop.Geoclue.Master' had owner '' but we thought it was ':1.1'
^QObject::connect: Cannot connect \(null\)::stateChanged\(QNetworkSession::State\) to QNetworkReplyHttpImpl::_q_networkSessionStateChanged\(QNetworkSession::State\)
^QXcbClipboard: Cannot transfer data, no data available
^load glyph failed

View File

@ -26,7 +26,7 @@ __copyright__ = "Copyright 2014-2017 Florian Bruhin (The Compiler)"
__license__ = "GPL"
__maintainer__ = __author__
__email__ = "mail@qutebrowser.org"
__version_info__ = (0, 10, 1)
__version_info__ = (0, 11, 0)
__version__ = '.'.join(str(e) for e in __version_info__)
__description__ = "A keyboard-driven, vim-like browser based on PyQt5."

View File

@ -414,10 +414,8 @@ def _init_modules(args, crash_handler):
log.init.debug("Initializing network...")
networkmanager.init()
if qtutils.version_check('5.8'):
# Otherwise we can only initialize it for QtWebKit because of crashes
log.init.debug("Initializing proxy...")
proxy.init()
log.init.debug("Initializing proxy...")
proxy.init()
log.init.debug("Initializing readline-bridge...")
readline_bridge = readline.ReadlineBridge()

View File

@ -157,12 +157,14 @@ class CommandDispatcher:
else:
return None
def _tab_focus_last(self):
def _tab_focus_last(self, *, show_error=True):
"""Select the tab which was last focused."""
try:
tab = objreg.get('last-focused-tab', scope='window',
window=self._win_id)
except KeyError:
if not show_error:
return
raise cmdexc.CommandError("No last focused tab!")
idx = self._tabbed_browser.indexOf(tab)
if idx == -1:
@ -278,9 +280,7 @@ class CommandDispatcher:
return
to_pin = not tab.data.pinned
tab_index = self._current_index() if count is None else count - 1
cmdutils.check_overflow(tab_index + 1, 'int')
self._tabbed_browser.set_tab_pinned(tab_index, to_pin)
self._tabbed_browser.set_tab_pinned(tab, to_pin)
@cmdutils.register(instance='command-dispatcher', name='open',
maxsplit=0, scope='window')
@ -513,7 +513,7 @@ class CommandDispatcher:
newtab.data.keep_icon = True
newtab.history.deserialize(history)
newtab.zoom.set_factor(curtab.zoom.factor())
new_tabbed_browser.set_tab_pinned(idx, curtab.data.pinned)
new_tabbed_browser.set_tab_pinned(newtab, curtab.data.pinned)
return newtab
@cmdutils.register(instance='command-dispatcher', scope='window')
@ -866,7 +866,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
def zoom(self, zoom: int = None, count=None):
def zoom(self, zoom=None, count=None):
"""Set the zoom level for the current tab.
The zoom can be given as argument or as [count]. If neither is
@ -877,6 +877,13 @@ class CommandDispatcher:
zoom: The zoom percentage to set.
count: The zoom percentage to set.
"""
if zoom is not None:
try:
zoom = int(zoom.rstrip('%'))
except ValueError:
raise cmdexc.CommandError("zoom: Invalid int value {}"
.format(zoom))
level = count if count is not None else zoom
if level is None:
level = config.get('ui', 'default-zoom')
@ -923,7 +930,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window')
def undo(self):
"""Re-open a closed tab (optionally skipping [count] closed tabs)."""
"""Re-open a closed tab."""
try:
self._tabbed_browser.undo()
except IndexError:
@ -1075,12 +1082,15 @@ class CommandDispatcher:
last tab.
count: The tab index to focus, starting with 1.
"""
index = count if count is not None else index
if index == 'last':
self._tab_focus_last()
return
index = count if count is not None else index
if index is None:
elif index == self._current_index() + 1:
self._tab_focus_last(show_error=False)
return
elif index is None:
self.tab_next()
return

View File

@ -385,5 +385,6 @@ def qute_backend_warning(_url):
html = jinja.render('backend-warning.html',
distribution=version.distribution(),
Distribution=version.Distribution,
version=pkg_resources.parse_version)
version=pkg_resources.parse_version,
title="Legacy backend warning")
return 'text/html', html

View File

@ -36,8 +36,7 @@ from PyQt5.QtWebEngineWidgets import (QWebEngineSettings, QWebEngineProfile,
from qutebrowser.browser import shared
from qutebrowser.config import config, websettings
from qutebrowser.utils import (objreg, utils, standarddir, javascript, log,
qtutils)
from qutebrowser.utils import objreg, utils, standarddir, javascript, qtutils
# The default QWebEngineProfile
@ -133,9 +132,6 @@ def _init_stylesheet(profile):
Mostly inspired by QupZilla:
https://github.com/QupZilla/qupzilla/blob/v2.0/src/lib/app/mainapplication.cpp#L1063-L1101
https://github.com/QupZilla/qupzilla/blob/v2.0/src/lib/tools/scripts.cpp#L119-L132
FIXME:qtwebengine Use QWebEngineStyleSheet once that's available
https://codereview.qt-project.org/#/c/148671/
"""
old_script = profile.scripts().findScript('_qute_stylesheet')
if not old_script.isNull():
@ -209,12 +205,7 @@ def init(args):
if not os.environ.get('QUTE_NO_OPENGL_WORKAROUND'):
# Hide "No OpenGL_accelerate module loaded: ..." message
logging.getLogger('OpenGL.acceleratesupport').propagate = False
try:
from OpenGL import GL # pylint: disable=unused-variable
except ImportError:
pass
else:
log.misc.debug("Imported PyOpenGL as workaround")
from OpenGL import GL # pylint: disable=unused-variable
_init_profiles()

View File

@ -20,6 +20,7 @@
"""Wrapper over a QWebEngineView."""
import os
import math
import functools
import sip
@ -342,7 +343,7 @@ class WebEngineScroller(browsertab.AbstractScroller):
else:
perc_y = min(100, round(100 / dy * jsret['px']['y']))
self._at_bottom = dy >= jsret['px']['y']
self._at_bottom = math.ceil(jsret['px']['y']) >= dy
self._pos_perc = perc_x, perc_y
self.perc_changed.emit(*self._pos_perc)

View File

@ -33,7 +33,6 @@ from PyQt5.QtWebKit import QWebSettings
from PyQt5.QtPrintSupport import QPrinter
from qutebrowser.browser import browsertab
from qutebrowser.browser.network import proxy
from qutebrowser.browser.webkit import webview, tabhistory, webkitelem
from qutebrowser.browser.webkit.network import webkitqutescheme
from qutebrowser.utils import qtutils, objreg, usertypes, utils, log, debug
@ -42,12 +41,6 @@ from qutebrowser.utils import qtutils, objreg, usertypes, utils, log, debug
def init():
"""Initialize QtWebKit-specific modules."""
qapp = QApplication.instance()
if not qtutils.version_check('5.8'):
# Otherwise we initialize it globally in app.py
log.init.debug("Initializing proxy...")
proxy.init()
log.init.debug("Initializing js-bridge...")
js_bridge = webkitqutescheme.JSBridge(qapp)
objreg.register('js-bridge', js_bridge)

View File

@ -437,14 +437,10 @@ def data(readonly=False):
"User agent to send. Empty to send the default."),
('proxy',
SettingValue(typ.Proxy(), 'system',
backends=(None if qtutils.version_check('5.8')
else [usertypes.Backend.QtWebKit])),
SettingValue(typ.Proxy(), 'system'),
"The proxy to use.\n\n"
"In addition to the listed values, you can use a `socks://...` "
"or `http://...` URL.\n\n"
"This setting only works with Qt 5.8 or newer when using the "
"QtWebEngine backend."),
"or `http://...` URL."),
('proxy-dns-requests',
SettingValue(typ.Bool(), 'true',

View File

@ -39,9 +39,15 @@ the <span class="mono">qute://settings</span> page or caret browsing).</span>
If you know more, please <a href="https://github.com/qutebrowser/qutebrowser/issues/new">open an issue</a>!
{%- endmacro %}
{% macro unknown_system() -%}
There's no information available for your system. {{ please_open_issue() }}
{%- endmacro %}
<p>
{% if distribution.parsed == Distribution.ubuntu %}
{% if distribution.version >= version('17.04') %}
{% if distribution.version == none %}
{{ unknown_system() }}
{% elif distribution.version >= version('17.04') %}
{{ install_webengine('python3-pyqt5.qtwebengine') }}
{% elif distribution.version >= version('16.04') %}
QtWebEngine is only available in Ubuntu's repositories since 17.04, but you can <a href="https://github.com/qutebrowser/qutebrowser/blob/master/INSTALL.asciidoc#installing-qutebrowser-with-tox">install qutebrowser via tox</a> with <span class="mono">tox -e mkvenv-pypi</span> to use the new backend.
@ -49,7 +55,9 @@ the <span class="mono">qute://settings</span> page or caret browsing).</span>
Unfortunately, no easy way is known to install QtWebEngine on Ubuntu &lt; 16.04. {{ please_open_issue() }}
{% endif %}
{% elif distribution.parsed == Distribution.debian %}
{% if distribution.version >= version('9') %}
{% if distribution.version == none %}
{{ unknown_system() }}
{% elif distribution.version >= version('9') %}
{{ install_webengine('python3-pyqt5.qtwebengine') }}
{% else %}
Unfortunately, no easy way is known to install QtWebEngine on Debian &lt; 9. {{ please_open_issue() }}
@ -63,7 +71,7 @@ the <span class="mono">qute://settings</span> page or caret browsing).</span>
{% elif distribution.parsed == Distribution.opensuse %}
{{ install_webengine('libqt5-qtwebengine') }}
{% else %}
There's no information available for your system. {{ please_open_issue() }}
{{ unknown_system() }}
{% endif %}
</p>
@ -72,18 +80,18 @@ the <span class="mono">qute://settings</span> page or caret browsing).</span>
<span class="note">This is a drop-in replacement for legacy QtWebKit.</span>
<p>
{% if distribution.parsed == Distribution.debian and distribution.version >= version('9') %}
{% if distribution.parsed == Distribution.debian and distribution.version != none and distribution.version >= version('9') %}
There are unofficial QtWebKit-NG packages <a href="http://repo.paretje.be/unstable/">available</a>.
{% elif distribution.parsed in [Distribution.ubuntu, Distribution.debian] %}
No easy way is known to install QtWebKit-NG on your system.
There are unofficial QtWebKit-NG packages <a href="http://repo.paretje.be/unstable/">available</a>, but they are intended for Debian Unstable.
{{ please_open_issue() }}
{% elif distribution.parsed in [Distribution.arch, Distribution.manjaro] %}
You should be able to install <span class="mono">qt5-webkit-ng</span> via <span class="mono">pacman</span>.
With an updated <span class="mono">qt5-webkit</span> package, you should already get QtWebKit-NG.
{% elif distribution.parsed == Distribution.gentoo %}
There's an unofficial <a href="https://gist.github.com/annulen/309569fb61e5d64a703c055c1e726f71">ebuild</a> available.
{% else %}
There's no information available for your system. {{ please_open_issue() }}
{{ unknown_system() }}
{% endif %}
</p>

View File

@ -273,6 +273,8 @@ class TabbedBrowser(tabwidget.TabWidget):
"""
idx = self.indexOf(tab)
if idx == -1:
if crashed:
return
raise TabDeletedError("tab {} is not contained in "
"TabbedWidget!".format(tab))
if tab is self._now_focused:
@ -340,7 +342,7 @@ class TabbedBrowser(tabwidget.TabWidget):
newtab = self.tabopen(url, background=False, idx=idx)
newtab.history.deserialize(history_data)
self.set_tab_pinned(idx, pinned)
self.set_tab_pinned(newtab, pinned)
@pyqtSlot('QUrl', bool)
def openurl(self, url, newtab):

View File

@ -26,7 +26,7 @@ from PyQt5.QtCore import (pyqtSignal, pyqtSlot, Qt, QSize, QRect, QPoint,
QTimer, QUrl)
from PyQt5.QtWidgets import (QTabWidget, QTabBar, QSizePolicy, QCommonStyle,
QStyle, QStylePainter, QStyleOptionTab,
QStyleFactory)
QStyleFactory, QWidget)
from PyQt5.QtGui import QIcon, QPalette, QColor
from qutebrowser.utils import qtutils, objreg, utils, usertypes, log
@ -94,17 +94,18 @@ class TabWidget(QTabWidget):
bar.set_tab_data(idx, 'indicator-color', color)
bar.update(bar.tabRect(idx))
def set_tab_pinned(self, idx, pinned, *, loading=False):
def set_tab_pinned(self, tab: QWidget,
pinned: bool, *, loading: bool = False) -> None:
"""Set the tab status as pinned.
Args:
idx: The tab index.
tab: The tab to pin
pinned: Pinned tab state to set.
loading: Whether to ignore current data state when
counting pinned_count.
"""
bar = self.tabBar()
tab = self.widget(idx)
idx = self.indexOf(tab)
# Only modify pinned_count if we had a change
# always modify pinned_count if we are loading

View File

@ -336,13 +336,14 @@ def check_libraries(backend):
"http://pyyaml.org/download/pyyaml/ (py3.4) "
"or Install via pip.",
pip="PyYAML"),
'PyQt5.QtSql':
_missing_str("PyQt5.QtSql")
'PyQt5.QtQml': _missing_str("PyQt5.QtQml"),
'PyQt5.QtSql': _missing_str("PyQt5.QtSql"),
}
if backend == 'webengine':
modules['PyQt5.QtWebEngineWidgets'] = _missing_str("QtWebEngine",
webengine=True)
modules['PyQt5.QtOpenGL'] = _missing_str("PyQt5.QtOpenGL")
modules['OpenGL'] = _missing_str("PyOpenGL")
else:
assert backend == 'webkit'
modules['PyQt5.QtWebKit'] = _missing_str("PyQt5.QtWebKit")

View File

@ -407,7 +407,7 @@ class SessionManager(QObject):
tab_to_focus = i
if new_tab.data.pinned:
tabbed_browser.set_tab_pinned(
i, new_tab.data.pinned, loading=True)
new_tab, new_tab.data.pinned, loading=True)
if tab_to_focus is not None:
tabbed_browser.setCurrentIndex(tab_to_focus)
if win.get('active', False):
@ -421,7 +421,10 @@ class SessionManager(QObject):
def delete(self, name):
"""Delete a session."""
path = self._get_session_path(name, check_exists=True)
os.remove(path)
try:
os.remove(path)
except OSError as e:
raise SessionError(e)
self.update_completion.emit()
def list_sessions(self):
@ -517,7 +520,7 @@ class SessionManager(QObject):
self.delete(name)
except SessionNotFoundError:
raise cmdexc.CommandError("Session {} not found!".format(name))
except (OSError, SessionError) as e:
except SessionError as e:
log.sessions.exception("Error while deleting session!")
raise cmdexc.CommandError("Error while deleting session: {}"
.format(e))

View File

@ -64,8 +64,7 @@ def get_argparser():
help="How URLs should be opened if there is already a "
"qutebrowser instance running.")
parser.add_argument('--backend', choices=['webkit', 'webengine'],
help="Which backend to use (webengine backend is "
"EXPERIMENTAL!).")
help="Which backend to use.")
parser.add_argument('--enable-webengine-inspector', action='store_true',
help="Enable the web inspector for QtWebEngine. Note "
"that this is a SECURITY RISK and you should not "

View File

@ -186,6 +186,7 @@ def _module_versions():
('yaml', ['__version__']),
('cssutils', ['__version__']),
('typing', []),
('OpenGL', ['__version__']),
('PyQt5.QtWebEngineWidgets', []),
('PyQt5.QtWebKitWidgets', []),
])

View File

@ -7,3 +7,4 @@ MarkupSafe==1.0
Pygments==2.2.0
pyPEG2==2.15.2
PyYAML==3.12
PyOpenGL==3.1.0

View File

@ -64,7 +64,7 @@ def call_tox(toxenv, *args, python=sys.executable):
env['PYTHON'] = python
env['PATH'] = os.environ['PATH'] + os.pathsep + os.path.dirname(python)
subprocess.check_call(
[sys.executable, '-m', 'tox', '-v', '-e', toxenv] + list(args),
[sys.executable, '-m', 'tox', '-vv', '-e', toxenv] + list(args),
env=env)
@ -109,8 +109,11 @@ def patch_osx_app():
for f in glob.glob(os.path.join(qtwe_core_dir, 'Resources', '*')):
dest = os.path.join(app_path, 'Contents', 'Resources')
if os.path.isdir(f):
shutil.copytree(f, os.path.join(dest, f))
dir_dest = os.path.join(dest, os.path.basename(f))
print("Copying directory {} to {}".format(f, dir_dest))
shutil.copytree(f, dir_dest)
else:
print("Copying {} to {}".format(f, dest))
shutil.copy(f, dest)
# Link dependencies
for lib in ['QtCore', 'QtWebEngineCore', 'QtQuick', 'QtQml', 'QtNetwork',
@ -124,7 +127,16 @@ def patch_osx_app():
def build_osx():
"""Build OS X .dmg/.app."""
utils.print_title("Cleaning up...")
for f in ['wc.dmg', 'template.dmg']:
try:
os.remove(f)
except FileNotFoundError:
pass
for d in ['dist', 'build']:
shutil.rmtree(d, ignore_errors=True)
utils.print_title("Updating 3rdparty content")
# Currently disabled because QtWebEngine has no pdfjs support
# update_3rdparty.run(ace=False, pdfjs=True, fancy_dmg=False)
utils.print_title("Building .app via pyinstaller")
call_tox('pyinstaller', '-r')
@ -132,25 +144,24 @@ def build_osx():
patch_osx_app()
utils.print_title("Building .dmg")
subprocess.check_call(['make', '-f', 'scripts/dev/Makefile-dmg'])
utils.print_title("Cleaning up...")
for f in ['wc.dmg', 'template.dmg']:
os.remove(f)
for d in ['dist', 'build']:
shutil.rmtree(d)
dmg_name = 'qutebrowser-{}.dmg'.format(qutebrowser.__version__)
os.rename('qutebrowser.dmg', dmg_name)
utils.print_title("Running smoke test")
with tempfile.TemporaryDirectory() as tmpdir:
subprocess.check_call(['hdiutil', 'attach', dmg_name,
'-mountpoint', tmpdir])
try:
binary = os.path.join(tmpdir, 'qutebrowser.app', 'Contents',
'MacOS', 'qutebrowser')
smoke_test(binary)
finally:
subprocess.check_call(['hdiutil', 'detach', tmpdir])
try:
with tempfile.TemporaryDirectory() as tmpdir:
subprocess.check_call(['hdiutil', 'attach', dmg_name,
'-mountpoint', tmpdir])
try:
binary = os.path.join(tmpdir, 'qutebrowser.app', 'Contents',
'MacOS', 'qutebrowser')
smoke_test(binary)
finally:
subprocess.call(['hdiutil', 'detach', tmpdir])
except PermissionError as e:
print("Failed to remove tempdir: {}".format(e))
return [(dmg_name, 'application/x-apple-diskimage', 'OS X .dmg')]
@ -167,6 +178,7 @@ def patch_windows(out_dir):
def build_windows():
"""Build windows executables/setups."""
utils.print_title("Updating 3rdparty content")
# Currently disabled because QtWebEngine has no pdfjs support
# update_3rdparty.run(ace=False, pdfjs=True, fancy_dmg=False)
utils.print_title("Building Windows binaries")
@ -203,8 +215,8 @@ def build_windows():
'/DVERSION={}'.format(qutebrowser.__version__),
'misc/qutebrowser.nsi'])
name_32 = 'qutebrowser-{}-win32.msi'.format(qutebrowser.__version__)
name_64 = 'qutebrowser-{}-amd64.msi'.format(qutebrowser.__version__)
name_32 = 'qutebrowser-{}-win32.exe'.format(qutebrowser.__version__)
name_64 = 'qutebrowser-{}-amd64.exe'.format(qutebrowser.__version__)
artifacts += [
(os.path.join('dist', name_32),

View File

@ -43,6 +43,12 @@ travis_retry() {
}
apt_install() {
sudo tee /etc/apt/sources.list <<EOF
deb http://us.archive.ubuntu.com/ubuntu/ trusty main
deb http://us.archive.ubuntu.com/ubuntu/ trusty-security main
deb http://us.archive.ubuntu.com/ubuntu/ trusty-updates main
EOF
sudo rm -rf /etc/apt/sources.list.d
travis_retry sudo apt-get -y -q update
travis_retry sudo apt-get -y -q install --no-install-recommends "$@"
}
@ -64,8 +70,9 @@ npm_install() {
}
install_node() {
curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
apt_install nodejs
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
travis_retry sudo apt-get -y -q update
travis_retry sudo apt-get -y -q install --no-install-recommends nodejs
}
check_pyqt() {

View File

@ -365,8 +365,7 @@ def generate_commands(filename):
def _generate_setting_section(f, sectname, sect):
"""Generate documentation for a single section."""
version_dependent_options = [('network', 'proxy'),
('general', 'print-element-backgrounds')]
version_dependent_options = [('general', 'print-element-backgrounds')]
for optname, option in sect.items():
f.write("\n")
f.write('[[{}-{}]]'.format(sectname, optname) + "\n")

View File

@ -579,9 +579,9 @@ Feature: Downloading things from a website.
And I wait until the download is finished
Then the downloaded file content-size should exist
@posix
Scenario: Downloading to unwritable destination
When I set storage -> prompt-download-directory to false
When the unwritable dir is unwritable
And I set storage -> prompt-download-directory to false
And I run :download http://localhost:(port)/data/downloads/download.bin --dest (tmpdir)/downloads/unwritable
Then the error "Download error: Permission denied" should be shown

View File

@ -50,7 +50,7 @@ Feature: Javascript stuff
And I open data/javascript/window_open.html in a new tab
And I run :click-element id open-normal
And I wait for "Changing title for idx 2 to 'about:blank'" in the log
And I run :tab-focus 2
And I run :buffer window_open.html
And I run :click-element id close-twice
And I wait for "Focus object changed: *" in the log
Then no crash should happen

View File

@ -292,6 +292,13 @@ Feature: Scrolling
And I run :scroll-page --bottom-navigate next 0 1
Then data/hello2.txt should be loaded
Scenario: :scroll-page with --bottom-navigate when not at the bottom
When I run :scroll-px 0 10
And I wait until the scroll position changed
And I run :scroll-page --bottom-navigate next 0 1
Then the following tabs should be open:
- data/scroll/simple.html
Scenario: :scroll-page with --top-navigate
When I run :scroll-page --top-navigate prev 0 -1
Then data/hello3.txt should be loaded

View File

@ -236,6 +236,18 @@ Feature: Tab management
- data/numbers/2.txt
- data/numbers/3.txt
Scenario: :tab-focus with current tab number
When I open data/numbers/1.txt
And I open data/numbers/2.txt in a new tab
And I open data/numbers/3.txt in a new tab
And I run :tab-focus 1
And I run :tab-focus 3
And I run :tab-focus 3
Then the following tabs should be open:
- data/numbers/1.txt (active)
- data/numbers/2.txt
- data/numbers/3.txt
Scenario: :tab-focus with -1
When I open data/numbers/1.txt
And I open data/numbers/2.txt in a new tab
@ -1061,6 +1073,16 @@ Feature: Tab management
- data/numbers/2.txt (pinned)
- data/numbers/3.txt (active)
Scenario: :tab-pin with an invalid count
When I open data/numbers/1.txt
And I open data/numbers/2.txt in a new tab
And I open data/numbers/3.txt in a new tab
And I run :tab-pin with count 23
Then the following tabs should be open:
- data/numbers/1.txt
- data/numbers/2.txt
- data/numbers/3.txt (active)
Scenario: Pinned :tab-close prompt yes
When I open data/numbers/1.txt
And I run :tab-pin

View File

@ -21,6 +21,7 @@ import os
import sys
import shlex
import pytest
import pytest_bdd as bdd
bdd.scenarios('downloads.feature')
@ -53,6 +54,14 @@ def clean_old_downloads(quteproc):
quteproc.send_cmd(':download-clear')
@bdd.when("the unwritable dir is unwritable")
def check_unwritable(tmpdir):
unwritable = tmpdir / 'downloads' / 'unwritable'
if os.access(str(unwritable), os.W_OK):
# Docker container or similar
pytest.skip("Unwritable dir was writable")
@bdd.when("I wait until the download is finished")
def wait_for_download_finished(quteproc):
quteproc.wait_for(category='downloads', message='Download * finished')

View File

@ -51,6 +51,11 @@ Feature: Zooming in and out
Then the message "Zoom level: 50%" should be shown
And the zoom should be 50%
Scenario: Setting zoom with trailing %
When I run :zoom 50%
Then the message "Zoom level: 50%" should be shown
And the zoom should be 50%
Scenario: Setting zoom with count
When I run :zoom with count 40
Then the message "Zoom level: 40%" should be shown

View File

@ -584,6 +584,9 @@ class TabbedBrowserStub(QObject):
self.tabs = []
self.shutting_down = False
self._qtabbar = QTabBar()
self.index_of = None
self.current_index = None
self.opened_url = None
def count(self):
return len(self.tabs)
@ -600,6 +603,26 @@ class TabbedBrowserStub(QObject):
def tabBar(self):
return self._qtabbar
def indexOf(self, _tab):
if self.index_of is None:
raise ValueError("indexOf got called with index_of None!")
elif self.index_of is RuntimeError:
raise RuntimeError
else:
return self.index_of
def currentIndex(self):
if self.current_index is None:
raise ValueError("currentIndex got called with current_index "
"None!")
return self.current_index
def currentWidget(self):
return self.tabs[self.currentIndex() - 1]
def tabopen(self, url):
self.opened_url = url
class ApplicationStub(QObject):

View File

@ -1,53 +0,0 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2015-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 collections
import pytest
from qutebrowser.browser import commands
from qutebrowser.mainwindow import tabbedbrowser
from qutebrowser.utils import objreg
from qutebrowser.keyinput import modeman
ObjectsRet = collections.namedtuple('Dispatcher', ['tb', 'cd'])
pytestmark = pytest.mark.usefixtures('cookiejar_and_cache')
@pytest.fixture
def objects(qtbot, default_config, key_config_stub, tab_registry,
host_blocker_stub):
"""Fixture providing a CommandDispatcher and a fake TabbedBrowser."""
win_id = 0
modeman.init(win_id, parent=None)
tabbed_browser = tabbedbrowser.TabbedBrowser(win_id)
qtbot.add_widget(tabbed_browser)
objreg.register('tabbed-browser', tabbed_browser, scope='window',
window=win_id)
dispatcher = commands.CommandDispatcher(win_id, tabbed_browser)
objreg.register('command-dispatcher', dispatcher, scope='window',
window=win_id)
yield ObjectsRet(tabbed_browser, dispatcher)
@pytest.mark.skipif(True, reason="Work in progress")
def test_openurl(objects):
objects.cd.openurl('localhost')

View File

@ -29,27 +29,6 @@ from qutebrowser.browser import signalfilter
from qutebrowser.utils import objreg
class FakeTabbedBrowser:
def __init__(self):
self.index_of = None
self.current_index = None
def indexOf(self, _tab):
if self.index_of is None:
raise ValueError("indexOf got called with index_of None!")
elif self.index_of is RuntimeError:
raise RuntimeError
else:
return self.index_of
def currentIndex(self):
if self.current_index is None:
raise ValueError("currentIndex got called with current_index "
"None!")
return self.current_index
class Signaller(QObject):
signal = pyqtSignal(str)
@ -84,8 +63,8 @@ def objects():
@pytest.fixture
def tabbed_browser(win_registry):
tb = FakeTabbedBrowser()
def tabbed_browser(stubs, win_registry):
tb = stubs.TabbedBrowserStub()
objreg.register('tabbed-browser', tb, scope='window', window=0)
yield tb
objreg.delete('tabbed-browser', scope='window', window=0)

View File

@ -31,15 +31,6 @@ from qutebrowser.utils import usertypes, objreg
Enum = usertypes.enum('Enum', ['foo', 'foo_bar'])
class FakeTabbedBrowser:
def __init__(self):
self.opened_url = None
def tabopen(self, url):
self.opened_url = url
class TestArgumentParser:
@pytest.fixture
@ -47,8 +38,8 @@ class TestArgumentParser:
return argparser.ArgumentParser('foo')
@pytest.fixture
def tabbed_browser(self, win_registry):
tb = FakeTabbedBrowser()
def tabbed_browser(self, stubs, win_registry):
tb = stubs.TabbedBrowserStub()
objreg.register('tabbed-browser', tb, scope='window', window=0)
yield tb
objreg.delete('tabbed-browser', scope='window', window=0)

View File

@ -0,0 +1,251 @@
[general]
ignore-case = smart
startpage = https://start.duckduckgo.com
yank-ignored-url-parameters = ref,utm_source,utm_medium,utm_campaign,utm_term,utm_content
default-open-dispatcher =
default-page = ${startpage}
auto-search = naive
auto-save-config = true
auto-save-interval = 15000
editor = gvim -f "{}"
editor-encoding = utf-8
private-browsing = false
developer-extras = false
print-element-backgrounds = true
xss-auditing = false
default-encoding = iso-8859-1
new-instance-open-target = tab
new-instance-open-target.window = last-focused
log-javascript-console = debug
save-session = false
session-default-name =
url-incdec-segments = path,query
[ui]
history-session-interval = 30
zoom-levels = 25%,33%,50%,67%,75%,90%,100%,110%,125%,150%,175%,200%,250%,300%,400%,500%
default-zoom = 100%
downloads-position = top
status-position = bottom
message-timeout = 2000
message-unfocused = false
confirm-quit = never
zoom-text-only = false
frame-flattening = false
user-stylesheet =
hide-scrollbar = true
smooth-scrolling = false
remove-finished-downloads = -1
hide-statusbar = false
statusbar-padding = 1,1,0,0
window-title-format = {perc}{title}{title_sep}qutebrowser
modal-js-dialog = false
hide-wayland-decoration = false
keyhint-blacklist =
keyhint-delay = 500
prompt-radius = 8
prompt-filebrowser = true
[network]
do-not-track = true
accept-language = en-US,en
referer-header = same-domain
user-agent =
proxy = system
proxy-dns-requests = true
ssl-strict = ask
dns-prefetch = true
custom-headers =
netrc-file =
[completion]
show = always
download-path-suggestion = path
timestamp-format = %Y-%m-%d
height = 50%
cmd-history-max-items = 100
web-history-max-items = 1000
quick-complete = true
shrink = false
scrollbar-width = 12
scrollbar-padding = 2
[input]
timeout = 500
partial-timeout = 5000
insert-mode-on-plugins = false
auto-leave-insert-mode = true
auto-insert-mode = false
forward-unbound-keys = auto
spatial-navigation = false
links-included-in-focus-chain = true
rocker-gestures = false
mouse-zoom-divider = 512
[tabs]
background-tabs = false
select-on-remove = next
new-tab-position = next
new-tab-position-explicit = last
last-close = ignore
show = always
show-switching-delay = 800
wrap = true
movable = true
close-mouse-button = middle
position = top
show-favicons = true
favicon-scale = 1.0
width = 20%
pinned-width = 43
indicator-width = 3
tabs-are-windows = false
title-format = {index}: {title}
title-format-pinned = {index}
title-alignment = left
mousewheel-tab-switching = true
padding = 0,0,5,5
indicator-padding = 2,2,0,4
[storage]
download-directory =
prompt-download-directory = true
remember-download-directory = true
maximum-pages-in-cache = 0
offline-web-application-cache = true
local-storage = true
cache-size =
[content]
allow-images = true
allow-javascript = true
allow-plugins = false
webgl = true
hyperlink-auditing = false
geolocation = ask
notifications = ask
media-capture = ask
javascript-can-open-windows-automatically = false
javascript-can-close-windows = false
javascript-can-access-clipboard = false
ignore-javascript-prompt = false
ignore-javascript-alert = false
local-content-can-access-remote-urls = false
local-content-can-access-file-urls = true
cookies-accept = no-3rdparty
cookies-store = true
host-block-lists = https://www.malwaredomainlist.com/hostslist/hosts.txt,http://someonewhocares.org/hosts/hosts,http://winhelp2002.mvps.org/hosts.zip,http://malwaredomains.lehigh.edu/files/justdomains.zip,https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&mimetype=plaintext
host-blocking-enabled = true
host-blocking-whitelist = piwik.org
enable-pdfjs = false
[hints]
border = 1px solid #E3BE23
mode = letter
chars = asdfghjkl
min-chars = 1
scatter = true
uppercase = false
dictionary = /usr/share/dict/words
auto-follow = unique-match
auto-follow-timeout = 0
next-regexes = \bnext\b,\bmore\b,\bnewer\b,\b[>→≫]\b,\b(>>|»)\b,\bcontinue\b
prev-regexes = \bprev(ious)?\b,\bback\b,\bolder\b,\b[<←≪]\b,\b(<<|«)\b
find-implementation = python
hide-unmatched-rapid-hints = true
[searchengines]
DEFAULT = https://duckduckgo.com/?q={}
[aliases]
[colors]
completion.fg = white
completion.bg = #333333
completion.alternate-bg = #444444
completion.category.fg = white
completion.category.bg = qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #888888, stop:1 #505050)
completion.category.border.top = black
completion.category.border.bottom = ${completion.category.border.top}
completion.item.selected.fg = black
completion.item.selected.bg = #e8c000
completion.item.selected.border.top = #bbbb00
completion.item.selected.border.bottom = ${completion.item.selected.border.top}
completion.match.fg = #ff4444
completion.scrollbar.fg = ${completion.fg}
completion.scrollbar.bg = ${completion.bg}
statusbar.fg = white
statusbar.bg = black
statusbar.fg.private = ${statusbar.fg}
statusbar.bg.private = #666666
statusbar.fg.insert = ${statusbar.fg}
statusbar.bg.insert = darkgreen
statusbar.fg.command = ${statusbar.fg}
statusbar.bg.command = ${statusbar.bg}
statusbar.fg.command.private = ${statusbar.fg.private}
statusbar.bg.command.private = ${statusbar.bg.private}
statusbar.fg.caret = ${statusbar.fg}
statusbar.bg.caret = purple
statusbar.fg.caret-selection = ${statusbar.fg}
statusbar.bg.caret-selection = #a12dff
statusbar.progress.bg = white
statusbar.url.fg = ${statusbar.fg}
statusbar.url.fg.success = white
statusbar.url.fg.success.https = lime
statusbar.url.fg.error = orange
statusbar.url.fg.warn = yellow
statusbar.url.fg.hover = aqua
tabs.fg.odd = white
tabs.bg.odd = grey
tabs.fg.even = white
tabs.bg.even = darkgrey
tabs.fg.selected.odd = white
tabs.bg.selected.odd = black
tabs.fg.selected.even = ${tabs.fg.selected.odd}
tabs.bg.selected.even = ${tabs.bg.selected.odd}
tabs.bg.bar = #555555
tabs.indicator.start = #0000aa
tabs.indicator.stop = #00aa00
tabs.indicator.error = #ff0000
tabs.indicator.system = rgb
hints.fg = black
hints.bg = qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 247, 133, 0.8), stop:1 rgba(255, 197, 66, 0.8))
hints.fg.match = green
downloads.bg.bar = black
downloads.fg.start = white
downloads.bg.start = #0000aa
downloads.fg.stop = ${downloads.fg.start}
downloads.bg.stop = #00aa00
downloads.fg.system = rgb
downloads.bg.system = rgb
downloads.fg.error = white
downloads.bg.error = red
webpage.bg = white
keyhint.fg = #FFFFFF
keyhint.fg.suffix = #FFFF00
keyhint.bg = rgba(0, 0, 0, 80%)
messages.fg.error = white
messages.bg.error = red
messages.border.error = #bb0000
messages.fg.warning = white
messages.bg.warning = darkorange
messages.border.warning = #d47300
messages.fg.info = white
messages.bg.info = black
messages.border.info = #333333
prompts.fg = white
prompts.bg = darkblue
prompts.selected.bg = #308cc6
[fonts]
_monospace = xos4 Terminus, Terminus, Monospace, "DejaVu Sans Mono", Monaco, "Bitstream Vera Sans Mono", "Andale Mono", "Courier New", Courier, "Liberation Mono", monospace, Fixed, Consolas, Terminal
completion = 8pt ${_monospace}
completion.category = bold ${completion}
tabbar = 8pt ${_monospace}
statusbar = 8pt ${_monospace}
downloads = 8pt ${_monospace}
hints = bold 13px ${_monospace}
debug-console = 8pt ${_monospace}
web-family-standard =
web-family-fixed =
web-family-serif =
web-family-sans-serif =
web-family-cursive =
web-family-fantasy =
web-size-minimum = 0
web-size-minimum-logical = 6
web-size-default = 16
web-size-default-fixed = 13
keyhint = 8pt ${_monospace}
messages.error = 8pt ${_monospace}
messages.warning = 8pt ${_monospace}
messages.info = 8pt ${_monospace}
prompts = 8pt sans-serif

View File

@ -408,7 +408,7 @@ class TestDefaultConfig:
If it did change, place a new qutebrowser-vx.y.z.conf in old_configs
and then increment the version.
"""
assert qutebrowser.__version__ == '0.10.1'
assert qutebrowser.__version__ == '0.11.0'
@pytest.mark.parametrize('filename',
os.listdir(os.path.join(os.path.dirname(__file__), 'old_configs')),

View File

@ -123,24 +123,30 @@ class TestFileHandling:
os.remove(filename)
@pytest.mark.posix
def test_unreadable(self, message_mock, editor, caplog):
"""Test file handling when closing with an unreadable file."""
editor.edit("")
filename = editor._file.name
assert os.path.exists(filename)
os.chmod(filename, 0o077)
if os.access(filename, os.R_OK):
# Docker container or similar
pytest.skip("File was still readable")
with caplog.at_level(logging.ERROR):
editor._proc.finished.emit(0, QProcess.NormalExit)
assert not os.path.exists(filename)
msg = message_mock.getmsg(usertypes.MessageLevel.error)
assert msg.text.startswith("Failed to read back edited file: ")
@pytest.mark.posix
def test_unwritable(self, monkeypatch, message_mock, editor, tmpdir,
caplog):
"""Test file handling when the initial file is not writable."""
tmpdir.chmod(0)
if os.access(str(tmpdir), os.W_OK):
# Docker container or similar
pytest.skip("File was still writable")
monkeypatch.setattr(editormod.tempfile, 'tempdir', str(tmpdir))
with caplog.at_level(logging.ERROR):

View File

@ -137,20 +137,6 @@ class FakeMainWindow(QObject):
return self._geometry
class FakeTabbedBrowser:
"""A fake tabbed-browser which contains some widgets."""
def __init__(self, widgets):
self._widgets = widgets
def widgets(self):
return self._widgets
def currentIndex(self):
return 1
@pytest.fixture
def fake_window(win_registry, stubs, monkeypatch, qtbot):
"""Fixture which provides a fake main windows with a tabbedbrowser."""
@ -159,7 +145,7 @@ def fake_window(win_registry, stubs, monkeypatch, qtbot):
webview = QWebView()
qtbot.add_widget(webview)
browser = FakeTabbedBrowser([webview])
browser = stubs.TabbedBrowserStub([webview])
objreg.register('tabbed-browser', browser, scope='window', window=0)
yield
@ -211,7 +197,7 @@ class TestSave:
"""Fixture which provides a window with a fake history."""
win = FakeMainWindow(b'fake-geometry-0', win_id=0)
objreg.register('main-window', win, scope='window', window=0)
browser = FakeTabbedBrowser([webview])
browser = stubs.TabbedBrowserStub([webview])
objreg.register('tabbed-browser', browser, scope='window', window=0)
qapp = stubs.FakeQApplication(active_window=win)

View File

@ -496,6 +496,7 @@ class ImportFake:
'typing': True,
'PyQt5.QtWebEngineWidgets': True,
'PyQt5.QtWebKitWidgets': True,
'OpenGL': True,
}
self.version_attribute = '__version__'
self.version = '1.2.3'
@ -555,7 +556,7 @@ class TestModuleVersions:
"""Test with all modules present in version 1.2.3."""
expected = ['sip: yes', 'colorama: 1.2.3', 'pypeg2: 1.2.3',
'jinja2: 1.2.3', 'pygments: 1.2.3', 'yaml: 1.2.3',
'cssutils: 1.2.3', 'typing: yes',
'cssutils: 1.2.3', 'typing: yes', 'OpenGL: 1.2.3',
'PyQt5.QtWebEngineWidgets: yes',
'PyQt5.QtWebKitWidgets: yes']
assert version._module_versions() == expected
@ -579,17 +580,17 @@ class TestModuleVersions:
@pytest.mark.parametrize('value, expected', [
('VERSION', ['sip: yes', 'colorama: 1.2.3', 'pypeg2: yes',
'jinja2: yes', 'pygments: yes', 'yaml: yes',
'cssutils: yes', 'typing: yes',
'cssutils: yes', 'typing: yes', 'OpenGL: yes',
'PyQt5.QtWebEngineWidgets: yes',
'PyQt5.QtWebKitWidgets: yes']),
('SIP_VERSION_STR', ['sip: 1.2.3', 'colorama: yes', 'pypeg2: yes',
'jinja2: yes', 'pygments: yes', 'yaml: yes',
'cssutils: yes', 'typing: yes',
'cssutils: yes', 'typing: yes', 'OpenGL: yes',
'PyQt5.QtWebEngineWidgets: yes',
'PyQt5.QtWebKitWidgets: yes']),
(None, ['sip: yes', 'colorama: yes', 'pypeg2: yes', 'jinja2: yes',
'pygments: yes', 'yaml: yes', 'cssutils: yes', 'typing: yes',
'PyQt5.QtWebEngineWidgets: yes',
'OpenGL: yes', 'PyQt5.QtWebEngineWidgets: yes',
'PyQt5.QtWebKitWidgets: yes']),
])
def test_version_attribute(self, value, expected, import_fake):
@ -807,7 +808,7 @@ def test_chromium_version_unpatched(qapp):
(True, False, True, False, True), # no webkit
(True, False, True, 'ng', True), # QtWebKit-NG
(True, False, True, True, False), # unknown Linux distribution
])
]) # pylint: disable=too-many-locals
def test_version_output(git_commit, frozen, style, with_webkit,
known_distribution, stubs, monkeypatch, init_sql):
"""Test version.version()."""

24
tox.ini
View File

@ -4,7 +4,7 @@
# and then run "tox" from this directory.
[tox]
envlist = py34,py35,py36-cov,misc,vulture,flake8,pylint,pyroma,check-manifest
envlist = py36-cov,misc,vulture,flake8,pylint,pyroma,check-manifest,eslint
distshare = {toxworkdir}
skipsdist = true
@ -111,6 +111,28 @@ deps =
PyQt5==5.8.2
commands = {envpython} -bb -m pytest {posargs:tests}
[testenv:py35-pyqt59]
basepython = python3.5
setenv =
{[testenv]setenv}
QUTE_BDD_WEBENGINE=true
passenv = {[testenv]passenv}
deps =
{[testenv]deps}
PyQt5==5.9
commands = {envpython} -bb -m pytest {posargs:tests}
[testenv:py36-pyqt59]
basepython = {env:PYTHON:python3.6}
setenv =
{[testenv]setenv}
QUTE_BDD_WEBENGINE=true
passenv = {[testenv]passenv}
deps =
{[testenv]deps}
PyQt5==5.9
commands = {envpython} -bb -m pytest {posargs:tests}
# other envs
[testenv:mkvenv]