Move quitter/signal/crash_handler out of qApp.

This commit is contained in:
Florian Bruhin 2015-05-06 08:51:44 +02:00
parent 564a589bc6
commit 3b5b49daac
2 changed files with 49 additions and 33 deletions

View File

@ -66,8 +66,22 @@ def run(args):
print(version.GPL_BOILERPLATE.strip()) print(version.GPL_BOILERPLATE.strip())
sys.exit(0) sys.exit(0)
quitter = Quitter(args)
objreg.register('quitter', quitter)
global qApp global qApp
qApp = Application(args) qApp = Application(args)
qApp.lastWindowClosed.connect(quitter.on_last_window_closed)
crash_handler = crashsignal.CrashHandler(
app=qApp, quitter=quitter, args=args, parent=qApp)
crash_handler.activate()
objreg.register('crash-handler', crash_handler)
signal_handler = crashsignal.SignalHandler(app=qApp, quitter=quitter,
parent=qApp)
signal_handler.activate()
objreg.register('signal-handler', signal_handler)
try: try:
sent = ipc.send_to_running_instance(args.command) sent = ipc.send_to_running_instance(args.command)
@ -93,7 +107,7 @@ def run(args):
# We didn't really initialize much so far, so we just quit hard. # We didn't really initialize much so far, so we just quit hard.
sys.exit(1) sys.exit(1)
init(args) init(args, crash_handler)
ret = qt_mainloop() ret = qt_mainloop()
return ret return ret
@ -107,8 +121,13 @@ def qt_mainloop():
return qApp.exec_() return qApp.exec_()
def init(args): def init(args, crash_handler):
"""Initialize everything.""" """Initialize everything.
Args:
args: The argparse namespace.
crash_handler: The CrashHandler instance.
"""
log.init.debug("Starting init...") log.init.debug("Starting init...")
qApp.setQuitOnLastWindowClosed(False) qApp.setQuitOnLastWindowClosed(False)
qApp.setOrganizationName("qutebrowser") qApp.setOrganizationName("qutebrowser")
@ -118,7 +137,7 @@ def init(args):
utils.actute_warning() utils.actute_warning()
try: try:
_init_modules(args) _init_modules(args, crash_handler)
except (OSError, UnicodeDecodeError) as e: except (OSError, UnicodeDecodeError) as e:
msgbox = QMessageBox( msgbox = QMessageBox(
QMessageBox.Critical, "Error while initializing!", QMessageBox.Critical, "Error while initializing!",
@ -143,7 +162,7 @@ def init(args):
QDesktopServices.setUrlHandler('qute', open_desktopservices_url) QDesktopServices.setUrlHandler('qute', open_desktopservices_url)
log.init.debug("Init done!") log.init.debug("Init done!")
qApp.crash_handler.raise_crashdlg() crash_handler.raise_crashdlg()
def _init_icon(): def _init_icon():
@ -342,8 +361,13 @@ def _maybe_hide_mouse_cursor():
qApp.restoreOverrideCursor() qApp.restoreOverrideCursor()
def _init_modules(args): def _init_modules(args, crash_handler):
"""Initialize all 'modules' which need to be initialized.""" """Initialize all 'modules' which need to be initialized.
Args:
args: The argparse namespace.
crash_handler: The CrashHandler instance.
"""
# pylint: disable=too-many-statements # pylint: disable=too-many-statements
log.init.debug("Initializing save manager...") log.init.debug("Initializing save manager...")
save_manager = savemanager.SaveManager(qApp) save_manager = savemanager.SaveManager(qApp)
@ -362,7 +386,7 @@ def _init_modules(args):
log.init.debug("Initializing web history...") log.init.debug("Initializing web history...")
history.init(qApp) history.init(qApp)
log.init.debug("Initializing crashlog...") log.init.debug("Initializing crashlog...")
qApp.crash_handler.handle_segfault() crash_handler.handle_segfault()
log.init.debug("Initializing sessions...") log.init.debug("Initializing sessions...")
sessions.init(qApp) sessions.init(qApp)
log.init.debug("Initializing js-bridge...") log.init.debug("Initializing js-bridge...")
@ -573,6 +597,9 @@ class Quitter:
def _shutdown(self, status): # noqa def _shutdown(self, status): # noqa
"""Second stage of shutdown.""" """Second stage of shutdown."""
log.destroy.debug("Stage 2 of shutting down...") log.destroy.debug("Stage 2 of shutting down...")
if qApp is None:
# No QApplication exists yet, so quit hard.
sys.exit(status)
# Remove eventfilter # Remove eventfilter
try: try:
log.destroy.debug("Removing eventfilter...") log.destroy.debug("Removing eventfilter...")
@ -602,14 +629,14 @@ class Quitter:
"Error while saving {}: {}".format(key, e)) "Error while saving {}: {}".format(key, e))
msgbox.exec_() msgbox.exec_()
# Re-enable faulthandler to stdout, then remove crash log # Re-enable faulthandler to stdout, then remove crash log
log.destroy.debug("Deactiving crash log...") log.destroy.debug("Deactivating crash log...")
qApp.crash_handler.destroy_crashlogfile() objreg.get('crash-handler').destroy_crashlogfile()
# If we don't kill our custom handler here we might get segfaults # If we don't kill our custom handler here we might get segfaults
log.destroy.debug("Deactiving message handler...") log.destroy.debug("Deactiving message handler...")
qInstallMessageHandler(None) qInstallMessageHandler(None)
# Now we can hopefully quit without segfaults # Now we can hopefully quit without segfaults
log.destroy.debug("Deferring QApplication::exit...") log.destroy.debug("Deferring QApplication::exit...")
qApp.signal_handler.deactivate() objreg.get('signal-handler').deactivate()
# We use a singleshot timer to exit here to minimize the likelihood of # We use a singleshot timer to exit here to minimize the likelihood of
# segfaults. # segfaults.
QTimer.singleShot(0, functools.partial(qApp.exit, status)) QTimer.singleShot(0, functools.partial(qApp.exit, status))
@ -630,11 +657,7 @@ class Application(QApplication):
"""Main application instance. """Main application instance.
Attributes: Attributes:
quitter: The Quitter objet.
crash_handler: The CrashHandler being used.
signal_handler: The SignalHandler being used.
_args: ArgumentParser instance. _args: ArgumentParser instance.
_shutting_down: True if we're currently shutting down.
""" """
def __init__(self, args): def __init__(self, args):
@ -648,17 +671,6 @@ class Application(QApplication):
super().__init__(qt_args) super().__init__(qt_args)
log.init.debug("Initializing application...") log.init.debug("Initializing application...")
self.quitter = Quitter(args)
self.lastWindowClosed.connect(self.quitter.on_last_window_closed)
objreg.register('quitter', self.quitter)
self.crash_handler = crashsignal.CrashHandler(app=self, args=args,
parent=self)
self.crash_handler.activate()
objreg.register('crash-handler', self.crash_handler)
self.signal_handler = crashsignal.SignalHandler(app=self, parent=self)
self.signal_handler.activate()
self._args = args self._args = args
objreg.register('args', args) objreg.register('args', args)

View File

@ -43,14 +43,16 @@ class CrashHandler(QObject):
Attributes: Attributes:
_app: The QApplication instance. _app: The QApplication instance.
_quitter: The Quitter instance.
_args: The argparse namespace. _args: The argparse namespace.
_crash_dialog: The CrashDialog currently being shown. _crash_dialog: The CrashDialog currently being shown.
_crash_log_file: The file handle for the faulthandler crash log. _crash_log_file: The file handle for the faulthandler crash log.
""" """
def __init__(self, app, args, parent=None): def __init__(self, *, app, quitter, args, parent=None):
super().__init__(parent) super().__init__(parent)
self._app = app self._app = app
self._quitter = quitter
self._args = args self._args = args
self._crash_log_file = None self._crash_log_file = None
self._crash_dialog = None self._crash_dialog = None
@ -160,7 +162,7 @@ class CrashHandler(QObject):
exc = (exctype, excvalue, tb) exc = (exctype, excvalue, tb)
qapp = QApplication.instance() qapp = QApplication.instance()
if not qapp.quitter.quit_status['crash']: if not self._quitter.quit_status['crash']:
log.misc.error("ARGH, there was an exception while the crash " log.misc.error("ARGH, there was an exception while the crash "
"dialog is already shown:", exc_info=exc) "dialog is already shown:", exc_info=exc)
return return
@ -185,7 +187,7 @@ class CrashHandler(QObject):
qapp.quit() qapp.quit()
return return
qapp.quitter.quit_status['crash'] = False self._quitter.quit_status['crash'] = False
try: try:
pages = self._recover_pages(forgiving=True) pages = self._recover_pages(forgiving=True)
@ -212,7 +214,7 @@ class CrashHandler(QObject):
try: try:
self._app.lastWindowClosed.disconnect( self._app.lastWindowClosed.disconnect(
self._app.quitter.on_last_window_closed) self._quitter.on_last_window_closed)
except TypeError: except TypeError:
log.destroy.exception("Error while preventing shutdown") log.destroy.exception("Error while preventing shutdown")
self._app.closeAllWindows() self._app.closeAllWindows()
@ -220,7 +222,7 @@ class CrashHandler(QObject):
self._args.debug, pages, cmd_history, exc, objects) self._args.debug, pages, cmd_history, exc, objects)
ret = self._crash_dialog.exec_() ret = self._crash_dialog.exec_()
if ret == QDialog.Accepted: # restore if ret == QDialog.Accepted: # restore
self._app.quitter.restart(pages) self._quitter.restart(pages)
# We might risk a segfault here, but that's better than continuing to # We might risk a segfault here, but that's better than continuing to
# run in some undefined state, so we only do the most needed shutdown # run in some undefined state, so we only do the most needed shutdown
@ -241,6 +243,7 @@ class SignalHandler(QObject):
Attributes: Attributes:
_app: The QApplication instance. _app: The QApplication instance.
_quitter: The Quitter instance.
_activated: Whether activate() was called. _activated: Whether activate() was called.
_notifier: A QSocketNotifier used for signals on Unix. _notifier: A QSocketNotifier used for signals on Unix.
_timer: A QTimer used to poll for signals on Windows. _timer: A QTimer used to poll for signals on Windows.
@ -248,9 +251,10 @@ class SignalHandler(QObject):
_orig_wakeup_fd: The original wakeup filedescriptor. _orig_wakeup_fd: The original wakeup filedescriptor.
""" """
def __init__(self, app, parent=None): def __init__(self, *, app, quitter, parent=None):
super().__init__(parent) super().__init__(parent)
self._app = app self._app = app
self._quitter = quitter
self._notifier = None self._notifier = None
self._timer = usertypes.Timer(self, 'python_hacks') self._timer = usertypes.Timer(self, 'python_hacks')
self._orig_handlers = {} self._orig_handlers = {}
@ -330,7 +334,7 @@ class SignalHandler(QObject):
signal.signal(signal.SIGTERM, self.interrupt_forcefully) signal.signal(signal.SIGTERM, self.interrupt_forcefully)
# If we call shutdown directly here, we get a segfault. # If we call shutdown directly here, we get a segfault.
QTimer.singleShot(0, functools.partial( QTimer.singleShot(0, functools.partial(
self._app.quitter.shutdown, 128 + signum)) self._quitter.shutdown, 128 + signum))
def interrupt_forcefully(self, signum, _frame): def interrupt_forcefully(self, signum, _frame):
"""Interrupt forcefully on the second SIGINT/SIGTERM request. """Interrupt forcefully on the second SIGINT/SIGTERM request.