Compare commits

...

59 Commits

Author SHA1 Message Date
Florian Bruhin
612afc45ef Release v0.1.3 2015-02-12 06:22:14 +01:00
Florian Bruhin
3050c09150 Regenerate docs 2015-02-12 06:20:36 +01:00
Florian Bruhin
b44d7c0b84 Don't show line edit text in its repr().
Previously we showed self.text in the __repr__ of MinimalLineEdit. This however
is a bad idea, because it exposes passwords to the debug log when the currently
focused widget is logged.
2015-02-11 23:38:01 +01:00
Florian Bruhin
b852daeeae Handle shutdown of page with prompt correctly.
Before we didn't cancel javascript prompts when a page was closed, which lead
to exceptions or segfaults.
2015-02-11 23:15:41 +01:00
Florian Bruhin
f146003858 Don't log statusbar messages in signalfilter. 2015-02-11 23:15:41 +01:00
Florian Bruhin
a09503d5b5 Don't log javascript console messages by default. 2015-02-11 23:15:41 +01:00
Florian Bruhin
659fa02613 Keep more debug log in memory. 2015-02-11 23:15:41 +01:00
Florian Bruhin
ecfdf7b077 Reorder stacktrace.asciidoc 2015-02-11 23:12:32 +01:00
Florian Bruhin
cacc42417b Update Arch section in stacktrace.asciidoc. 2015-02-11 23:12:32 +01:00
Florian Bruhin
2403e5b792 fuzzy_url: handle invalid URLs with autosearch off
Fixes #497.
2015-02-11 23:12:32 +01:00
Florian Bruhin
9b05455c40 Handle explicit searches with auto-search=false.
See #497.
2015-02-11 23:12:32 +01:00
Florian Bruhin
e957796915 Abort download override question on error/cancel.
If a download error occured or the user cancelled the download during the file
override question, an exception occured as the download was no longer valid
when the question was answered.

See #416.
2015-02-11 23:12:32 +01:00
Florian Bruhin
1de82a2e63 Set a higher z-index for hint labels.
This fixes hinting on the youtube top bar.

Fixes #496.
2015-02-11 23:12:32 +01:00
Florian Bruhin
54eed6a88f Don't open relative files in fuzzy_url with :open
With most actions which use fuzzy_url (:open/quickmarks/etc.) it's rather
confusing when relative files are opened - the only place where they should be
opened is when we're processing a commandline argument.
2015-02-11 23:12:32 +01:00
Florian Bruhin
c0bc6368d1 Minor style adjustments in crashdialog.py. 2015-02-11 23:12:32 +01:00
Florian Bruhin
51549fc17f Hide adblocked iframes.
We now hide iframes which have been blocked completely instead of displaying an
error page in there. Displaying the error page also did break back/forward,
e.g. on reddit.

Fixes #493.
2015-02-11 23:12:32 +01:00
Florian Bruhin
38a236a31a Close contextmenu when closing tab to avoid crash.
Fixes #494.
2015-02-11 23:12:32 +01:00
Florian Bruhin
a065568549 Fix statusbar quickly popping up as window. 2015-02-11 23:12:32 +01:00
Florian Bruhin
4abd7089ed Clean up NetworkManager after downloads finished.
Fixes #490.
2015-02-11 23:12:32 +01:00
Florian Bruhin
d37064aa5a Fix restoring of cmd widget after an error.
We accidentally restored the prompt widget instead of the command widget when
an immediate error message interrupted command mode.

Fixes #487.

Conflicts (cherry-pick):
	qutebrowser/mainwindow/statusbar/bar.py
2015-02-11 23:12:13 +01:00
Florian Bruhin
9625791018 Fix retrying of downloads after the tab is closed. 2015-02-11 23:11:34 +01:00
Florian Bruhin
5c9718c8cd crashdialog: Shorten paste titles.
Unfortunately the maximum char count for paste titles is 32...
2015-02-11 23:11:34 +01:00
Florian Bruhin
7655313d39 Remove restore checkbox from fatal report dialog. 2015-02-11 23:11:34 +01:00
Florian Bruhin
c42c19683a Display error on qt_mainloop crashes with old Qt.
See #447.
2015-02-11 23:11:34 +01:00
Florian Bruhin
2f55e216b0 Use qVersion() instead of QT_VERSION_STR. 2015-02-11 23:11:34 +01:00
Florian Bruhin
a5264bdebd Crash dialog redesign.
We now have "Report/Don't report" buttons and a restart checkbox (checked by
default), so users don't accidentally send reports when they don't want to.
2015-02-11 23:11:34 +01:00
Florian Bruhin
5f310b4385 Produce better titles for crash logs.
See #483 and #447.
2015-02-11 23:11:34 +01:00
Thorsten Wißmann
b2a01934b6 Fix some check_libraries() for arch
By now, the python-jinja and python-pygments packages are available in
community.
2015-02-11 23:11:34 +01:00
Florian Bruhin
00003e4ff6 crashdialog: Move contact info to top.
See #447.
2015-02-11 23:11:34 +01:00
Florian Bruhin
30ac341b8e crashdialog: Reword contact info text.
See #447.
2015-02-11 23:11:34 +01:00
Florian Bruhin
49943efa87 crashdialog: Remove Github from contact types.
See #447.
2015-02-11 23:11:34 +01:00
Florian Bruhin
bfd2ef830e Handle all IPCErrors properly. 2015-02-11 23:11:34 +01:00
Florian Bruhin
6f831c292e Move version info more to the top in logs. 2015-02-11 23:11:34 +01:00
Florian Bruhin
0842dc1bf3 Handle another webelem.IsNullError with hints. 2015-02-11 23:11:34 +01:00
Florian Bruhin
302929be9d Save report dialog contact infomation. 2015-02-11 23:11:34 +01:00
Florian Bruhin
8011a3c63d Handle UnicodeDecodeError when reading configs.
(WTF are you guys doing?!)
2015-02-11 23:11:34 +01:00
Florian Bruhin
d9d5b2df0c Release v0.1.2 2015-01-09 22:30:04 +01:00
Florian Bruhin
d6fd5a817e Regenerate docs. 2015-01-09 22:28:25 +01:00
Florian Bruhin
301186d407 Use qurl_from_user_input() in urlutils.is_url().
It seems 354018efcd broke IPv6 IPs on older Qt
versions:

======================================================================
FAIL: test_urls (qutebrowser.test.utils.test_urlutils.IsUrlTests) (url='2001:41d0:2:6c11::1')
Test things which are URLs.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/var/lib/buildbot/slaves/slave/ubuntu-utopic/build/qutebrowser/test/utils/test_urlutils.py", line 168, in test_urls
    self.assertTrue(urlutils.is_url(url), url)
AssertionError: False is not true : 2001:41d0:2:6c11::1
2015-01-09 22:26:35 +01:00
Florian Bruhin
ab121a98da Enter KeyMode.normal directly in ModeManager.
We used to enter KeyMode.none and then with a zero-time singleShot QTimer enter
the normal mode. This doesn't really make sense, and caused an exception if a
keypress was processed before the timer fired.

Fixes #433.
2015-01-09 22:26:35 +01:00
Florian Bruhin
a463038834 Make sure QUrl::fromUserInput is valid in is_url.
Fixes #460.

Without this fix, it's possible for URLs to be valid according to is_url, but
not according to QUrl::fromUserInput, e.g. "http:foo:0". This caused an
exception later because fuzzy_url runs qtutils.ensure_valid.
2015-01-09 22:26:35 +01:00
Florian Bruhin
22761b4373 Switch Qt style to Fusion on OS X on Qt 5.4.
Fixes #462.
See #459.

Upstream bugs:

https://bugreports.qt.io/browse/QTBUG-42948
https://bugreports.qt.io/browse/QTBUG-43070
2015-01-09 19:27:44 +01:00
Florian Bruhin
78f6f3a0e1 Fix error handling for local files in :adblock-update 2015-01-09 07:17:47 +01:00
Florian Bruhin
6166ea51e2 Hide 2 more Qt warnings. 2015-01-09 07:17:47 +01:00
Florian Bruhin
4d4065dfac Add !important to all hint properties. 2015-01-09 07:17:47 +01:00
Error 800
81f350ee99 Added !important to hint styles
Prevents websites from overriding hint styles
2015-01-09 07:16:44 +01:00
Florian Bruhin
4b98e6e9ce Make init_venv.py work with multiple sip .so files.
On my Debian jessie there's a sip.cpython-34m-x86_64-linux-gnu.so and a
sip.cpython-34dm-x86_64-linux-gnu.so.
2015-01-09 07:16:44 +01:00
Florian Bruhin
11f8ab1f85 Fix maxsplit-splitting with empty args (""/'').
Fixes #453.
2015-01-09 07:16:44 +01:00
Florian Bruhin
0449da048f Uncheck sending of debug log with private browsing.
Fixes #436.
2015-01-09 07:16:44 +01:00
Error 800
c78e938dea Added !important to hint styles
Prevents websites from overriding hint styles
2015-01-09 07:16:44 +01:00
Error 800
99fb8a5d87 Fixed uppercase hints option
Corrected CSS property from 'texttransform' to 'text-transform'
2015-01-09 07:16:44 +01:00
Matthias Lisin
b1e0b8f119 Commas are awesome
Fixes #438
Fixes #439
2015-01-09 07:16:43 +01:00
Florian Bruhin
8d49e001e9 Abort blocking questions when new page is loaded.
Fixes #430.
Fixes #431.
Hopefully fixes #354.
Hopefully fixes #434.

Conflicts:
	qutebrowser/browser/network/networkmanager.py
2015-01-09 07:16:32 +01:00
Florian Bruhin
965c176acf Fix validation of ShellCommand config type.
Fixes #432.
2015-01-09 07:15:44 +01:00
Florian Bruhin
896da1c27e Add SSL info to version info. 2015-01-09 07:15:44 +01:00
Florian Bruhin
8f33fcfc52 Replace unencodable chars in download filenames.
Fixes #427.
2015-01-09 07:15:44 +01:00
Florian Bruhin
91b0a33ab0 Update copyright years 2015-01-09 07:15:43 +01:00
Florian Bruhin
b059f4058f Remove hosts-file.net from blocker default lists. 2015-01-09 07:15:43 +01:00
Florian Bruhin
b63ce438b4 Fix user-stylesheet setting with an empty value. 2015-01-09 07:15:43 +01:00
147 changed files with 926 additions and 508 deletions

View File

@@ -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

View File

@@ -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&amp;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&amp;mimetype=plaintext]+
== hints
Hinting settings.

View File

@@ -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

View 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.
#

View File

@@ -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."

View File

@@ -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.
#

View File

@@ -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))

View File

@@ -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.
#

View File

@@ -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)

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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."""

View File

@@ -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.
#

View File

@@ -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')

View File

@@ -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.
#

View File

@@ -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
#

View File

@@ -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>

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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>

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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)

View File

@@ -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.
#

View File

@@ -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

View File

@@ -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())

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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:

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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:

View File

@@ -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"

View File

@@ -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.
#

View File

@@ -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:

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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)

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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')

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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

View File

@@ -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.
#

View File

@@ -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()

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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):

View File

@@ -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"),

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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):

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View File

@@ -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.
#

View 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()

View File

@@ -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