summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <git@the-compiler.org>2015-03-16 23:23:49 +0100
committerFlorian Bruhin <git@the-compiler.org>2015-03-19 06:21:08 +0100
commita4a60995155791ebcbc981d34b08efd6be753606 (patch)
treea1b729949d8fadd0ead9407ed3c82ac6c9c3007f
parent44dd4da33f6fe9520e6b7442fb9eaebd9ed78788 (diff)
downloadqutebrowser-a4a60995155791ebcbc981d34b08efd6be753606.tar.gz
qutebrowser-a4a60995155791ebcbc981d34b08efd6be753606.zip
Don't poll for signals on Unix.
A better solution is to use QSocketNotifier and os.wakeup_fd to get notified about new signals. Thanks to Yuya Nishihara / TortoiseHG for the hint! Fixes #555.
-rw-r--r--qutebrowser/app.py54
1 files changed, 42 insertions, 12 deletions
diff --git a/qutebrowser/app.py b/qutebrowser/app.py
index aa64b5639..6084688b9 100644
--- a/qutebrowser/app.py
+++ b/qutebrowser/app.py
@@ -34,7 +34,7 @@ import faulthandler
from PyQt5.QtWidgets import QApplication, QDialog, QMessageBox
from PyQt5.QtGui import QDesktopServices, QPixmap, QIcon
from PyQt5.QtCore import (pyqtSlot, qInstallMessageHandler, QTimer, QUrl,
- QStandardPaths, QObject, Qt)
+ QStandardPaths, QObject, Qt, QSocketNotifier)
import qutebrowser
import qutebrowser.resources # pylint: disable=unused-import
@@ -62,6 +62,8 @@ class Application(QApplication):
_crashdlg: The crash dialog currently open.
_crashlogfile: A file handler to the fatal crash logfile.
_event_filter: The EventFilter for the application.
+ _signal_notifier: A QSocketNotifier used for signals on Unix.
+ _signal_timer: A QTimer used to poll for signals on Windows.
geometry: The geometry of the last closed main window.
"""
@@ -145,8 +147,8 @@ class Application(QApplication):
log.init.debug("Connecting signals...")
self._connect_signals()
- log.init.debug("Applying python hacks...")
- self._python_hacks()
+ log.init.debug("Setting up signal handlers...")
+ self._setup_signals()
QDesktopServices.setUrlHandler('http', self.open_desktopservices_url)
QDesktopServices.setUrlHandler('https', self.open_desktopservices_url)
@@ -378,19 +380,47 @@ class Application(QApplication):
pass
state_config['general']['quickstart-done'] = '1'
- def _python_hacks(self):
- """Get around some PyQt-oddities by evil hacks.
+ def _setup_signals(self):
+ """Set up signal handlers.
- This sets up the uncaught exception hook, quits with an appropriate
- exit status, and handles Ctrl+C properly by passing control to the
- Python interpreter once all 500ms.
+ On Windows this uses a QTimer to periodically hand control over to
+ Python so it can handle signals.
+
+ On Unix, it uses a QSocketNotifier with os.set_wakeup_fd to get
+ notified.
"""
signal.signal(signal.SIGINT, self.interrupt)
signal.signal(signal.SIGTERM, self.interrupt)
- timer = usertypes.Timer(self, 'python_hacks')
- timer.start(500)
- timer.timeout.connect(lambda: None)
- objreg.register('python-hack-timer', timer)
+
+ if os.name == 'posix' and hasattr(signal, 'set_wakeup_fd'):
+ import fcntl
+ read_fd, write_fd = os.pipe()
+ for fd in (read_fd, write_fd):
+ flags = fcntl.fcntl(fd, fcntl.F_GETFL)
+ fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
+ self._signal_notifier = QSocketNotifier(
+ read_fd, QSocketNotifier.Read, self)
+ self._signal_notifier.activated.connect(self._handle_signal_wakeup)
+ signal.set_wakeup_fd(write_fd)
+ else:
+ self._signal_timer = usertypes.Timer(self, 'python_hacks')
+ self._signal_timer.start(1000)
+ self._signal_timer.timeout.connect(lambda: None)
+
+ @pyqtSlot()
+ def _handle_signal_wakeup(self):
+ """This gets called via self._signal_notifier when there's a signal.
+
+ Python will get control here, so the signal will get handled.
+ """
+ log.destroy.debug("Handling signal wakeup!")
+ self._signal_notifier.setEnabled(False)
+ read_fd = self._signal_notifier.socket()
+ try:
+ os.read(read_fd, 1)
+ except OSError:
+ log.destroy.exception("Failed to read wakeup fd.")
+ self._signal_notifier.setEnabled(True)
def _connect_signals(self):
"""Connect all signals to their slots."""