diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py index 58fb117c9..454e2f33c 100644 --- a/qutebrowser/browser/browsertab.py +++ b/qutebrowser/browser/browsertab.py @@ -595,18 +595,20 @@ class AbstractTab(QWidget): """Return the widget events should be sent to.""" raise NotImplementedError - def send_event(self, evt, *, postpone=False): + def send_event(self, evt): """Send the given event to the underlying widget. - Args: - postpone: Postpone the event to be handled later instead of - immediately. Using this might cause crashes in Qt. + The event will be sent via QApplication.postEvent. + Note that a posted event may not be re-used in any way! """ + # This only gives us some mild protection against re-using events, but + # it's certainly better than a segfault. + if getattr(evt, 'posted', False): + raise AssertionError("Can't re-use an event which was already " + "posted!") recipient = self._event_target() - if postpone: - QApplication.postEvent(recipient, evt) - else: - QApplication.sendEvent(recipient, evt) + evt.posted = True + QApplication.postEvent(recipient, evt) @pyqtSlot(QUrl) def _on_link_clicked(self, url): diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index b5cc2621f..ee726f316 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1974,8 +1974,8 @@ class CommandDispatcher: window = QApplication.focusWindow() if window is None: raise cmdexc.CommandError("No focused window!") - QApplication.sendEvent(window, press_event) - QApplication.sendEvent(window, release_event) + QApplication.postEvent(window, press_event) + QApplication.postEvent(window, release_event) else: try: tab = objreg.get('tab', scope='tab', tab='current') diff --git a/qutebrowser/browser/webelem.py b/qutebrowser/browser/webelem.py index e0b661edb..7f7aab1dd 100644 --- a/qutebrowser/browser/webelem.py +++ b/qutebrowser/browser/webelem.py @@ -376,9 +376,7 @@ class AbstractWebElement(collections.abc.MutableMapping): ] for evt in events: - # For some reason, postpone=True is needed here to *not* cause - # segfaults in misc.feature because of :fake-key later... - self._tab.send_event(evt, postpone=True) + self._tab.send_event(evt) def after_click(): """Move cursor to end and reset override_target after clicking.""" diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index cbe1d01be..20c9ed30a 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -214,9 +214,9 @@ class WebEngineScroller(browsertab.AbstractScroller): def _key_press(self, key, count=1): # FIXME:qtwebengine Abort scrolling if the minimum/maximum was reached. - press_evt = QKeyEvent(QEvent.KeyPress, key, Qt.NoModifier, 0, 0, 0) - release_evt = QKeyEvent(QEvent.KeyRelease, key, Qt.NoModifier, 0, 0, 0) for _ in range(count): + press_evt = QKeyEvent(QEvent.KeyPress, key, Qt.NoModifier, 0, 0, 0) + release_evt = QKeyEvent(QEvent.KeyRelease, key, Qt.NoModifier, 0, 0, 0) self._tab.send_event(press_evt) self._tab.send_event(release_evt) diff --git a/qutebrowser/browser/webkit/webkittab.py b/qutebrowser/browser/webkit/webkittab.py index fe984b60e..c2d64a343 100644 --- a/qutebrowser/browser/webkit/webkittab.py +++ b/qutebrowser/browser/webkit/webkittab.py @@ -409,14 +409,15 @@ class WebKitScroller(browsertab.AbstractScroller): def _key_press(self, key, count=1, getter_name=None, direction=None): frame = self._widget.page().mainFrame() - press_evt = QKeyEvent(QEvent.KeyPress, key, Qt.NoModifier, 0, 0, 0) - release_evt = QKeyEvent(QEvent.KeyRelease, key, Qt.NoModifier, 0, 0, 0) getter = None if getter_name is None else getattr(frame, getter_name) # FIXME:qtwebengine needed? # self._widget.setFocus() for _ in range(count): + press_evt = QKeyEvent(QEvent.KeyPress, key, Qt.NoModifier, 0, 0, 0) + release_evt = QKeyEvent(QEvent.KeyRelease, key, Qt.NoModifier, + 0, 0, 0) # Abort scrolling if the minimum/maximum was reached. if (getter is not None and frame.scrollBarValue(direction) == getter(direction)): diff --git a/tests/end2end/features/scroll.feature b/tests/end2end/features/scroll.feature index db48613b5..87abfab3c 100644 --- a/tests/end2end/features/scroll.feature +++ b/tests/end2end/features/scroll.feature @@ -84,7 +84,6 @@ Feature: Scrolling And I wait until the scroll position changed to 0/0 Then the page should not be scrolled - # causes segfault with postEvent instead of sendEvent Scenario: Scrolling down with count 10 When I run :scroll down with count 10 Then no crash should happen