Handle exceptions with a crash dialog.
This commit is contained in:
parent
a71684ea0f
commit
2c276b98a4
@ -1,7 +1,9 @@
|
|||||||
""" Initialization of qutebrowser and application-wide things """
|
""" Initialization of qutebrowser and application-wide things """
|
||||||
|
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
|
import traceback
|
||||||
import faulthandler
|
import faulthandler
|
||||||
from signal import signal, SIGINT
|
from signal import signal, SIGINT
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
@ -12,12 +14,13 @@ from argparse import ArgumentParser
|
|||||||
import qutebrowser.utils.harfbuzz as harfbuzz
|
import qutebrowser.utils.harfbuzz as harfbuzz
|
||||||
harfbuzz.fix()
|
harfbuzz.fix()
|
||||||
|
|
||||||
from PyQt5.QtWidgets import QApplication
|
from PyQt5.QtWidgets import QApplication, QDialog
|
||||||
from PyQt5.QtCore import QUrl, QTimer
|
from PyQt5.QtCore import QUrl, QTimer
|
||||||
|
|
||||||
import qutebrowser.commands.utils as cmdutils
|
import qutebrowser.commands.utils as cmdutils
|
||||||
import qutebrowser.utils.config as config
|
import qutebrowser.utils.config as config
|
||||||
from qutebrowser.widgets.mainwindow import MainWindow
|
from qutebrowser.widgets.mainwindow import MainWindow
|
||||||
|
from qutebrowser.widgets import CrashDialog
|
||||||
from qutebrowser.commands.keys import KeyParser
|
from qutebrowser.commands.keys import KeyParser
|
||||||
from qutebrowser.utils.appdirs import AppDirs
|
from qutebrowser.utils.appdirs import AppDirs
|
||||||
|
|
||||||
@ -107,32 +110,57 @@ class QuteBrowser(QApplication):
|
|||||||
fallback='http://ddg.gg/').split(','):
|
fallback='http://ddg.gg/').split(','):
|
||||||
self.mainwindow.tabs.tabopen(url)
|
self.mainwindow.tabs.tabopen(url)
|
||||||
|
|
||||||
def _tmp_exception_hook(self, exctype, value, traceback):
|
def _tmp_exception_hook(self, exctype, excvalue, tb):
|
||||||
"""Handle exceptions while initializing by simply exiting.
|
"""Handle exceptions while initializing by simply exiting.
|
||||||
|
|
||||||
This is only temporary and will get replaced by exception_hook later.
|
This is only temporary and will get replaced by exception_hook later.
|
||||||
It's necessary because PyQt seems to ignore exceptions by default.
|
It's necessary because PyQt seems to ignore exceptions by default.
|
||||||
"""
|
"""
|
||||||
sys.__excepthook__(exctype, value, traceback)
|
sys.__excepthook__(exctype, excvalue, tb)
|
||||||
self.exit(1)
|
self.exit(1)
|
||||||
|
|
||||||
def _exception_hook(self, exctype, value, traceback):
|
def _exception_hook(self, exctype, excvalue, tb):
|
||||||
"""Handle uncaught python exceptions.
|
"""Handle uncaught python exceptions.
|
||||||
|
|
||||||
It'll try very hard to write all open tabs to a file, and then exit
|
It'll try very hard to write all open tabs to a file, and then exit
|
||||||
gracefully.
|
gracefully.
|
||||||
"""
|
"""
|
||||||
# pylint: disable=broad-except
|
# pylint: disable=broad-except
|
||||||
sys.__excepthook__(exctype, value, traceback)
|
|
||||||
|
exc = (exctype, excvalue, tb)
|
||||||
|
traceback.print_exception(*exc)
|
||||||
|
|
||||||
|
pages = []
|
||||||
try:
|
try:
|
||||||
for tabidx in range(self.mainwindow.tabs.count()):
|
for tabidx in range(self.mainwindow.tabs.count()):
|
||||||
try:
|
try:
|
||||||
# FIXME write to some file
|
url = self.mainwindow.tabs.widget(tabidx).url().toString()
|
||||||
print(self.mainwindow.tabs.widget(tabidx).url().url())
|
url = url.strip()
|
||||||
|
if url:
|
||||||
|
pages.append(url)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
history = self.mainwindow.status.cmd.history[-5:]
|
||||||
|
except Exception:
|
||||||
|
history = []
|
||||||
|
|
||||||
|
dlg = CrashDialog(pages, history, exc)
|
||||||
|
ret = dlg.exec_()
|
||||||
|
if ret == QDialog.Accepted: # restore
|
||||||
|
os.environ['PYTHONPATH'] = os.pathsep.join(sys.path)
|
||||||
|
# FIXME we might want to use argparse's features to not open pages
|
||||||
|
# again if they were opened via cmdline
|
||||||
|
argv = [sys.executable] + sys.argv + pages
|
||||||
|
logging.debug('Running {} with args {}'.format(sys.executable,
|
||||||
|
argv))
|
||||||
|
sys.stdout.flush()
|
||||||
|
# FIXME this seems broken on Windows, execv() splits on whitespace
|
||||||
|
# in arguments?!?
|
||||||
|
os.execv(sys.executable, argv)
|
||||||
self.exit(1)
|
self.exit(1)
|
||||||
|
|
||||||
def _python_hacks(self):
|
def _python_hacks(self):
|
||||||
|
@ -1 +1,59 @@
|
|||||||
"""The Qt widgets needed by qutebrowser."""
|
"""The Qt widgets needed by qutebrowser."""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import (QDialog, QLabel, QTextEdit, QVBoxLayout,
|
||||||
|
QHBoxLayout, QPushButton)
|
||||||
|
|
||||||
|
import qutebrowser.utils as utils
|
||||||
|
|
||||||
|
|
||||||
|
class CrashDialog(QDialog):
|
||||||
|
"""Dialog which gets shown after there was a crash."""
|
||||||
|
|
||||||
|
def __init__(self, pages, cmdhist, exc):
|
||||||
|
super().__init__()
|
||||||
|
self.setFixedSize(500, 350)
|
||||||
|
self.setWindowTitle('Whoops!')
|
||||||
|
|
||||||
|
vbox = QVBoxLayout()
|
||||||
|
lbl = QLabel(self)
|
||||||
|
#lbl.setGeometry(5, 5, 395, 295)
|
||||||
|
lbl.setText(
|
||||||
|
'Argh! qutebrowser crashed unexpectedly.<br/>'
|
||||||
|
'Please review the info below to remove sensitive data and then '
|
||||||
|
'submit it to '
|
||||||
|
'<a href="mailto:me@the-compiler.org">me@the-compiler.org</a>.'
|
||||||
|
'<br/><br/>You can click "Restore tabs" to attempt to reopen your '
|
||||||
|
'open pages.'
|
||||||
|
)
|
||||||
|
vbox.addWidget(lbl)
|
||||||
|
|
||||||
|
txt = QTextEdit(self)
|
||||||
|
txt.setReadOnly(True)
|
||||||
|
#txt.setGeometry(5, 400, 395, 295)
|
||||||
|
txt.setText(
|
||||||
|
'==== Version info ====\n{}\n\n'.format(utils.version()) +
|
||||||
|
'==== Exception ====\n{}\n'.format(
|
||||||
|
''.join(traceback.format_exception(*exc))) +
|
||||||
|
'==== Open pages ====\n{}\n\n'.format('\n'.join(pages)) +
|
||||||
|
'==== Command history ====\n{}\n\n'.format('\n'.join(cmdhist)) +
|
||||||
|
'==== Commandline args ====\n{}'.format(' '.join(sys.argv[1:]))
|
||||||
|
)
|
||||||
|
vbox.addWidget(txt)
|
||||||
|
self.setLayout(vbox)
|
||||||
|
|
||||||
|
hbox = QHBoxLayout()
|
||||||
|
btn_quit = QPushButton(self)
|
||||||
|
btn_quit.setText('Quit')
|
||||||
|
btn_quit.clicked.connect(self.reject)
|
||||||
|
hbox.addWidget(btn_quit)
|
||||||
|
btn_restore = QPushButton(self)
|
||||||
|
btn_restore.setText('Restore tabs')
|
||||||
|
btn_restore.clicked.connect(self.accept)
|
||||||
|
btn_restore.setDefault(True)
|
||||||
|
hbox.addWidget(btn_restore)
|
||||||
|
|
||||||
|
vbox.addLayout(hbox)
|
||||||
|
self.show()
|
||||||
|
Loading…
Reference in New Issue
Block a user