diff --git a/doc/BUGS b/doc/BUGS index f3da407b8..eb3d529c8 100644 --- a/doc/BUGS +++ b/doc/BUGS @@ -9,8 +9,6 @@ Downloads - Download focus rectangle on windows - download-page on qute:htmllog is broken - Prevent invalid filenames (e.g. com1) when downloading on Windows -- When quitting while being asked for a download filename: segfault / memory - corruption Webview ------- diff --git a/qutebrowser/app.py b/qutebrowser/app.py index d0402f45b..91c179087 100644 --- a/qutebrowser/app.py +++ b/qutebrowser/app.py @@ -704,6 +704,23 @@ class Application(QApplication): return self._shutting_down = True log.destroy.debug("Shutting down with status {}...".format(status)) + if self.mainwindow.status.prompt.prompter.shutdown(): + # If shutdown was called while we were asking a question, we're in + # a still sub-eventloop (which gets quitted now) and not in the + # main one. + # This means we need to defer the real shutdown to when we're back + # in the real main event loop, or we'll get a segfault. + log.destroy.debug("Deferring real shutdown because question was " + "active.") + QTimer.singleShot(0, partial(self._shutdown, status)) + else: + # If we have no questions to shut down, we are already in the real + # event loop, so we can shut down immediately. + self._shutdown(status) + + def _shutdown(self, status): + """Second stage of shutdown.""" + log.destroy.debug("Stage 2 of shutting down...") # Remove eventfilter if self.modeman is not None: log.destroy.debug("Removing eventfilter...") diff --git a/qutebrowser/widgets/statusbar/prompter.py b/qutebrowser/widgets/statusbar/prompter.py index 7ebf88b3f..890a6ab78 100644 --- a/qutebrowser/widgets/statusbar/prompter.py +++ b/qutebrowser/widgets/statusbar/prompter.py @@ -157,6 +157,23 @@ class Prompter: self._busy = True return mode + def shutdown(self): + """Cancel all blocking questions. + + Quits and removes all running eventloops. + + Return: + True if loops needed to be aborted, + False otherwise. + """ + if self._loops: + for loop in self._loops: + loop.quit() + loop.deleteLater() + return True + else: + return False + @pyqtSlot(KeyMode) def on_mode_left(self, mode): """Clear and reset input when the mode was left."""