Use QApplication.postEvent again

We had some funny segfaults reported during scrolling (i.e. with
QApplication.sendEvent), and some code already had to use postpone=True
so there was no segfault...

So now we're back to postEvent again, and eliminated the main reason for
segfaults with it, which was re-using (and -posting) events which had
already been posted.

At least during tests this seems to run stable, let's hope it helps for
the people having crashes as well.
This commit is contained in:
Florian Bruhin 2016-09-11 19:37:09 +02:00
parent de03feabfe
commit fff777404b
6 changed files with 18 additions and 18 deletions

View File

@ -595,18 +595,20 @@ class AbstractTab(QWidget):
"""Return the widget events should be sent to.""" """Return the widget events should be sent to."""
raise NotImplementedError raise NotImplementedError
def send_event(self, evt, *, postpone=False): def send_event(self, evt):
"""Send the given event to the underlying widget. """Send the given event to the underlying widget.
Args: The event will be sent via QApplication.postEvent.
postpone: Postpone the event to be handled later instead of Note that a posted event may not be re-used in any way!
immediately. Using this might cause crashes in Qt.
""" """
# 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() recipient = self._event_target()
if postpone: evt.posted = True
QApplication.postEvent(recipient, evt) QApplication.postEvent(recipient, evt)
else:
QApplication.sendEvent(recipient, evt)
@pyqtSlot(QUrl) @pyqtSlot(QUrl)
def _on_link_clicked(self, url): def _on_link_clicked(self, url):

View File

@ -1974,8 +1974,8 @@ class CommandDispatcher:
window = QApplication.focusWindow() window = QApplication.focusWindow()
if window is None: if window is None:
raise cmdexc.CommandError("No focused window!") raise cmdexc.CommandError("No focused window!")
QApplication.sendEvent(window, press_event) QApplication.postEvent(window, press_event)
QApplication.sendEvent(window, release_event) QApplication.postEvent(window, release_event)
else: else:
try: try:
tab = objreg.get('tab', scope='tab', tab='current') tab = objreg.get('tab', scope='tab', tab='current')

View File

@ -376,9 +376,7 @@ class AbstractWebElement(collections.abc.MutableMapping):
] ]
for evt in events: for evt in events:
# For some reason, postpone=True is needed here to *not* cause self._tab.send_event(evt)
# segfaults in misc.feature because of :fake-key later...
self._tab.send_event(evt, postpone=True)
def after_click(): def after_click():
"""Move cursor to end and reset override_target after clicking.""" """Move cursor to end and reset override_target after clicking."""

View File

@ -214,9 +214,9 @@ class WebEngineScroller(browsertab.AbstractScroller):
def _key_press(self, key, count=1): def _key_press(self, key, count=1):
# FIXME:qtwebengine Abort scrolling if the minimum/maximum was reached. # 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): 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(press_evt)
self._tab.send_event(release_evt) self._tab.send_event(release_evt)

View File

@ -409,14 +409,15 @@ class WebKitScroller(browsertab.AbstractScroller):
def _key_press(self, key, count=1, getter_name=None, direction=None): def _key_press(self, key, count=1, getter_name=None, direction=None):
frame = self._widget.page().mainFrame() 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) getter = None if getter_name is None else getattr(frame, getter_name)
# FIXME:qtwebengine needed? # FIXME:qtwebengine needed?
# self._widget.setFocus() # self._widget.setFocus()
for _ in range(count): 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. # Abort scrolling if the minimum/maximum was reached.
if (getter is not None and if (getter is not None and
frame.scrollBarValue(direction) == getter(direction)): frame.scrollBarValue(direction) == getter(direction)):

View File

@ -84,7 +84,6 @@ Feature: Scrolling
And I wait until the scroll position changed to 0/0 And I wait until the scroll position changed to 0/0
Then the page should not be scrolled Then the page should not be scrolled
# causes segfault with postEvent instead of sendEvent
Scenario: Scrolling down with count 10 Scenario: Scrolling down with count 10
When I run :scroll down with count 10 When I run :scroll down with count 10
Then no crash should happen Then no crash should happen