Make closing/crashing much more reliable.
This commit is contained in:
parent
966ceba1e6
commit
8c37e1c33a
@ -70,6 +70,7 @@ class QuteBrowser(QApplication):
|
|||||||
keyparser = None
|
keyparser = None
|
||||||
args = None # ArgumentParser
|
args = None # ArgumentParser
|
||||||
timer = None # QTimer for python hacks
|
timer = None # QTimer for python hacks
|
||||||
|
shutting_down = False
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(sys.argv)
|
super().__init__(sys.argv)
|
||||||
@ -94,7 +95,8 @@ class QuteBrowser(QApplication):
|
|||||||
self._init_cmds()
|
self._init_cmds()
|
||||||
self.mainwindow = MainWindow()
|
self.mainwindow = MainWindow()
|
||||||
|
|
||||||
self.aboutToQuit.connect(self._shutdown)
|
self.setQuitOnLastWindowClosed(False)
|
||||||
|
self.lastWindowClosed.connect(self.shutdown)
|
||||||
self.mainwindow.tabs.keypress.connect(self.keyparser.handle)
|
self.mainwindow.tabs.keypress.connect(self.keyparser.handle)
|
||||||
self.keyparser.set_cmd_text.connect(
|
self.keyparser.set_cmd_text.connect(
|
||||||
self.mainwindow.status.cmd.on_set_cmd_text)
|
self.mainwindow.status.cmd.on_set_cmd_text)
|
||||||
@ -171,6 +173,15 @@ class QuteBrowser(QApplication):
|
|||||||
except Exception:
|
except Exception:
|
||||||
history = []
|
history = []
|
||||||
|
|
||||||
|
# Try to shutdown gracefully
|
||||||
|
try:
|
||||||
|
self.shutdown(do_quit=False)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
self.lastWindowClosed.disconnect(self.shutdown)
|
||||||
|
except TypeError:
|
||||||
|
logging.exception("Preventing shutdown failed.")
|
||||||
QApplication.closeAllWindows()
|
QApplication.closeAllWindows()
|
||||||
dlg = CrashDialog(pages, history, exc)
|
dlg = CrashDialog(pages, history, exc)
|
||||||
ret = dlg.exec_()
|
ret = dlg.exec_()
|
||||||
@ -182,7 +193,10 @@ class QuteBrowser(QApplication):
|
|||||||
logging.debug('Running {} with args {}'.format(sys.executable,
|
logging.debug('Running {} with args {}'.format(sys.executable,
|
||||||
argv))
|
argv))
|
||||||
subprocess.Popen(argv)
|
subprocess.Popen(argv)
|
||||||
sys.exit(1)
|
try:
|
||||||
|
self.quit()
|
||||||
|
except Exception:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
def _python_hacks(self):
|
def _python_hacks(self):
|
||||||
"""Get around some PyQt-oddities by evil hacks.
|
"""Get around some PyQt-oddities by evil hacks.
|
||||||
@ -246,10 +260,24 @@ class QuteBrowser(QApplication):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def _shutdown(self):
|
def shutdown(self, do_quit=True):
|
||||||
"""Try to shutdown everything cleanly."""
|
"""Try to shutdown everything cleanly.
|
||||||
|
|
||||||
|
For some reason lastWindowClosing sometimes seem to get emitted twice,
|
||||||
|
so we make sure we only run once here.
|
||||||
|
|
||||||
|
quit -- Whether to quit after shutting down.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if self.shutting_down:
|
||||||
|
return
|
||||||
|
self.shutting_down = True
|
||||||
|
logging.debug("Shutting down...")
|
||||||
config.config.save()
|
config.config.save()
|
||||||
|
self.mainwindow.tabs.shutdown_complete.connect(self.quit)
|
||||||
self.mainwindow.tabs.shutdown()
|
self.mainwindow.tabs.shutdown()
|
||||||
|
if do_quit:
|
||||||
|
self.quit()
|
||||||
|
|
||||||
@pyqtSlot(tuple)
|
@pyqtSlot(tuple)
|
||||||
def cmd_handler(self, tpl):
|
def cmd_handler(self, tpl):
|
||||||
@ -272,7 +300,7 @@ class QuteBrowser(QApplication):
|
|||||||
'opencur': self.mainwindow.tabs.opencur,
|
'opencur': self.mainwindow.tabs.opencur,
|
||||||
'tabopen': self.mainwindow.tabs.tabopen,
|
'tabopen': self.mainwindow.tabs.tabopen,
|
||||||
'tabopencur': self.mainwindow.tabs.tabopencur,
|
'tabopencur': self.mainwindow.tabs.tabopencur,
|
||||||
'quit': self.quit,
|
'quit': self.shutdown,
|
||||||
'tabclose': self.mainwindow.tabs.cur_close,
|
'tabclose': self.mainwindow.tabs.cur_close,
|
||||||
'tabprev': self.mainwindow.tabs.switch_prev,
|
'tabprev': self.mainwindow.tabs.switch_prev,
|
||||||
'tabnext': self.mainwindow.tabs.switch_next,
|
'tabnext': self.mainwindow.tabs.switch_next,
|
||||||
|
@ -67,6 +67,7 @@ class TabbedBrowser(TabWidget):
|
|||||||
cur_scroll_perc_changed = pyqtSignal(int, int)
|
cur_scroll_perc_changed = pyqtSignal(int, int)
|
||||||
set_cmd_text = pyqtSignal(str) # Set commandline to a given text
|
set_cmd_text = pyqtSignal(str) # Set commandline to a given text
|
||||||
keypress = pyqtSignal('QKeyEvent')
|
keypress = pyqtSignal('QKeyEvent')
|
||||||
|
shutdown_complete = pyqtSignal() # All tabs have been shut down.
|
||||||
_url_stack = [] # Stack of URLs of closed tabs
|
_url_stack = [] # Stack of URLs of closed tabs
|
||||||
_space = None # Space QShortcut
|
_space = None # Space QShortcut
|
||||||
_tabs = None
|
_tabs = None
|
||||||
@ -154,15 +155,22 @@ class TabbedBrowser(TabWidget):
|
|||||||
# FIXME maybe we actually should store the webview objects here
|
# FIXME maybe we actually should store the webview objects here
|
||||||
self._url_stack.append(tab.url())
|
self._url_stack.append(tab.url())
|
||||||
self.removeTab(idx)
|
self.removeTab(idx)
|
||||||
try:
|
tab.shutdown(callback=functools.partial(self._cb_tab_shutdown,
|
||||||
self._tabs.remove(tab)
|
tab))
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
tab.shutdown()
|
|
||||||
else:
|
else:
|
||||||
# FIXME
|
# FIXME
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def _cb_tab_shutdown(self, tab):
|
||||||
|
"""Called after a tab has been shut down completely."""
|
||||||
|
try:
|
||||||
|
self._tabs.remove(tab)
|
||||||
|
except ValueError:
|
||||||
|
logging.error("tab {} could not be removed from tabs {}.".format(
|
||||||
|
tab, self._tabs))
|
||||||
|
if not self._tabs: # all tabs shut down
|
||||||
|
self.shutdown_complete.emit()
|
||||||
|
|
||||||
def cur_reload(self, count=None):
|
def cur_reload(self, count=None):
|
||||||
"""Reload the current/[count]th tab.
|
"""Reload the current/[count]th tab.
|
||||||
|
|
||||||
@ -433,9 +441,14 @@ class TabbedBrowser(TabWidget):
|
|||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
"""Try to shut down all tabs cleanly."""
|
"""Try to shut down all tabs cleanly."""
|
||||||
self.currentChanged.disconnect()
|
try:
|
||||||
|
self.currentChanged.disconnect()
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
for tabidx in range(self.count()):
|
for tabidx in range(self.count()):
|
||||||
self.widget(tabidx).shutdown()
|
tab = self.widget(tabidx)
|
||||||
|
tab.shutdown(callback=functools.partial(self._cb_tab_shutdown,
|
||||||
|
tab))
|
||||||
|
|
||||||
|
|
||||||
class BrowserTab(QWebView):
|
class BrowserTab(QWebView):
|
||||||
@ -451,12 +464,15 @@ class BrowserTab(QWebView):
|
|||||||
open_tab = pyqtSignal('QUrl')
|
open_tab = pyqtSignal('QUrl')
|
||||||
linkHovered = pyqtSignal(str, str, str)
|
linkHovered = pyqtSignal(str, str, str)
|
||||||
_scroll_pos = (-1, -1)
|
_scroll_pos = (-1, -1)
|
||||||
|
_shutdown_callback = None # callback to be called after shutdown
|
||||||
_open_new_tab = False # open new tab for the next action
|
_open_new_tab = False # open new tab for the next action
|
||||||
|
_destroyed = None # Dict of all items to be destroyed.
|
||||||
# dict of tab specific signals, and the values we last got from them.
|
# dict of tab specific signals, and the values we last got from them.
|
||||||
signal_cache = None
|
signal_cache = None
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
self._destroyed = {}
|
||||||
self.setPage(BrowserPage())
|
self.setPage(BrowserPage())
|
||||||
self.signal_cache = SignalCache(uncached=['linkHovered'])
|
self.signal_cache = SignalCache(uncached=['linkHovered'])
|
||||||
self.loadProgress.connect(self.on_load_progress)
|
self.loadProgress.connect(self.on_load_progress)
|
||||||
@ -513,7 +529,7 @@ class BrowserTab(QWebView):
|
|||||||
"""
|
"""
|
||||||
self.progress = prog
|
self.progress = prog
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self, callback=None):
|
||||||
"""Shut down the tab cleanly and remove it.
|
"""Shut down the tab cleanly and remove it.
|
||||||
|
|
||||||
Inspired by [1].
|
Inspired by [1].
|
||||||
@ -521,13 +537,37 @@ class BrowserTab(QWebView):
|
|||||||
[1] https://github.com/integricho/path-of-a-pyqter/tree/master/qttut08
|
[1] https://github.com/integricho/path-of-a-pyqter/tree/master/qttut08
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
page = self.page()
|
||||||
|
netman = page.networkAccessManager()
|
||||||
|
self._shutdown_callback = callback
|
||||||
|
try:
|
||||||
|
# Avoid loading finished signal when stopping
|
||||||
|
self.loadFinished.disconnect()
|
||||||
|
except TypeError:
|
||||||
|
logging.exception("This should never happen.")
|
||||||
self.stop()
|
self.stop()
|
||||||
self.close()
|
self.close()
|
||||||
self.settings().setAttribute(QWebSettings.JavascriptEnabled, False)
|
self.settings().setAttribute(QWebSettings.JavascriptEnabled, False)
|
||||||
self.page().deleteLater()
|
|
||||||
|
self._destroyed[page] = False
|
||||||
|
page.destroyed.connect(functools.partial(self.on_destroyed, page))
|
||||||
|
page.deleteLater()
|
||||||
|
|
||||||
|
self._destroyed[self] = False
|
||||||
|
self.destroyed.connect(functools.partial(self.on_destroyed, self))
|
||||||
self.deleteLater()
|
self.deleteLater()
|
||||||
self.page().networkAccessManager().abort_requests()
|
|
||||||
self.page().networkAccessManager().deleteLater()
|
self._destroyed[netman] = False
|
||||||
|
netman.abort_requests()
|
||||||
|
netman.destroyed.connect(functools.partial(self.on_destroyed, netman))
|
||||||
|
netman.deleteLater()
|
||||||
|
|
||||||
|
def on_destroyed(self, sender):
|
||||||
|
"""Called when a subsystem has been destroyed during shutdown."""
|
||||||
|
self._destroyed[sender] = True
|
||||||
|
if all(self._destroyed.values()):
|
||||||
|
if self._shutdown_callback is not None:
|
||||||
|
self._shutdown_callback()
|
||||||
|
|
||||||
def eventFilter(self, watched, e):
|
def eventFilter(self, watched, e):
|
||||||
"""Dirty hack to emit a signal if the scroll position changed.
|
"""Dirty hack to emit a signal if the scroll position changed.
|
||||||
|
Loading…
Reference in New Issue
Block a user