Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
612afc45ef | ||
|
|
3050c09150 | ||
|
|
b44d7c0b84 | ||
|
|
b852daeeae | ||
|
|
f146003858 | ||
|
|
a09503d5b5 | ||
|
|
659fa02613 | ||
|
|
ecfdf7b077 | ||
|
|
cacc42417b | ||
|
|
2403e5b792 | ||
|
|
9b05455c40 | ||
|
|
e957796915 | ||
|
|
1de82a2e63 | ||
|
|
54eed6a88f | ||
|
|
c0bc6368d1 | ||
|
|
51549fc17f | ||
|
|
38a236a31a | ||
|
|
a065568549 | ||
|
|
4abd7089ed | ||
|
|
d37064aa5a | ||
|
|
9625791018 | ||
|
|
5c9718c8cd | ||
|
|
7655313d39 | ||
|
|
c42c19683a | ||
|
|
2f55e216b0 | ||
|
|
a5264bdebd | ||
|
|
5f310b4385 | ||
|
|
b2a01934b6 | ||
|
|
00003e4ff6 | ||
|
|
30ac341b8e | ||
|
|
49943efa87 | ||
|
|
bfd2ef830e | ||
|
|
6f831c292e | ||
|
|
0842dc1bf3 | ||
|
|
302929be9d | ||
|
|
8011a3c63d | ||
|
|
d9d5b2df0c | ||
|
|
d6fd5a817e | ||
|
|
301186d407 | ||
|
|
ab121a98da | ||
|
|
a463038834 | ||
|
|
22761b4373 | ||
|
|
78f6f3a0e1 | ||
|
|
6166ea51e2 | ||
|
|
4d4065dfac | ||
|
|
81f350ee99 | ||
|
|
4b98e6e9ce | ||
|
|
11f8ab1f85 | ||
|
|
0449da048f | ||
|
|
c78e938dea | ||
|
|
99fb8a5d87 | ||
|
|
b1e0b8f119 | ||
|
|
8d49e001e9 | ||
|
|
965c176acf | ||
|
|
896da1c27e | ||
|
|
8f33fcfc52 | ||
|
|
91b0a33ab0 | ||
|
|
b059f4058f | ||
|
|
b63ce438b4 |
@@ -130,12 +130,15 @@ Contributors, sorted by the number of commits in descending order:
|
||||
* rikn00
|
||||
* Brian Jackson
|
||||
* Martin Zimmermann
|
||||
* Error 800
|
||||
* Mathias Fussenegger
|
||||
* Larry Hynes
|
||||
* Johannes Altmanninger
|
||||
* Joel Torstensson
|
||||
* Thorsten Wißmann
|
||||
* Regina Hug
|
||||
* Peter Vilim
|
||||
* Matthias Lisin
|
||||
* Helen Sherwood-Taylor
|
||||
// QUTE_AUTHORS_END
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|<<general-site-specific-quirks,site-specific-quirks>>|Enable workarounds for broken sites.
|
||||
|<<general-default-encoding,default-encoding>>|Default encoding to use for websites.
|
||||
|<<general-new-instance-open-target,new-instance-open-target>>|How to open links in an existing instance if a new one is launched.
|
||||
|<<general-log-javascript-console,log-javascript-console>>|Whether to log javascript console messages.
|
||||
|==============
|
||||
|
||||
.Quick reference for section ``ui''
|
||||
@@ -361,6 +362,17 @@ Valid values:
|
||||
|
||||
Default: +pass:[window]+
|
||||
|
||||
[[general-log-javascript-console]]
|
||||
=== log-javascript-console
|
||||
Whether to log javascript console messages.
|
||||
|
||||
Valid values:
|
||||
|
||||
* +true+
|
||||
* +false+
|
||||
|
||||
Default: +pass:[false]+
|
||||
|
||||
== ui
|
||||
General options related to the user interface.
|
||||
|
||||
@@ -1026,7 +1038,7 @@ The file can be in one of the following formats:
|
||||
- One host per line
|
||||
- A zip-file of any of the above, with either only one file, or a file named 'hosts' (with any extension).
|
||||
|
||||
Default: +pass:[http://www.malwaredomainlist.com/hostslist/hosts.txt,http://someonewhocares.org/hosts/hosts,http://winhelp2002.mvps.org/hosts.zip,http://malwaredomains.lehigh.edu/files/justdomains.zip,http://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&mimetype=plaintext,http://hosts-file.net/ad_servers.asp]+
|
||||
Default: +pass:[http://www.malwaredomainlist.com/hostslist/hosts.txt,http://someonewhocares.org/hosts/hosts,http://winhelp2002.mvps.org/hosts.zip,http://malwaredomains.lehigh.edu/files/justdomains.zip,http://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&mimetype=plaintext]+
|
||||
|
||||
== hints
|
||||
Hinting settings.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
Getting stacktraces on crashes
|
||||
==============================
|
||||
:toc:
|
||||
The Compiler <mail@qutebrowser.org>
|
||||
|
||||
When there is a fatal crash in qutebrowser - most of the times a
|
||||
@@ -14,10 +15,17 @@ https://en.wikipedia.org/wiki/Debug_symbol[debugging symbols] is required.
|
||||
The rest of this guide is quite Linux specific, though there is a
|
||||
<<windows,section for Windows>> at the end.
|
||||
|
||||
Getting debugging symbols
|
||||
-------------------------
|
||||
Crashes which can be reproduced
|
||||
-------------------------------
|
||||
|
||||
.Debian/Ubuntu/...
|
||||
If a crash can be reproduced, packages with debugging symbols should be
|
||||
installed, and the crash should be reproduced under gdb.
|
||||
|
||||
Getting debugging symbols
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Debian/Ubuntu/...
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
For Debian based systems (Debian, Ubuntu, Linux Mint, ...), debug information
|
||||
is available in the repositories:
|
||||
@@ -26,76 +34,66 @@ is available in the repositories:
|
||||
# apt-get install python3-pyqt5-dbg python3-pyqt5.qtwebkit-dbg python3-dbg libqt5webkit5-dbg
|
||||
----
|
||||
|
||||
.Archlinux
|
||||
Archlinux
|
||||
^^^^^^^^^
|
||||
|
||||
For Archlinux, no debug informations are provided. You can either compile Qt
|
||||
yourself (which will take a few hours even on a modern machine) or use
|
||||
debugging symbols compiled by me (x86_64 only).
|
||||
debugging symbols compiled/packaged by me (x86_64 only).
|
||||
|
||||
To compile by yourself:
|
||||
.To compile by yourself
|
||||
|
||||
----
|
||||
$ git clone https://github.com/The-Compiler/qt-debug-pkgbuild.git
|
||||
$ cd qt-debug-pkgbuild
|
||||
$ git checkout symbols
|
||||
$ export DEBUG_CFLAGS='-ggdb3 -fvar-tracking-assignments -Og'
|
||||
$ export DEBUG_CXXFLAGS='-ggdb3 -fvar-tracking-assignments -Og'
|
||||
$ cd qt5
|
||||
$ makepkg -si
|
||||
$ makepkg -si --pkg qt5-base,qt5-webkit
|
||||
$ cd ../pyqt5
|
||||
$ makepkg -si
|
||||
$ makepkg -si --pkg pyqt5-common,python-pyqt5
|
||||
----
|
||||
|
||||
To install my pre-built packages:
|
||||
.To install my pre-built packages
|
||||
|
||||
First download and sign the key:
|
||||
|
||||
----
|
||||
$ mkdir qt-debug
|
||||
$ cd qt-debug
|
||||
$ wget -r -l1 -A '*.tar.xz' -L -np -nd http://www.qutebrowser.org/qt-symbols-pkg/
|
||||
# pacman -U *.pkg.tar.xz
|
||||
# pacman-key -r 0xD6A1C70FE80A0C82
|
||||
$ pacman-key -f 0xD6A1C70FE80A0C82
|
||||
Key fingerprint = 14AF EC28 70C6 4863 C5C7 ACCB D6A1 C70F E80A 0C82
|
||||
# pacman-key --lsign-key 0xD6A1C70FE80A0C82
|
||||
----
|
||||
|
||||
After you are done debugging, make sure to install the system packages again so
|
||||
you get updates. This can be done with this command:
|
||||
Then edit your `/etc/pacman.conf` to add the repository to the bottom:
|
||||
|
||||
----
|
||||
# pacman -S qt5
|
||||
[qt-debug]
|
||||
Server = http://qutebrowser.org/qt-debug/$arch
|
||||
----
|
||||
|
||||
Getting a core dump
|
||||
-------------------
|
||||
Then install the packages:
|
||||
|
||||
The next step is finding the core dump so we can get a stacktrace from it.
|
||||
----
|
||||
# pacman -Sy pyqt5-common-debug python-pyqt5-debug qt5-base-debug qt5-webkit-debug
|
||||
----
|
||||
|
||||
First of all, try to reproduce your problem. If you can, run qutebrowser
|
||||
directly inside gdb like this:
|
||||
The `-debug` packages conflict with the non-debug variants - it's safe to
|
||||
remove them.
|
||||
|
||||
Getting the stack trace
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
First install `gdb` on your system if it's not installed already.
|
||||
|
||||
Then run qutebrowser directly inside gdb like this:
|
||||
|
||||
----
|
||||
$ gdb $(which python3) -ex 'run -m qutebrowser --debug'
|
||||
----
|
||||
|
||||
If you cannot reproduce the problem, you need to check if a coredump got
|
||||
written somewhere.
|
||||
|
||||
Check the file `/proc/sys/kernel/core_pattern` on your system. If it does not
|
||||
start with a `|` character (pipe), check if there is a file named `core` or
|
||||
`core.NNNN` in the directory from that file, or in the current directory.
|
||||
|
||||
If so, execute gdb like this:
|
||||
|
||||
----
|
||||
$ gdb $(which python3) /path/to/core
|
||||
----
|
||||
|
||||
If your `/proc/sys/kernel/core_pattern` contains something like
|
||||
`|/usr/lib/systemd/systemd-coredump`, use `coredumpctl` as root to run gdb:
|
||||
|
||||
----
|
||||
# coredumpctl gdb $(which python3)
|
||||
----
|
||||
|
||||
Getting a stack trace
|
||||
---------------------
|
||||
|
||||
Regardless of the way you used to open gdb, you should now see something like:
|
||||
After you reproduce the crash, you should now see something like:
|
||||
|
||||
----
|
||||
Program received signal SIGSEGV, Segmentation fault.
|
||||
@@ -107,16 +105,58 @@ Now enter these commands at the gdb prompt:
|
||||
|
||||
----
|
||||
(gdb) set logging on
|
||||
(gdb) set logging redirect on
|
||||
(gdb) bt
|
||||
(gdb) bt full
|
||||
# you might have to press enter a few times until you get the prompt back
|
||||
(gdb) set logging redirect off
|
||||
(gdb) quit
|
||||
----
|
||||
|
||||
Now copy the last few lines of the debug log (before you got the gdb prompt)
|
||||
and the full content of `gdb.txt` into the bug report. Please also add some
|
||||
words about what you were doing (or what pages you visited) before the crash
|
||||
This will create a `gdb.txt` in your current directory.
|
||||
|
||||
Copy the last few lines of the debug log (before you got the gdb prompt) and
|
||||
the full content of `gdb.txt` into the bug report. Please also add some words
|
||||
about what you were doing (or what pages you visited) before the crash
|
||||
happened.
|
||||
|
||||
Crashes which can NOT be reproduced
|
||||
-----------------------------------
|
||||
|
||||
If you cannot reproduce the problem, you need to check if a coredump got
|
||||
written somewhere. You should not install debug symbols as they won't match the
|
||||
generated coredump.
|
||||
|
||||
First install `gdb` on your system if it's not installed already.
|
||||
|
||||
Then check the file `/proc/sys/kernel/core_pattern` on your system. If it does
|
||||
not start with a `|` character (pipe), check if there is a file named `core` or
|
||||
`core.NNNN` in the directory from that file, or in the current directory.
|
||||
|
||||
If so, execute gdb like this:
|
||||
|
||||
----
|
||||
$ gdb $(which python3) /path/to/core
|
||||
----
|
||||
|
||||
If your `/proc/sys/kernel/core_pattern` contains something like
|
||||
`|/usr/lib/systemd/systemd-coredump`, use `coredumpctl` to run gdb:
|
||||
|
||||
----
|
||||
$ coredumpctl gdb $(which python3)
|
||||
----
|
||||
|
||||
Getting the stack trace
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Now enter these commands at the gdb prompt:
|
||||
|
||||
----
|
||||
(gdb) set logging on
|
||||
(gdb) bt
|
||||
# you might have to press enter a few times until you get the prompt back
|
||||
(gdb) quit
|
||||
----
|
||||
|
||||
Copy the content of `gdb.txt` into the bug report. Please also add some words
|
||||
about what you were doing (or what pages you visited) before the crash
|
||||
happened.
|
||||
|
||||
[[windows]]
|
||||
@@ -130,9 +170,9 @@ file displayed there.
|
||||
|
||||
Now install
|
||||
http://www.microsoft.com/en-us/download/details.aspx?id=42933[DebugDiag] from
|
||||
Microsoft, then run the "DebugDiag 2 Analysis" tool. There, check
|
||||
"CrashHangAnalysis" and add your crash dump via "Add Data files". Then click
|
||||
"Start analysis".
|
||||
Microsoft, then run the *DebugDiag 2 Analysis* tool. There, check
|
||||
*CrashHangAnalysis* and add your crash dump via *Add Data files*. Then click
|
||||
*Start analysis*.
|
||||
|
||||
Close the Internet Explorer which opens when it's done and use the
|
||||
folder-button at the top left to get to the reports. There find the report file
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -24,11 +24,11 @@
|
||||
import os.path
|
||||
|
||||
__author__ = "Florian Bruhin"
|
||||
__copyright__ = "Copyright 2014 Florian Bruhin (The Compiler)"
|
||||
__copyright__ = "Copyright 2014-2015 Florian Bruhin (The Compiler)"
|
||||
__license__ = "GPL"
|
||||
__maintainer__ = __author__
|
||||
__email__ = "mail@qutebrowser.org"
|
||||
__version_info__ = (0, 1, 1)
|
||||
__version_info__ = (0, 1, 3)
|
||||
__version__ = '.'.join(map(str, __version_info__))
|
||||
__description__ = "A keyboard-driven, vim-like browser based on PyQt5 and QtWebKit."
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -106,12 +106,11 @@ class Application(QApplication):
|
||||
print(version.GPL_BOILERPLATE.strip())
|
||||
sys.exit(0)
|
||||
|
||||
sent = ipc.send_to_running_instance(self._args.command)
|
||||
if sent:
|
||||
sys.exit(0)
|
||||
|
||||
log.init.debug("Starting IPC server...")
|
||||
try:
|
||||
sent = ipc.send_to_running_instance(self._args.command)
|
||||
if sent:
|
||||
sys.exit(0)
|
||||
log.init.debug("Starting IPC server...")
|
||||
ipc.init()
|
||||
except ipc.IPCError as e:
|
||||
text = ('{}\n\nMaybe another instance is running but '
|
||||
@@ -131,7 +130,7 @@ class Application(QApplication):
|
||||
utils.actute_warning()
|
||||
try:
|
||||
self._init_modules()
|
||||
except OSError as e:
|
||||
except (OSError, UnicodeDecodeError) as e:
|
||||
msgbox = QMessageBox(
|
||||
QMessageBox.Critical, "Error while initializing!",
|
||||
"Error while initializing: {}".format(e))
|
||||
@@ -224,7 +223,7 @@ class Application(QApplication):
|
||||
if data:
|
||||
# Crashlog exists and has data in it, so something crashed
|
||||
# previously.
|
||||
self._crashdlg = crashdialog.FatalCrashDialog(
|
||||
self._crashdlg = crashdialog.get_fatal_crash_dialog(
|
||||
self._args.debug, data)
|
||||
self._crashdlg.show()
|
||||
else:
|
||||
@@ -324,7 +323,7 @@ class Application(QApplication):
|
||||
window=win_id)
|
||||
log.init.debug("Startup URL {}".format(cmd))
|
||||
try:
|
||||
url = urlutils.fuzzy_url(cmd, cwd)
|
||||
url = urlutils.fuzzy_url(cmd, cwd, relative=True)
|
||||
except urlutils.FuzzyUrlError as e:
|
||||
message.error(0, "Error in startup argument '{}': "
|
||||
"{}".format(cmd, e))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -112,7 +112,7 @@ class HostBlocker:
|
||||
"Run :adblock-update to get adblock lists.")
|
||||
|
||||
@cmdutils.register(instance='host-blocker')
|
||||
def adblock_update(self):
|
||||
def adblock_update(self, win_id: {'special': 'win_id'}):
|
||||
"""Update the adblock block lists."""
|
||||
self.blocked_hosts = set()
|
||||
self._done_count = 0
|
||||
@@ -125,8 +125,10 @@ class HostBlocker:
|
||||
if url.scheme() == 'file':
|
||||
try:
|
||||
fileobj = open(url.path(), 'rb')
|
||||
except OSError:
|
||||
log.misc.exception("Failed to open block list!")
|
||||
except OSError as e:
|
||||
message.error(win_id, "adblock: Error while reading {}: "
|
||||
"{}".format(url.path(), e.strerror))
|
||||
continue
|
||||
download = FakeDownload(fileobj)
|
||||
self._in_progress.append(download)
|
||||
self.on_download_finished(download)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
import os.path
|
||||
import shutil
|
||||
import functools
|
||||
@@ -164,13 +165,13 @@ class DownloadItem(QObject):
|
||||
done.
|
||||
fileobj: The file object to download the file to.
|
||||
reply: The QNetworkReply associated with this download.
|
||||
retry_info: A RetryInfo instance.
|
||||
_filename: The filename of the download.
|
||||
_redirects: How many time we were redirected already.
|
||||
_buffer: A BytesIO object to buffer incoming data until we know the
|
||||
target file.
|
||||
_read_timer: A QTimer which reads the QNetworkReply into self._buffer
|
||||
periodically.
|
||||
_retry_info: A RetryInfo instance.
|
||||
_win_id: The window ID the DownloadItem runs in.
|
||||
|
||||
Signals:
|
||||
@@ -201,7 +202,7 @@ class DownloadItem(QObject):
|
||||
reply: The QNetworkReply to download.
|
||||
"""
|
||||
super().__init__(parent)
|
||||
self._retry_info = None
|
||||
self.retry_info = None
|
||||
self.done = False
|
||||
self.stats = DownloadItemStats(self)
|
||||
self.stats.updated.connect(self.data_changed)
|
||||
@@ -275,6 +276,8 @@ class DownloadItem(QObject):
|
||||
q.answered_yes.connect(self._create_fileobj)
|
||||
q.answered_no.connect(functools.partial(self.cancel, False))
|
||||
q.cancelled.connect(functools.partial(self.cancel, False))
|
||||
self.cancelled.connect(q.abort)
|
||||
self.error.connect(q.abort)
|
||||
message_bridge = objreg.get('message-bridge', scope='window',
|
||||
window=self._win_id)
|
||||
message_bridge.ask(q, blocking=False)
|
||||
@@ -310,8 +313,8 @@ class DownloadItem(QObject):
|
||||
reply.finished.connect(self.on_reply_finished)
|
||||
reply.error.connect(self.on_reply_error)
|
||||
reply.readyRead.connect(self.on_ready_read)
|
||||
self._retry_info = RetryInfo(request=reply.request(),
|
||||
manager=reply.manager())
|
||||
self.retry_info = RetryInfo(request=reply.request(),
|
||||
manager=reply.manager())
|
||||
if not self.fileobj:
|
||||
self._read_timer.start()
|
||||
# We could have got signals before we connected slots to them.
|
||||
@@ -364,7 +367,7 @@ class DownloadItem(QObject):
|
||||
def retry(self):
|
||||
"""Retry a failed download."""
|
||||
self.cancel()
|
||||
new_reply = self._retry_info.manager.get(self._retry_info.request)
|
||||
new_reply = self.retry_info.manager.get(self.retry_info.request)
|
||||
self.do_retry.emit(new_reply)
|
||||
|
||||
def open_file(self):
|
||||
@@ -385,6 +388,10 @@ class DownloadItem(QObject):
|
||||
"existing: {}, fileobj {}".format(
|
||||
filename, self._filename, self.fileobj))
|
||||
filename = os.path.expanduser(filename)
|
||||
# Remove chars which can't be encoded in the filename encoding.
|
||||
# See https://github.com/The-Compiler/qutebrowser/issues/427
|
||||
encoding = sys.getfilesystemencoding()
|
||||
filename = utils.force_encoding(filename, encoding)
|
||||
if os.path.isabs(filename) and os.path.isdir(filename):
|
||||
# We got an absolute directory from the user, so we save it under
|
||||
# the default filename in that directory.
|
||||
@@ -557,7 +564,8 @@ class DownloadManager(QAbstractListModel):
|
||||
self._win_id = win_id
|
||||
self.downloads = []
|
||||
self.questions = []
|
||||
self._networkmanager = networkmanager.NetworkManager(win_id, self)
|
||||
self._networkmanager = networkmanager.NetworkManager(
|
||||
win_id, None, self)
|
||||
|
||||
def __repr__(self):
|
||||
return utils.get_repr(self, downloads=len(self.downloads))
|
||||
@@ -639,7 +647,10 @@ class DownloadManager(QAbstractListModel):
|
||||
return self.fetch_request(request, filename, fileobj, page,
|
||||
auto_remove)
|
||||
q = self._prepare_question()
|
||||
q.default = urlutils.filename_from_url(request.url())
|
||||
filename = urlutils.filename_from_url(request.url())
|
||||
encoding = sys.getfilesystemencoding()
|
||||
filename = utils.force_encoding(filename, encoding)
|
||||
q.default = filename
|
||||
message_bridge = objreg.get('message-bridge', scope='window',
|
||||
window=self._win_id)
|
||||
q.answered.connect(
|
||||
@@ -719,6 +730,9 @@ class DownloadManager(QAbstractListModel):
|
||||
download.autoclose = False
|
||||
else:
|
||||
q = self._prepare_question()
|
||||
encoding = sys.getfilesystemencoding()
|
||||
suggested_filename = utils.force_encoding(suggested_filename,
|
||||
encoding)
|
||||
q.default = suggested_filename
|
||||
q.answered.connect(download.set_filename)
|
||||
q.cancelled.connect(download.cancel)
|
||||
@@ -785,10 +799,19 @@ class DownloadManager(QAbstractListModel):
|
||||
Return:
|
||||
A boolean.
|
||||
"""
|
||||
assert nam.adopted_downloads == 0
|
||||
for download in self.downloads:
|
||||
if download.reply is not None and download.reply.manager() is nam:
|
||||
return True
|
||||
return False
|
||||
running_download = (download.reply is not None and
|
||||
download.reply.manager() is nam)
|
||||
# user could request retry after tab is closed.
|
||||
failed_download = (download.done and (not download.successful) and
|
||||
download.retry_info.manager is nam)
|
||||
if running_download or failed_download:
|
||||
log.downloads.debug("Found running/failed downloads, "
|
||||
"adopting the NAM.")
|
||||
nam.adopted_downloads += 1
|
||||
download.destroyed.connect(nam.on_adopted_download_destroyed)
|
||||
return nam.adopted_downloads
|
||||
|
||||
def can_clear(self):
|
||||
"""Check if there are finished downloads to clear."""
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -267,6 +267,14 @@ class HintManager(QObject):
|
||||
display = elem.styleProperty('display', QWebElement.InlineStyle)
|
||||
return display == 'none'
|
||||
|
||||
def _show_elem(self, elem):
|
||||
"""Show a given element."""
|
||||
elem.setStyleProperty('display', 'inline !important')
|
||||
|
||||
def _hide_elem(self, elem):
|
||||
"""Hide a given element."""
|
||||
elem.setStyleProperty('display', 'none !important')
|
||||
|
||||
def _set_style_properties(self, elem, label):
|
||||
"""Set the hint CSS on the element given.
|
||||
|
||||
@@ -275,23 +283,23 @@ class HintManager(QObject):
|
||||
label: The label QWebElement.
|
||||
"""
|
||||
attrs = [
|
||||
('display', 'inline'),
|
||||
('z-index', '100000'),
|
||||
('pointer-events', 'none'),
|
||||
('position', 'absolute'),
|
||||
('color', config.get('colors', 'hints.fg')),
|
||||
('background', config.get('colors', 'hints.bg')),
|
||||
('font', config.get('fonts', 'hints')),
|
||||
('border', config.get('hints', 'border')),
|
||||
('opacity', str(config.get('hints', 'opacity'))),
|
||||
('display', 'inline !important'),
|
||||
('z-index', '{} !important'.format(int(2 ** 32 / 2 - 1))),
|
||||
('pointer-events', 'none !important'),
|
||||
('position', 'absolute !important'),
|
||||
('color', config.get('colors', 'hints.fg') + ' !important'),
|
||||
('background', config.get('colors', 'hints.bg') + ' !important'),
|
||||
('font', config.get('fonts', 'hints') + ' !important'),
|
||||
('border', config.get('hints', 'border') + ' !important'),
|
||||
('opacity', str(config.get('hints', 'opacity')) + ' !important'),
|
||||
]
|
||||
|
||||
# Make text uppercase if set in config
|
||||
if (config.get('hints', 'uppercase') and
|
||||
config.get('hints', 'mode') == 'letter'):
|
||||
attrs.append(('texttransform', 'uppercase'))
|
||||
attrs.append(('text-transform', 'uppercase !important'))
|
||||
else:
|
||||
attrs.append(('texttransform', 'none'))
|
||||
attrs.append(('text-transform', 'none !important'))
|
||||
|
||||
for k, v in attrs:
|
||||
label.setStyleProperty(k, v)
|
||||
@@ -313,8 +321,8 @@ class HintManager(QObject):
|
||||
top /= zoom
|
||||
log.hints.vdebug("Drawing label '{!r}' at {}/{} for element '{!r}', "
|
||||
"zoom level {}".format(label, left, top, elem, zoom))
|
||||
label.setStyleProperty('left', '{}px'.format(left))
|
||||
label.setStyleProperty('top', '{}px'.format(top))
|
||||
label.setStyleProperty('left', '{}px !important'.format(left))
|
||||
label.setStyleProperty('top', '{}px !important'.format(top))
|
||||
|
||||
def _draw_label(self, elem, string):
|
||||
"""Draw a hint label over an element.
|
||||
@@ -706,10 +714,10 @@ class HintManager(QObject):
|
||||
match_color, matched, rest))
|
||||
if self._is_hidden(elems.label):
|
||||
# hidden element which matches again -> unhide it
|
||||
elems.label.setStyleProperty('display', 'inline')
|
||||
self._show_elem(elems.label)
|
||||
else:
|
||||
# element doesn't match anymore -> hide it
|
||||
elems.label.setStyleProperty('display', 'none')
|
||||
self._hide_elem(elems.label)
|
||||
except webelem.IsNullError:
|
||||
pass
|
||||
|
||||
@@ -725,16 +733,19 @@ class HintManager(QObject):
|
||||
str(elems.elem).lower().startswith(filterstr)):
|
||||
if self._is_hidden(elems.label):
|
||||
# hidden element which matches again -> unhide it
|
||||
elems.label.setStyleProperty('display', 'inline')
|
||||
self._show_elem(elems.label)
|
||||
else:
|
||||
# element doesn't match anymore -> hide it
|
||||
elems.label.setStyleProperty('display', 'none')
|
||||
self._hide_elem(elems.label)
|
||||
except webelem.IsNullError:
|
||||
pass
|
||||
visible = {}
|
||||
for k, e in self._context.elems.items():
|
||||
if not self._is_hidden(e.label):
|
||||
visible[k] = e
|
||||
try:
|
||||
if not self._is_hidden(e.label):
|
||||
visible[k] = e
|
||||
except webelem.IsNullError:
|
||||
pass
|
||||
if not visible:
|
||||
# Whoops, filtered all hints
|
||||
modeman.leave(self._win_id, usertypes.KeyMode.hint, 'all filtered')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -43,10 +43,16 @@ class NetworkManager(QNetworkAccessManager):
|
||||
"""Our own QNetworkAccessManager.
|
||||
|
||||
Attributes:
|
||||
adopted_downloads: If downloads are running with this QNAM but the
|
||||
associated tab gets closed already, the NAM gets
|
||||
reparented to the DownloadManager. This counts the
|
||||
still running downloads, so the QNAM can clean
|
||||
itself up when this reaches zero again.
|
||||
_requests: Pending requests.
|
||||
_scheme_handlers: A dictionary (scheme -> handler) of supported custom
|
||||
schemes.
|
||||
_win_id: The window ID this NetworkManager is associated with.
|
||||
_tab_id: The tab ID this NetworkManager is associated with.
|
||||
|
||||
Signals:
|
||||
shutting_down: Emitted when the QNAM is shutting down.
|
||||
@@ -54,14 +60,16 @@ class NetworkManager(QNetworkAccessManager):
|
||||
|
||||
shutting_down = pyqtSignal()
|
||||
|
||||
def __init__(self, win_id, parent=None):
|
||||
def __init__(self, win_id, tab_id, parent=None):
|
||||
log.init.debug("Initializing NetworkManager")
|
||||
with log.disable_qt_msghandler():
|
||||
# WORKAROUND for a hang when a message is printed - See:
|
||||
# http://www.riverbankcomputing.com/pipermail/pyqt/2014-November/035045.html
|
||||
super().__init__(parent)
|
||||
log.init.debug("NetworkManager init done")
|
||||
self.adopted_downloads = 0
|
||||
self._win_id = win_id
|
||||
self._tab_id = tab_id
|
||||
self._requests = []
|
||||
self._scheme_handlers = {
|
||||
'qute': qutescheme.QuteSchemeHandler(win_id),
|
||||
@@ -124,6 +132,9 @@ class NetworkManager(QNetworkAccessManager):
|
||||
self.shutting_down.connect(q.abort)
|
||||
if owner is not None:
|
||||
owner.destroyed.connect(q.abort)
|
||||
webview = objreg.get('webview', scope='tab', window=self._win_id,
|
||||
tab=self._tab_id)
|
||||
webview.loadStarted.connect(q.abort)
|
||||
bridge = objreg.get('message-bridge', scope='window', window=win_id)
|
||||
bridge.ask(q, blocking=True)
|
||||
q.deleteLater()
|
||||
@@ -203,6 +214,19 @@ class NetworkManager(QNetworkAccessManager):
|
||||
# switched from private mode to normal mode
|
||||
self._set_cookiejar()
|
||||
|
||||
@pyqtSlot()
|
||||
def on_adopted_download_destroyed(self):
|
||||
"""Check if we can clean up if an adopted download was destroyed.
|
||||
|
||||
See the description for adopted_downloads for details.
|
||||
"""
|
||||
self.adopted_downloads -= 1
|
||||
log.downloads.debug("Adopted download destroyed, {} left.".format(
|
||||
self.adopted_downloads))
|
||||
assert self.adopted_downloads >= 0
|
||||
if self.adopted_downloads == 0:
|
||||
self.deleteLater()
|
||||
|
||||
# WORKAROUND for:
|
||||
# http://www.riverbankcomputing.com/pipermail/pyqt/2014-September/034806.html
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# Based on the Eric5 helpviewer,
|
||||
# Copyright (c) 2009 - 2014 Detlev Offenbach <detlev@die-offenbachs.de>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# Based on the Eric5 helpviewer,
|
||||
# Copyright (c) 2009 - 2014 Detlev Offenbach <detlev@die-offenbachs.de>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -41,7 +41,8 @@ class SignalFilter(QObject):
|
||||
BLACKLIST: List of signal names which should not be logged.
|
||||
"""
|
||||
|
||||
BLACKLIST = ['cur_scroll_perc_changed', 'cur_progress']
|
||||
BLACKLIST = ['cur_scroll_perc_changed', 'cur_progress',
|
||||
'cur_statusbar_message']
|
||||
|
||||
def __init__(self, win_id, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
import functools
|
||||
|
||||
from PyQt5.QtCore import pyqtSlot, PYQT_VERSION, Qt, QUrl
|
||||
from PyQt5.QtCore import pyqtSlot, pyqtSignal, PYQT_VERSION, Qt, QUrl
|
||||
from PyQt5.QtGui import QDesktopServices
|
||||
from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest
|
||||
from PyQt5.QtWidgets import QFileDialog
|
||||
@@ -45,18 +45,26 @@ class BrowserPage(QWebPage):
|
||||
_networkmnager: The NetworkManager used.
|
||||
_win_id: The window ID this BrowserPage is associated with.
|
||||
_ignore_load_started: Whether to ignore the next loadStarted signal.
|
||||
_is_shutting_down: Whether the page is currently shutting down.
|
||||
|
||||
Signals:
|
||||
shutting_down: Emitted when the page is currently shutting down.
|
||||
"""
|
||||
|
||||
def __init__(self, win_id, parent=None):
|
||||
shutting_down = pyqtSignal()
|
||||
|
||||
def __init__(self, win_id, tab_id, parent=None):
|
||||
super().__init__(parent)
|
||||
self._win_id = win_id
|
||||
self._is_shutting_down = False
|
||||
self._extension_handlers = {
|
||||
QWebPage.ErrorPageExtension: self._handle_errorpage,
|
||||
QWebPage.ChooseMultipleFilesExtension: self._handle_multiple_files,
|
||||
}
|
||||
self._ignore_load_started = False
|
||||
self.error_occured = False
|
||||
self._networkmanager = networkmanager.NetworkManager(win_id, self)
|
||||
self._networkmanager = networkmanager.NetworkManager(
|
||||
win_id, tab_id, self)
|
||||
self.setNetworkAccessManager(self._networkmanager)
|
||||
self.setForwardUnsupportedContent(True)
|
||||
self.printRequested.connect(self.on_print_requested)
|
||||
@@ -72,8 +80,10 @@ class BrowserPage(QWebPage):
|
||||
|
||||
def javaScriptPrompt(self, _frame, msg, default):
|
||||
"""Override javaScriptPrompt to use the statusbar."""
|
||||
answer = message.ask(self._win_id, "js: {}".format(msg),
|
||||
usertypes.PromptMode.text, default)
|
||||
if self._is_shutting_down:
|
||||
return (False, "")
|
||||
answer = self._ask("js: {}".format(msg), usertypes.PromptMode.text,
|
||||
default)
|
||||
if answer is None:
|
||||
return (False, "")
|
||||
else:
|
||||
@@ -120,8 +130,17 @@ class BrowserPage(QWebPage):
|
||||
else:
|
||||
error_str = info.errorString
|
||||
if error_str == networkmanager.HOSTBLOCK_ERROR_STRING:
|
||||
# We don't set error_occured in this case.
|
||||
error_str = "Request blocked by host blocker."
|
||||
# we don't set error_occured in this case.
|
||||
main_frame = info.frame.page().mainFrame()
|
||||
if info.frame != main_frame:
|
||||
# Content in an iframe -> Hide the frame so it doesn't use
|
||||
# any space. We can't hide the frame's documentElement
|
||||
# directly though.
|
||||
for elem in main_frame.documentElement().findAll('iframe'):
|
||||
if QUrl(elem.attribute('src')) == info.url:
|
||||
elem.setAttribute('style', 'display: none')
|
||||
return False
|
||||
else:
|
||||
self._ignore_load_started = True
|
||||
self.error_occured = True
|
||||
@@ -157,6 +176,41 @@ class BrowserPage(QWebPage):
|
||||
suggested_file)
|
||||
return True
|
||||
|
||||
def _ask(self, text, mode, default=None):
|
||||
"""Ask a blocking question in the statusbar.
|
||||
|
||||
Args:
|
||||
text: The text to display to the user.
|
||||
mode: A PromptMode.
|
||||
default: The default value to display.
|
||||
|
||||
Return:
|
||||
The answer the user gave or None if the prompt was cancelled.
|
||||
"""
|
||||
q = usertypes.Question()
|
||||
q.text = text
|
||||
q.mode = mode
|
||||
q.default = default
|
||||
self.loadStarted.connect(q.abort)
|
||||
self.shutting_down.connect(q.abort)
|
||||
bridge = objreg.get('message-bridge', scope='window',
|
||||
window=self._win_id)
|
||||
bridge.ask(q, blocking=True)
|
||||
q.deleteLater()
|
||||
return q.answer
|
||||
|
||||
def shutdown(self):
|
||||
"""Prepare the web page for being deleted."""
|
||||
self._is_shutting_down = True
|
||||
self.shutting_down.emit()
|
||||
download_manager = objreg.get('download-manager', scope='window',
|
||||
window=self._win_id)
|
||||
nam = self.networkAccessManager()
|
||||
if download_manager.has_downloads_with_nam(nam):
|
||||
nam.setParent(download_manager)
|
||||
else:
|
||||
nam.shutdown()
|
||||
|
||||
def display_content(self, reply, mimetype):
|
||||
"""Display a QNetworkReply with an explicitely set mimetype."""
|
||||
self.mainFrame().setContent(reply.readAll(), mimetype, reply.url())
|
||||
@@ -268,18 +322,22 @@ class BrowserPage(QWebPage):
|
||||
|
||||
def javaScriptAlert(self, _frame, msg):
|
||||
"""Override javaScriptAlert to use the statusbar."""
|
||||
message.ask(self._win_id, "[js alert] {}".format(msg),
|
||||
usertypes.PromptMode.alert)
|
||||
if self._is_shutting_down:
|
||||
return
|
||||
self._ask("[js alert] {}".format(msg), usertypes.PromptMode.alert)
|
||||
|
||||
def javaScriptConfirm(self, _frame, msg):
|
||||
"""Override javaScriptConfirm to use the statusbar."""
|
||||
ans = message.ask(self._win_id, "[js confirm] {}".format(msg),
|
||||
usertypes.PromptMode.yesno)
|
||||
if self._is_shutting_down:
|
||||
return False
|
||||
ans = self._ask("[js confirm] {}".format(msg),
|
||||
usertypes.PromptMode.yesno)
|
||||
return bool(ans)
|
||||
|
||||
def javaScriptConsoleMessage(self, msg, line, source):
|
||||
"""Override javaScriptConsoleMessage to use debug log."""
|
||||
log.js.debug("[{}:{}] {}".format(source, line, msg))
|
||||
if config.get('general', 'log-javascript-console'):
|
||||
log.js.debug("[{}:{}] {}".format(source, line, msg))
|
||||
|
||||
def chooseFile(self, _frame, suggested_file):
|
||||
"""Override QWebPage's chooseFile to be able to chose a file to upload.
|
||||
@@ -293,8 +351,8 @@ class BrowserPage(QWebPage):
|
||||
|
||||
def shouldInterruptJavaScript(self):
|
||||
"""Override shouldInterruptJavaScript to use the statusbar."""
|
||||
answer = message.ask(self._win_id, "Interrupt long-running "
|
||||
"javascript?", usertypes.PromptMode.yesno)
|
||||
answer = self._ask("Interrupt long-running javascript?",
|
||||
usertypes.PromptMode.yesno)
|
||||
if answer is None:
|
||||
answer = True
|
||||
return answer
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -19,11 +19,12 @@
|
||||
|
||||
"""The main browser widgets."""
|
||||
|
||||
import sys
|
||||
import itertools
|
||||
import functools
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QTimer, QUrl
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
from PyQt5.QtWidgets import QApplication, QStyleFactory
|
||||
from PyQt5.QtWebKit import QWebSettings
|
||||
from PyQt5.QtWebKitWidgets import QWebView, QWebPage
|
||||
|
||||
@@ -76,15 +77,21 @@ class WebView(QWebView):
|
||||
linkHovered: QWebPages linkHovered signal exposed.
|
||||
load_status_changed: The loading status changed
|
||||
url_text_changed: Current URL string changed.
|
||||
shutting_down: Emitted when the view is shutting down.
|
||||
"""
|
||||
|
||||
scroll_pos_changed = pyqtSignal(int, int)
|
||||
linkHovered = pyqtSignal(str, str, str)
|
||||
load_status_changed = pyqtSignal(str)
|
||||
url_text_changed = pyqtSignal(str)
|
||||
shutting_down = pyqtSignal()
|
||||
|
||||
def __init__(self, win_id, parent=None):
|
||||
super().__init__(parent)
|
||||
if sys.platform == 'darwin' and qtutils.version_check('5.4'):
|
||||
# WORKAROUND for https://bugreports.qt.io/browse/QTBUG-42948
|
||||
# See https://github.com/The-Compiler/qutebrowser/issues/462
|
||||
self.setStyle(QStyleFactory.create('Fusion'))
|
||||
self._win_id = win_id
|
||||
self.load_status = LoadStatus.none
|
||||
self._check_insertmode = False
|
||||
@@ -113,7 +120,7 @@ class WebView(QWebView):
|
||||
window=win_id)
|
||||
tab_registry[self.tab_id] = self
|
||||
objreg.register('webview', self, registry=self.registry)
|
||||
page = webpage.BrowserPage(win_id, self)
|
||||
page = webpage.BrowserPage(win_id, self.tab_id, self)
|
||||
self.setPage(page)
|
||||
hintmanager = hints.HintManager(win_id, self.tab_id, self)
|
||||
hintmanager.mouse_event.connect(self.on_mouse_event)
|
||||
@@ -295,19 +302,14 @@ class WebView(QWebView):
|
||||
|
||||
def shutdown(self):
|
||||
"""Shut down the webview."""
|
||||
self.shutting_down.emit()
|
||||
self.page().shutdown()
|
||||
# We disable javascript because that prevents some segfaults when
|
||||
# quitting it seems.
|
||||
log.destroy.debug("Shutting down {!r}.".format(self))
|
||||
settings = self.settings()
|
||||
settings.setAttribute(QWebSettings.JavascriptEnabled, False)
|
||||
self.stop()
|
||||
download_manager = objreg.get('download-manager', scope='window',
|
||||
window=self._win_id)
|
||||
nam = self.page().networkAccessManager()
|
||||
if download_manager.has_downloads_with_nam(nam):
|
||||
nam.setParent(download_manager)
|
||||
else:
|
||||
nam.shutdown()
|
||||
|
||||
def openurl(self, url):
|
||||
"""Open a URL in the browser.
|
||||
@@ -526,3 +528,9 @@ class WebView(QWebView):
|
||||
# We want to make sure we check the focus element after the WebView is
|
||||
# updated completely.
|
||||
QTimer.singleShot(0, self.mouserelease_insertmode)
|
||||
|
||||
def contextMenuEvent(self, e):
|
||||
"""Save a reference to the context menu so we can close it."""
|
||||
menu = self.page().createStandardContextMenu()
|
||||
self.shutting_down.connect(menu.close)
|
||||
menu.exec_(e.globalPos())
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -271,8 +271,11 @@ class CommandRunner(QObject):
|
||||
maxsplit=maxsplit)
|
||||
for s in args:
|
||||
# remove quotes and replace \" by "
|
||||
s = re.sub(r"""(^|[^\\])["']""", r'\1', s)
|
||||
s = re.sub(r"""\\(["'])""", r'\1', s)
|
||||
if s == '""' or s == "''":
|
||||
s = ''
|
||||
else:
|
||||
s = re.sub(r"""(^|[^\\])["']""", r'\1', s)
|
||||
s = re.sub(r"""\\(["'])""", r'\1', s)
|
||||
self._args.append(s)
|
||||
break
|
||||
else:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -123,7 +123,7 @@ def init(args):
|
||||
try:
|
||||
app = objreg.get('app')
|
||||
config_obj = ConfigManager(confdir, 'qutebrowser.conf', app)
|
||||
except (configexc.Error, configparser.Error) as e:
|
||||
except (configexc.Error, configparser.Error, UnicodeDecodeError) as e:
|
||||
log.init.exception(e)
|
||||
errstr = "Error while reading config:"
|
||||
try:
|
||||
@@ -141,7 +141,7 @@ def init(args):
|
||||
objreg.register('config', config_obj)
|
||||
try:
|
||||
key_config = keyconf.KeyConfigParser(confdir, 'keys.conf')
|
||||
except keyconf.KeyConfigError as e:
|
||||
except (keyconf.KeyConfigError, UnicodeDecodeError) as e:
|
||||
log.init.exception(e)
|
||||
errstr = "Error while reading key config:\n"
|
||||
if e.lineno is not None:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -190,6 +190,10 @@ DATA = collections.OrderedDict([
|
||||
SettingValue(typ.NewInstanceOpenTarget(), 'window'),
|
||||
"How to open links in an existing instance if a new one is "
|
||||
"launched."),
|
||||
|
||||
('log-javascript-console',
|
||||
SettingValue(typ.Bool(), 'false'),
|
||||
"Whether to log javascript console messages."),
|
||||
)),
|
||||
|
||||
('ui', sect.KeyValue(
|
||||
@@ -517,8 +521,7 @@ DATA = collections.OrderedDict([
|
||||
'http://winhelp2002.mvps.org/hosts.zip,'
|
||||
'http://malwaredomains.lehigh.edu/files/justdomains.zip,'
|
||||
'http://pgl.yoyo.org/adservers/serverlist.php?'
|
||||
'hostformat=hosts&mimetype=plaintext,'
|
||||
'http://hosts-file.net/ad_servers.asp'),
|
||||
'hostformat=hosts&mimetype=plaintext'),
|
||||
"List of URLs of lists which contain hosts to block.\n\n"
|
||||
"The file can be in one of the following formats:\n\n"
|
||||
"- An '/etc/hosts'-like file\n"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -937,13 +937,13 @@ class ShellCommand(BaseType):
|
||||
return
|
||||
else:
|
||||
raise configexc.ValidationError(value, "may not be empty!")
|
||||
if self.placeholder and '{}' not in self.transform(value):
|
||||
raise configexc.ValidationError(value, "needs to contain a "
|
||||
"{}-placeholder.")
|
||||
try:
|
||||
shlex.split(value)
|
||||
except ValueError as e:
|
||||
raise configexc.ValidationError(value, str(e))
|
||||
if self.placeholder and '{}' not in self.transform(value):
|
||||
raise configexc.ValidationError(value, "needs to contain a "
|
||||
"{}-placeholder.")
|
||||
|
||||
def transform(self, value):
|
||||
if not value:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -29,13 +29,12 @@ Module attributes:
|
||||
import os.path
|
||||
|
||||
from PyQt5.QtWebKit import QWebSettings
|
||||
from PyQt5.QtCore import QStandardPaths
|
||||
from PyQt5.QtCore import QStandardPaths, QUrl
|
||||
|
||||
from qutebrowser.config import config
|
||||
from qutebrowser.utils import usertypes, standarddir, objreg
|
||||
|
||||
MapType = usertypes.enum('MapType', ['attribute', 'setter', 'setter_none',
|
||||
'static_setter'])
|
||||
MapType = usertypes.enum('MapType', ['attribute', 'setter', 'static_setter'])
|
||||
|
||||
|
||||
MAPPINGS = {
|
||||
@@ -71,35 +70,41 @@ MAPPINGS = {
|
||||
},
|
||||
'fonts': {
|
||||
'web-family-standard':
|
||||
(MapType.setter_none, lambda qws, v:
|
||||
qws.setFontFamily(QWebSettings.StandardFont, v)),
|
||||
(MapType.setter, lambda qws, v:
|
||||
qws.setFontFamily(QWebSettings.StandardFont, v),
|
||||
""),
|
||||
'web-family-fixed':
|
||||
(MapType.setter_none, lambda qws, v:
|
||||
qws.setFontFamily(QWebSettings.FixedFont, v)),
|
||||
(MapType.setter, lambda qws, v:
|
||||
qws.setFontFamily(QWebSettings.FixedFont, v),
|
||||
""),
|
||||
'web-family-serif':
|
||||
(MapType.setter_none, lambda qws, v:
|
||||
qws.setFontFamily(QWebSettings.SerifFont, v)),
|
||||
(MapType.setter, lambda qws, v:
|
||||
qws.setFontFamily(QWebSettings.SerifFont, v),
|
||||
""),
|
||||
'web-family-sans-serif':
|
||||
(MapType.setter_none, lambda qws, v:
|
||||
qws.setFontFamily(QWebSettings.SansSerifFont, v)),
|
||||
(MapType.setter, lambda qws, v:
|
||||
qws.setFontFamily(QWebSettings.SansSerifFont, v),
|
||||
""),
|
||||
'web-family-cursive':
|
||||
(MapType.setter_none, lambda qws, v:
|
||||
qws.setFontFamily(QWebSettings.CursiveFont, v)),
|
||||
(MapType.setter, lambda qws, v:
|
||||
qws.setFontFamily(QWebSettings.CursiveFont, v),
|
||||
""),
|
||||
'web-family-fantasy':
|
||||
(MapType.setter_none, lambda qws, v:
|
||||
qws.setFontFamily(QWebSettings.FantasyFont, v)),
|
||||
(MapType.setter, lambda qws, v:
|
||||
qws.setFontFamily(QWebSettings.FantasyFont, v),
|
||||
""),
|
||||
'web-size-minimum':
|
||||
(MapType.setter, lambda qws, v:
|
||||
qws.setFontSize(QWebSettings.MinimumFontSize, v)),
|
||||
qws.setFontSize(QWebSettings.MinimumFontSize, v)),
|
||||
'web-size-minimum-logical':
|
||||
(MapType.setter, lambda qws, v:
|
||||
qws.setFontSize(QWebSettings.MinimumLogicalFontSize, v)),
|
||||
qws.setFontSize(QWebSettings.MinimumLogicalFontSize, v)),
|
||||
'web-size-default':
|
||||
(MapType.setter, lambda qws, v:
|
||||
qws.setFontSize(QWebSettings.DefaultFontSize, v)),
|
||||
qws.setFontSize(QWebSettings.DefaultFontSize, v)),
|
||||
'web-size-default-fixed':
|
||||
(MapType.setter, lambda qws, v:
|
||||
qws.setFontSize(QWebSettings.DefaultFixedFontSize, v)),
|
||||
qws.setFontSize(QWebSettings.DefaultFixedFontSize, v)),
|
||||
},
|
||||
'ui': {
|
||||
'zoom-text-only':
|
||||
@@ -107,9 +112,12 @@ MAPPINGS = {
|
||||
'frame-flattening':
|
||||
(MapType.attribute, QWebSettings.FrameFlatteningEnabled),
|
||||
'user-stylesheet':
|
||||
(MapType.setter_none, lambda qws, v: qws.setUserStyleSheetUrl(v)),
|
||||
(MapType.setter, lambda qws, v:
|
||||
qws.setUserStyleSheetUrl(v),
|
||||
QUrl()),
|
||||
'css-media-type':
|
||||
(MapType.setter, lambda qws, v: qws.setCSSMediaType(v)),
|
||||
(MapType.setter, lambda qws, v:
|
||||
qws.setCSSMediaType(v)),
|
||||
#'accelerated-compositing':
|
||||
# (MapType.attribute, QWebSettings.AcceleratedCompositingEnabled),
|
||||
#'tiled-backing-store':
|
||||
@@ -125,16 +133,16 @@ MAPPINGS = {
|
||||
(MapType.attribute, QWebSettings.LocalStorageEnabled),
|
||||
'maximum-pages-in-cache':
|
||||
(MapType.static_setter, lambda v:
|
||||
QWebSettings.setMaximumPagesInCache(v)),
|
||||
QWebSettings.setMaximumPagesInCache(v)),
|
||||
'object-cache-capacities':
|
||||
(MapType.static_setter, lambda v:
|
||||
QWebSettings.setObjectCacheCapacities(*v)),
|
||||
QWebSettings.setObjectCacheCapacities(*v)),
|
||||
'offline-storage-default-quota':
|
||||
(MapType.static_setter, lambda v:
|
||||
QWebSettings.setOfflineStorageDefaultQuota(v)),
|
||||
QWebSettings.setOfflineStorageDefaultQuota(v)),
|
||||
'offline-web-application-cache-quota':
|
||||
(MapType.static_setter, lambda v:
|
||||
QWebSettings.setOfflineWebApplicationCacheQuota(v)),
|
||||
QWebSettings.setOfflineWebApplicationCacheQuota(v)),
|
||||
},
|
||||
'general': {
|
||||
'private-browsing':
|
||||
@@ -148,34 +156,39 @@ MAPPINGS = {
|
||||
'site-specific-quirks':
|
||||
(MapType.attribute, QWebSettings.SiteSpecificQuirksEnabled),
|
||||
'default-encoding':
|
||||
(MapType.setter_none, lambda qws, v:
|
||||
qws.setDefaultTextEncoding(v)),
|
||||
(MapType.setter, lambda qws, v: qws.setDefaultTextEncoding(v), ""),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
settings = None
|
||||
UNSET = object()
|
||||
|
||||
|
||||
def _set_setting(typ, arg, value):
|
||||
def _set_setting(typ, arg, default=UNSET, value=UNSET):
|
||||
"""Set a QWebSettings setting.
|
||||
|
||||
Args:
|
||||
typ: The type of the item.
|
||||
arg: The argument (attribute/handler)
|
||||
default: The value to use if the user set an empty string.
|
||||
value: The value to set.
|
||||
"""
|
||||
if not isinstance(typ, MapType):
|
||||
raise TypeError("Type {} is no MapType member!".format(typ))
|
||||
if value is UNSET:
|
||||
raise TypeError("No value given!")
|
||||
if value is None:
|
||||
if default is UNSET:
|
||||
return
|
||||
else:
|
||||
value = default
|
||||
|
||||
if typ == MapType.attribute:
|
||||
settings.setAttribute(arg, value)
|
||||
elif typ == MapType.setter_none:
|
||||
if value is None:
|
||||
value = ""
|
||||
elif typ == MapType.setter:
|
||||
arg(settings, value)
|
||||
elif typ == MapType.setter and value is not None:
|
||||
arg(settings, value)
|
||||
elif typ == MapType.static_setter and value is not None:
|
||||
elif typ == MapType.static_setter:
|
||||
arg(value)
|
||||
|
||||
|
||||
@@ -194,17 +207,17 @@ def init():
|
||||
global settings
|
||||
settings = QWebSettings.globalSettings()
|
||||
for sectname, section in MAPPINGS.items():
|
||||
for optname, (typ, arg) in section.items():
|
||||
for optname, mapping in section.items():
|
||||
value = config.get(sectname, optname)
|
||||
_set_setting(typ, arg, value)
|
||||
_set_setting(*mapping, value=value)
|
||||
objreg.get('config').changed.connect(update_settings)
|
||||
|
||||
|
||||
def update_settings(section, option):
|
||||
"""Update global settings when qwebsettings changed."""
|
||||
try:
|
||||
typ, arg = MAPPINGS[section][option]
|
||||
mapping = MAPPINGS[section][option]
|
||||
except KeyError:
|
||||
return
|
||||
value = config.get(section, option)
|
||||
_set_setting(typ, arg, value)
|
||||
_set_setting(*mapping, value=value)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -154,7 +154,7 @@ class ModeManager(QObject):
|
||||
self._win_id = win_id
|
||||
self._handlers = {}
|
||||
self.passthrough = []
|
||||
self.mode = usertypes.KeyMode.none
|
||||
self.mode = usertypes.KeyMode.normal
|
||||
self._releaseevents_to_pass = []
|
||||
self._forward_unbound_keys = config.get(
|
||||
'input', 'forward-unbound-keys')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -22,7 +22,6 @@
|
||||
import binascii
|
||||
import base64
|
||||
import itertools
|
||||
import functools
|
||||
|
||||
from PyQt5.QtCore import pyqtSlot, QRect, QPoint, QTimer, Qt
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout
|
||||
@@ -96,7 +95,10 @@ class MainWindow(QWidget):
|
||||
window=win_id)
|
||||
self._vbox.addWidget(self._tabbed_browser)
|
||||
|
||||
self.status = bar.StatusBar(win_id)
|
||||
# We need to set an explicit parent for StatusBar because it does some
|
||||
# show/hide magic immediately which would mean it'd show up as a
|
||||
# window.
|
||||
self.status = bar.StatusBar(win_id, parent=self)
|
||||
self._vbox.addWidget(self.status)
|
||||
|
||||
self._completion = completionwidget.CompletionView(win_id, self)
|
||||
@@ -112,8 +114,6 @@ class MainWindow(QWidget):
|
||||
modeman.init(self.win_id, self)
|
||||
|
||||
self._connect_signals()
|
||||
QTimer.singleShot(0, functools.partial(
|
||||
modeman.enter, win_id, usertypes.KeyMode.normal, 'init'))
|
||||
|
||||
# When we're here the statusbar might not even really exist yet, so
|
||||
# resizing will fail. Therefore, we use singleShot QTimers to make sure
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -252,7 +252,7 @@ class StatusBar(QWidget):
|
||||
if self._previous_widget == PreviousWidget.prompt:
|
||||
self._stack.setCurrentWidget(self.prompt)
|
||||
elif self._previous_widget == PreviousWidget.command:
|
||||
self._stack.setCurrentWidget(self.command)
|
||||
self._stack.setCurrentWidget(self.cmd)
|
||||
elif self._previous_widget == PreviousWidget.none:
|
||||
pass
|
||||
else:
|
||||
@@ -267,7 +267,7 @@ class StatusBar(QWidget):
|
||||
def _show_cmd_widget(self):
|
||||
"""Show command widget instead of temporary text."""
|
||||
self._set_error(False)
|
||||
self._previous_widget = PreviousWidget.prompt
|
||||
self._previous_widget = PreviousWidget.command
|
||||
if self._text_pop_timer.isActive():
|
||||
self._timer_was_active = True
|
||||
self._text_pop_timer.stop()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -21,43 +21,93 @@
|
||||
|
||||
"""The dialog which gets shown when qutebrowser crashes."""
|
||||
|
||||
import re
|
||||
import sys
|
||||
import html
|
||||
import getpass
|
||||
import traceback
|
||||
import functools
|
||||
|
||||
from PyQt5.QtCore import pyqtSlot, Qt, QSize
|
||||
from PyQt5.QtCore import pyqtSlot, Qt, QSize, qVersion
|
||||
from PyQt5.QtWidgets import (QDialog, QLabel, QTextEdit, QPushButton,
|
||||
QVBoxLayout, QHBoxLayout, QCheckBox)
|
||||
QVBoxLayout, QHBoxLayout, QCheckBox,
|
||||
QDialogButtonBox, QMessageBox)
|
||||
|
||||
from qutebrowser.utils import version, log, utils, objreg
|
||||
import qutebrowser
|
||||
from qutebrowser.utils import version, log, utils, objreg, qtutils
|
||||
from qutebrowser.misc import miscwidgets
|
||||
from qutebrowser.browser.network import pastebin
|
||||
from qutebrowser.config import config
|
||||
|
||||
|
||||
def parse_fatal_stacktrace(text):
|
||||
"""Get useful information from a fatal faulthandler stacktrace.
|
||||
|
||||
Args:
|
||||
text: The text to parse.
|
||||
|
||||
Return:
|
||||
A tuple with the first element being the error type, and the second
|
||||
element being the first stacktrace frame.
|
||||
"""
|
||||
lines = [
|
||||
r'Fatal Python error: (.*)',
|
||||
r' *',
|
||||
r'Current thread [^ ]* \(most recent call first\): *',
|
||||
r' File ".*", line \d+ in (.*)',
|
||||
]
|
||||
m = re.match('\n'.join(lines), text)
|
||||
if m is None:
|
||||
# We got some invalid text.
|
||||
return ('', '')
|
||||
else:
|
||||
return (m.group(1), m.group(2))
|
||||
|
||||
|
||||
def get_fatal_crash_dialog(debug, data):
|
||||
"""Get a fatal crash dialog based on a crash log.
|
||||
|
||||
If the crash is a segfault in qt_mainloop and we're on an old Qt version
|
||||
this is a simple error dialog which lets the user know they should upgrade
|
||||
if possible.
|
||||
|
||||
If it's anything else, it's a normal FatalCrashDialog with the possibility
|
||||
to report the crash.
|
||||
|
||||
Args:
|
||||
debug: Whether the debug flag (--debug) was given.
|
||||
data: The crash log data.
|
||||
"""
|
||||
errtype, frame = parse_fatal_stacktrace(data)
|
||||
if (qtutils.version_check('5.4') or errtype != 'Segmentation fault' or
|
||||
frame != 'qt_mainloop'):
|
||||
return FatalCrashDialog(debug, data)
|
||||
else:
|
||||
title = "qutebrowser was restarted after a fatal crash!"
|
||||
text = ("<b>qutebrowser was restarted after a fatal crash!</b><br/>"
|
||||
"Unfortunately, this crash occured in Qt (the library "
|
||||
"qutebrowser uses), and your version ({}) is outdated - "
|
||||
"Qt 5.4 or later is recommended. Unfortuntately Debian and "
|
||||
"Ubuntu don't ship a newer version (yet?)...".format(
|
||||
qVersion()))
|
||||
return QMessageBox(QMessageBox.Critical, title, text, QMessageBox.Ok)
|
||||
|
||||
|
||||
class _CrashDialog(QDialog):
|
||||
|
||||
"""Dialog which gets shown after there was a crash.
|
||||
|
||||
Class attributes:
|
||||
NAME: The kind of condition we report.
|
||||
|
||||
Attributes:
|
||||
These are just here to have a static reference to avoid GCing.
|
||||
_vbox: The main QVBoxLayout
|
||||
_lbl: The QLabel with the static text
|
||||
_debug_log: The QTextEdit with the crash information
|
||||
_hbox: The QHboxLayout containing the buttons
|
||||
_btn_box: The QDialogButtonBox containing the buttons.
|
||||
_url: Pastebin URL QLabel.
|
||||
_crash_info: A list of tuples with title and crash information.
|
||||
_paste_client: A PastebinClient instance to use.
|
||||
_paste_text: The text to pastebin.
|
||||
_resolution: Whether the dialog should be accepted on close.
|
||||
"""
|
||||
|
||||
NAME = None
|
||||
|
||||
def __init__(self, debug, parent=None):
|
||||
"""Constructor for CrashDialog.
|
||||
|
||||
@@ -67,12 +117,11 @@ class _CrashDialog(QDialog):
|
||||
super().__init__(parent)
|
||||
# We don't set WA_DeleteOnClose here as on an exception, we'll get
|
||||
# closed anyways, and it only could have unintended side-effects.
|
||||
self._buttons = []
|
||||
self._crash_info = []
|
||||
self._hbox = None
|
||||
self._btn_box = None
|
||||
self._btn_report = None
|
||||
self._btn_cancel = None
|
||||
self._lbl = None
|
||||
self._chk_report = None
|
||||
self._resolution = None
|
||||
self._paste_text = None
|
||||
self.setWindowTitle("Whoops!")
|
||||
self.resize(QSize(640, 600))
|
||||
@@ -80,6 +129,23 @@ class _CrashDialog(QDialog):
|
||||
self._paste_client = pastebin.PastebinClient(self)
|
||||
self._init_text()
|
||||
|
||||
contact = QLabel("I'd like to be able to follow up with you, to keep "
|
||||
"you posted on the status of this crash and get more "
|
||||
"information if I need it - how can I contact you?",
|
||||
wordWrap=True)
|
||||
self._vbox.addWidget(contact)
|
||||
self._contact = QTextEdit(tabChangesFocus=True, acceptRichText=False)
|
||||
try:
|
||||
state = objreg.get('state-config')
|
||||
try:
|
||||
self._contact.setPlainText(state['general']['contact-info'])
|
||||
except KeyError:
|
||||
self._contact.setPlaceholderText("Mail or IRC nickname")
|
||||
except Exception:
|
||||
log.misc.exception("Failed to get contact information!")
|
||||
self._contact.setPlaceholderText("Mail or IRC nickname")
|
||||
self._vbox.addWidget(self._contact, 2)
|
||||
|
||||
info = QLabel("What were you doing when this crash/bug happened?")
|
||||
self._vbox.addWidget(info)
|
||||
self._info = QTextEdit(tabChangesFocus=True, acceptRichText=False)
|
||||
@@ -87,11 +153,6 @@ class _CrashDialog(QDialog):
|
||||
"- Switched tabs\n"
|
||||
"- etc...")
|
||||
self._vbox.addWidget(self._info, 5)
|
||||
contact = QLabel("How can I contact you if I need more info?")
|
||||
self._vbox.addWidget(contact)
|
||||
self._contact = QTextEdit(tabChangesFocus=True, acceptRichText=False)
|
||||
self._contact.setPlaceholderText("Github username, mail or IRC")
|
||||
self._vbox.addWidget(self._contact, 2)
|
||||
|
||||
self._vbox.addSpacing(15)
|
||||
self._debug_log = QTextEdit(tabChangesFocus=True, acceptRichText=False,
|
||||
@@ -110,7 +171,8 @@ class _CrashDialog(QDialog):
|
||||
self._vbox.addWidget(self._debug_log, 10)
|
||||
self._vbox.addSpacing(15)
|
||||
|
||||
self._init_checkboxes(debug)
|
||||
self._init_checkboxes()
|
||||
self._init_info_text()
|
||||
self._init_buttons()
|
||||
|
||||
def __repr__(self):
|
||||
@@ -124,28 +186,29 @@ class _CrashDialog(QDialog):
|
||||
textInteractionFlags=Qt.LinksAccessibleByMouse)
|
||||
self._vbox.addWidget(self._lbl)
|
||||
|
||||
def _init_checkboxes(self, debug):
|
||||
"""Initialize the checkboxes.
|
||||
|
||||
Args:
|
||||
debug: Whether a --debug arg was given.
|
||||
"""
|
||||
self._chk_report = QCheckBox("Send a report")
|
||||
if not debug:
|
||||
self._chk_report.setChecked(True)
|
||||
self._vbox.addWidget(self._chk_report)
|
||||
info_label = QLabel("<i>Note that without your help, I can't fix the "
|
||||
"bug you encountered.</i>", wordWrap=True)
|
||||
self._vbox.addWidget(info_label)
|
||||
def _init_checkboxes(self):
|
||||
"""Initialize the checkboxes."""
|
||||
pass
|
||||
|
||||
def _init_buttons(self):
|
||||
"""Initialize the buttons.
|
||||
"""Initialize the buttons."""
|
||||
self._btn_box = QDialogButtonBox()
|
||||
self._vbox.addWidget(self._btn_box)
|
||||
|
||||
Should be extended by subclasses to provide the actual buttons.
|
||||
"""
|
||||
self._hbox = QHBoxLayout()
|
||||
self._vbox.addLayout(self._hbox)
|
||||
self._hbox.addStretch()
|
||||
self._btn_report = QPushButton("Report", default=True)
|
||||
self._btn_report.clicked.connect(self.on_report_clicked)
|
||||
self._btn_box.addButton(self._btn_report, QDialogButtonBox.AcceptRole)
|
||||
|
||||
self._btn_cancel = QPushButton("Don't report", autoDefault=False)
|
||||
self._btn_cancel.clicked.connect(self.finish)
|
||||
self._btn_box.addButton(self._btn_cancel, QDialogButtonBox.RejectRole)
|
||||
|
||||
def _init_info_text(self):
|
||||
"""Add an info text encouraging the user to report crashes."""
|
||||
info_label = QLabel("<br/><b>Note that without your help, I can't fix "
|
||||
"the bug you encountered.<br/>I read and respond "
|
||||
"to all crash reports!</b>", wordWrap=True)
|
||||
self._vbox.addWidget(info_label)
|
||||
|
||||
def _gather_crash_info(self):
|
||||
"""Gather crash information to display.
|
||||
@@ -177,6 +240,31 @@ class _CrashDialog(QDialog):
|
||||
text = '\n\n'.join(chunks)
|
||||
self._debug_log.setText(text)
|
||||
|
||||
def _get_error_type(self):
|
||||
"""Get the type of the error we're reporting."""
|
||||
raise NotImplementedError
|
||||
|
||||
def _get_paste_title_desc(self):
|
||||
"""Get a short description of the paste."""
|
||||
return ''
|
||||
|
||||
def _get_paste_title(self):
|
||||
"""Get a title for the paste."""
|
||||
desc = self._get_paste_title_desc()
|
||||
title = "qute {} {}".format(
|
||||
qutebrowser.__version__, self._get_error_type())
|
||||
if desc:
|
||||
title += ' {}'.format(desc)
|
||||
return title
|
||||
|
||||
def _save_contact_info(self):
|
||||
"""Save the contact info to disk."""
|
||||
try:
|
||||
state = objreg.get('state-config')
|
||||
state['general']['contact-info'] = self._contact.toPlainText()
|
||||
except Exception:
|
||||
log.misc.exception("Failed to save contact information!")
|
||||
|
||||
def report(self):
|
||||
"""Paste the crash info into the pastebin."""
|
||||
lines = []
|
||||
@@ -194,7 +282,7 @@ class _CrashDialog(QDialog):
|
||||
user = 'unknown'
|
||||
try:
|
||||
# parent: http://p.cmpl.cc/90286958
|
||||
self._paste_client.paste(user, "qutebrowser {}".format(self.NAME),
|
||||
self._paste_client.paste(user, self._get_paste_title(),
|
||||
self._paste_text, parent='90286958')
|
||||
except Exception as e:
|
||||
log.misc.exception("Error while paste-binning")
|
||||
@@ -202,17 +290,14 @@ class _CrashDialog(QDialog):
|
||||
self.show_error(exc_text)
|
||||
|
||||
@pyqtSlot()
|
||||
def on_button_clicked(self, button, accept):
|
||||
"""Report and close dialog if button was clicked."""
|
||||
button.setText("Reporting...")
|
||||
for btn in self._buttons:
|
||||
btn.setEnabled(False)
|
||||
self._resolution = accept
|
||||
def on_report_clicked(self):
|
||||
"""Report and close dialog if report button was clicked."""
|
||||
self._btn_report.setEnabled(False)
|
||||
self._btn_cancel.setEnabled(False)
|
||||
self._btn_report.setText("Reporting...")
|
||||
self._paste_client.success.connect(self.finish)
|
||||
self._paste_client.error.connect(self.show_error)
|
||||
reported = self.maybe_report()
|
||||
if not reported:
|
||||
self.finish()
|
||||
self.report()
|
||||
|
||||
@pyqtSlot(str)
|
||||
def show_error(self, text):
|
||||
@@ -227,24 +312,9 @@ class _CrashDialog(QDialog):
|
||||
|
||||
@pyqtSlot()
|
||||
def finish(self):
|
||||
"""Accept/reject the dialog when reporting is done."""
|
||||
if self._resolution:
|
||||
self.accept()
|
||||
else:
|
||||
self.reject()
|
||||
|
||||
@pyqtSlot()
|
||||
def maybe_report(self):
|
||||
"""Report the bug if the user allowed us to.
|
||||
|
||||
Return:
|
||||
True if a report was done, False otherwise.
|
||||
"""
|
||||
if self._chk_report.isChecked():
|
||||
self.report()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
"""Save contact info and close the dialog."""
|
||||
self._save_contact_info()
|
||||
self.accept()
|
||||
|
||||
|
||||
class ExceptionCrashDialog(_CrashDialog):
|
||||
@@ -252,17 +322,15 @@ class ExceptionCrashDialog(_CrashDialog):
|
||||
"""Dialog which gets shown on an exception.
|
||||
|
||||
Attributes:
|
||||
_buttons: A list of buttons.
|
||||
_pages: A list of lists of the open pages (URLs as strings)
|
||||
_cmdhist: A list with the command history (as strings)
|
||||
_exc: An exception tuple (type, value, traceback)
|
||||
_objects: A list of all QObjects as string.
|
||||
"""
|
||||
|
||||
NAME = 'exception'
|
||||
|
||||
def __init__(self, debug, pages, cmdhist, exc, objects, parent=None):
|
||||
self._chk_log = None
|
||||
self._chk_restore = None
|
||||
super().__init__(debug, parent)
|
||||
self._pages = pages
|
||||
self._cmdhist = cmdhist
|
||||
@@ -278,26 +346,20 @@ class ExceptionCrashDialog(_CrashDialog):
|
||||
|
||||
def _init_buttons(self):
|
||||
super()._init_buttons()
|
||||
btn_quit = QPushButton("Quit")
|
||||
btn_quit.clicked.connect(
|
||||
functools.partial(self.on_button_clicked, btn_quit, False))
|
||||
self._hbox.addWidget(btn_quit)
|
||||
|
||||
btn_restart = QPushButton("Restart", default=True)
|
||||
btn_restart.clicked.connect(
|
||||
functools.partial(self.on_button_clicked, btn_restart, True))
|
||||
self._hbox.addWidget(btn_restart)
|
||||
|
||||
self._buttons = [btn_quit, btn_restart]
|
||||
|
||||
def _init_checkboxes(self, debug):
|
||||
"""Add checkboxes to send crash report."""
|
||||
super()._init_checkboxes(debug)
|
||||
self._chk_log = QCheckBox("Include a debug log and a list of open "
|
||||
"pages", checked=True)
|
||||
if debug:
|
||||
self._chk_log.setChecked(False)
|
||||
self._chk_log.setEnabled(False)
|
||||
def _init_checkboxes(self):
|
||||
"""Add checkboxes to the dialog."""
|
||||
super()._init_checkboxes()
|
||||
self._chk_restore = QCheckBox("Restore open pages")
|
||||
self._chk_restore.setChecked(True)
|
||||
self._vbox.addWidget(self._chk_restore)
|
||||
self._chk_log = QCheckBox("Include a debug log in the report",
|
||||
checked=True)
|
||||
try:
|
||||
if config.get('general', 'private-browsing'):
|
||||
self._chk_log.setChecked(False)
|
||||
except Exception:
|
||||
log.misc.exception("Error while checking private browsing mode")
|
||||
self._chk_log.toggled.connect(self._set_crash_info)
|
||||
self._vbox.addWidget(self._chk_log)
|
||||
info_label = QLabel("<i>This makes it a lot easier to diagnose the "
|
||||
@@ -305,12 +367,19 @@ class ExceptionCrashDialog(_CrashDialog):
|
||||
"information such as which pages you visited "
|
||||
"or keyboard input.</i>", wordWrap=True)
|
||||
self._vbox.addWidget(info_label)
|
||||
self._chk_report.toggled.connect(self.on_chk_report_toggled)
|
||||
|
||||
def _get_error_type(self):
|
||||
return 'exc'
|
||||
|
||||
def _get_paste_title_desc(self):
|
||||
desc = traceback.format_exception_only(self._exc[0], self._exc[1])
|
||||
return desc[0].rstrip()
|
||||
|
||||
def _gather_crash_info(self):
|
||||
self._crash_info += [
|
||||
("Exception", ''.join(traceback.format_exception(*self._exc))),
|
||||
]
|
||||
super()._gather_crash_info()
|
||||
if self._chk_log.isChecked():
|
||||
self._crash_info += [
|
||||
("Commandline args", ' '.join(sys.argv[1:])),
|
||||
@@ -318,8 +387,6 @@ class ExceptionCrashDialog(_CrashDialog):
|
||||
("Command history", '\n'.join(self._cmdhist)),
|
||||
("Objects", self._objects),
|
||||
]
|
||||
super()._gather_crash_info()
|
||||
if self._chk_log.isChecked():
|
||||
try:
|
||||
self._crash_info.append(
|
||||
("Debug log", log.ram_handler.dump_log()))
|
||||
@@ -328,11 +395,12 @@ class ExceptionCrashDialog(_CrashDialog):
|
||||
("Debug log", traceback.format_exc()))
|
||||
|
||||
@pyqtSlot()
|
||||
def on_chk_report_toggled(self):
|
||||
"""Disable log checkbox if report is disabled."""
|
||||
is_checked = self._chk_report.isChecked()
|
||||
self._chk_log.setEnabled(is_checked)
|
||||
self._chk_log.setChecked(is_checked)
|
||||
def finish(self):
|
||||
self._save_contact_info()
|
||||
if self._chk_restore.isChecked():
|
||||
self.accept()
|
||||
else:
|
||||
self.reject()
|
||||
|
||||
|
||||
class FatalCrashDialog(_CrashDialog):
|
||||
@@ -341,15 +409,25 @@ class FatalCrashDialog(_CrashDialog):
|
||||
|
||||
Attributes:
|
||||
_log: The log text to display.
|
||||
_type: The type of error which occured.
|
||||
_func: The function (top of the stack) in which the error occured.
|
||||
"""
|
||||
|
||||
NAME = 'segfault'
|
||||
|
||||
def __init__(self, debug, text, parent=None):
|
||||
super().__init__(debug, parent)
|
||||
self._log = text
|
||||
self.setAttribute(Qt.WA_DeleteOnClose)
|
||||
self._set_crash_info()
|
||||
self._type, self._func = parse_fatal_stacktrace(self._log)
|
||||
|
||||
def _get_error_type(self):
|
||||
if self._type == 'Segmentation fault':
|
||||
return 'segv'
|
||||
else:
|
||||
return self._type
|
||||
|
||||
def _get_paste_title_desc(self):
|
||||
return self._func
|
||||
|
||||
def _init_text(self):
|
||||
super()._init_text()
|
||||
@@ -361,18 +439,8 @@ class FatalCrashDialog(_CrashDialog):
|
||||
"stacktrace.asciidoc</a> to submit a stacktrace.<br/>")
|
||||
self._lbl.setText(text)
|
||||
|
||||
def _init_buttons(self):
|
||||
super()._init_buttons()
|
||||
btn_ok = QPushButton(text="OK", default=True)
|
||||
btn_ok.clicked.connect(
|
||||
functools.partial(self.on_button_clicked, btn_ok, True))
|
||||
self._hbox.addWidget(btn_ok)
|
||||
self._buttons = [btn_ok]
|
||||
|
||||
def _gather_crash_info(self):
|
||||
self._crash_info += [
|
||||
("Fault log", self._log),
|
||||
]
|
||||
self._crash_info.append(("Fault log", self._log))
|
||||
super()._gather_crash_info()
|
||||
|
||||
|
||||
@@ -386,12 +454,9 @@ class ReportDialog(_CrashDialog):
|
||||
_objects: A list of all QObjects as string.
|
||||
"""
|
||||
|
||||
NAME = 'report'
|
||||
|
||||
def __init__(self, pages, cmdhist, objects, parent=None):
|
||||
super().__init__(False, parent)
|
||||
self.setAttribute(Qt.WA_DeleteOnClose)
|
||||
self._btn_report = None
|
||||
self._pages = pages
|
||||
self._cmdhist = cmdhist
|
||||
self._objects = objects
|
||||
@@ -402,18 +467,13 @@ class ReportDialog(_CrashDialog):
|
||||
text = "Please describe the bug you encountered below."
|
||||
self._lbl.setText(text)
|
||||
|
||||
def _init_buttons(self):
|
||||
super()._init_buttons()
|
||||
self._btn_report = QPushButton("Report", default=True)
|
||||
self._btn_report.clicked.connect(
|
||||
functools.partial(self.on_button_clicked, self._btn_report, True))
|
||||
self._hbox.addWidget(self._btn_report)
|
||||
self._buttons = [self._btn_report]
|
||||
|
||||
def _init_checkboxes(self, _debug):
|
||||
"""We don't want any checkboxes as the user wanted to report."""
|
||||
def _init_info_text(self):
|
||||
"""We don't want an info text as the user wanted to report."""
|
||||
pass
|
||||
|
||||
def _get_error_type(self):
|
||||
return 'report'
|
||||
|
||||
def _gather_crash_info(self):
|
||||
super()._gather_crash_info()
|
||||
self._crash_info += [
|
||||
@@ -427,16 +487,6 @@ class ReportDialog(_CrashDialog):
|
||||
except Exception:
|
||||
self._crash_info.append(("Debug log", traceback.format_exc()))
|
||||
|
||||
@pyqtSlot()
|
||||
def maybe_report(self):
|
||||
"""Report the crash.
|
||||
|
||||
We don't have a "Send a report" checkbox here because it was a manual
|
||||
report, which would be pretty useless without this info.
|
||||
"""
|
||||
self.report()
|
||||
return True
|
||||
|
||||
|
||||
class ReportErrorDialog(QDialog):
|
||||
|
||||
|
||||
@@ -234,14 +234,14 @@ def check_libraries():
|
||||
'jinja2':
|
||||
_missing_str("jinja2",
|
||||
debian="apt-get install python3-jinja2",
|
||||
arch="Install python-jinja from the AUR",
|
||||
arch="Install python-jinja from community",
|
||||
windows="Install from http://www.lfd.uci.edu/"
|
||||
"~gohlke/pythonlibs/#jinja2 or via pip.",
|
||||
pip="jinja2"),
|
||||
'pygments':
|
||||
_missing_str("pygments",
|
||||
debian="apt-get install python3-pygments",
|
||||
arch="Install python-jinja from the AUR",
|
||||
arch="Install python-pygments from community",
|
||||
windows="Install from http://www.lfd.uci.edu/"
|
||||
"~gohlke/pythonlibs/#pygments or via pip.",
|
||||
pip="pygments"),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -43,7 +43,7 @@ class MinimalLineEditMixin:
|
||||
self.setAttribute(Qt.WA_MacShowFocusRect, False)
|
||||
|
||||
def __repr__(self):
|
||||
return utils.get_repr(self, text=self.text())
|
||||
return utils.get_repr(self)
|
||||
|
||||
|
||||
class CommandLineEdit(QLineEdit):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
@@ -58,7 +58,7 @@ def get_argparser():
|
||||
debug.add_argument('--loglines',
|
||||
help="How many lines of the debug log to keep in RAM "
|
||||
"(-1: unlimited).",
|
||||
default=1000, type=int)
|
||||
default=2000, type=int)
|
||||
debug.add_argument('--debug', help="Turn on debugging options.",
|
||||
action='store_true')
|
||||
debug.add_argument('--nocolor', help="Turn off colored logging.",
|
||||
@@ -110,7 +110,11 @@ def main():
|
||||
app = app.Application(args)
|
||||
|
||||
def qt_mainloop():
|
||||
"""Simple wrapper to get a nicer stack trace for segfaults."""
|
||||
"""Simple wrapper to get a nicer stack trace for segfaults.
|
||||
|
||||
WARNING: misc/crashdialog.py checks the stacktrace for this function
|
||||
name, so if this is changed, it should be changed there as well!
|
||||
"""
|
||||
return app.exec_() # pylint: disable=maybe-no-member
|
||||
|
||||
# We set qApp explicitely here to reduce the risk of segfaults while
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>:
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>:
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
75
qutebrowser/test/misc/test_crashdialog.py
Normal file
75
qutebrowser/test/misc/test_crashdialog.py
Normal file
@@ -0,0 +1,75 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014-2015 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/>.
|
||||
|
||||
"""Tests for qutebrowser.misc.crashdialog."""
|
||||
|
||||
import unittest
|
||||
|
||||
from qutebrowser.misc import crashdialog
|
||||
|
||||
|
||||
VALID_CRASH_TEXT = """
|
||||
Fatal Python error: Segmentation fault
|
||||
_
|
||||
Current thread 0x00007f09b538d700 (most recent call first):
|
||||
File "", line 1 in testfunc
|
||||
File "filename", line 88 in func
|
||||
"""
|
||||
|
||||
VALID_CRASH_TEXT_EMPTY = """
|
||||
Fatal Python error: Aborted
|
||||
_
|
||||
Current thread 0x00007f09b538d700 (most recent call first):
|
||||
File "", line 1 in_
|
||||
File "filename", line 88 in func
|
||||
"""
|
||||
|
||||
INVALID_CRASH_TEXT = """
|
||||
Hello world!
|
||||
"""
|
||||
|
||||
|
||||
class ParseFatalStacktraceTests(unittest.TestCase):
|
||||
|
||||
"""Tests for parse_fatal_stacktrace."""
|
||||
|
||||
def test_valid_text(self):
|
||||
"""Test parse_fatal_stacktrace with a valid text."""
|
||||
text = VALID_CRASH_TEXT.strip().replace('_', ' ')
|
||||
typ, func = crashdialog.parse_fatal_stacktrace(text)
|
||||
self.assertEqual(typ, "Segmentation fault")
|
||||
self.assertEqual(func, 'testfunc')
|
||||
|
||||
def test_valid_text(self):
|
||||
"""Test parse_fatal_stacktrace with a valid text but empty function."""
|
||||
text = VALID_CRASH_TEXT_EMPTY.strip().replace('_', ' ')
|
||||
typ, func = crashdialog.parse_fatal_stacktrace(text)
|
||||
self.assertEqual(typ, 'Aborted')
|
||||
self.assertEqual(func, '')
|
||||
|
||||
def test_invalid_text(self):
|
||||
"""Test parse_fatal_stacktrace with an invalid text."""
|
||||
text = INVALID_CRASH_TEXT.strip().replace('_', ' ')
|
||||
typ, func = crashdialog.parse_fatal_stacktrace(text)
|
||||
self.assertEqual(typ, '')
|
||||
self.assertEqual(func, '')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,6 +1,6 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user