Attempt to fix a crash in touch event handlers.

This commit is contained in:
John Preston 2017-11-30 22:18:39 +04:00
parent 595af2c6d9
commit afd1548533
5 changed files with 226 additions and 198 deletions

View File

@ -685,81 +685,84 @@ void HistoryInner::touchEvent(QTouchEvent *e) {
}
switch (e->type()) {
case QEvent::TouchBegin:
if (_menu) {
e->accept();
return; // ignore mouse press, that was hiding context menu
}
if (_touchInProgress) return;
if (e->touchPoints().isEmpty()) return;
case QEvent::TouchBegin: {
if (_menu) {
e->accept();
return; // ignore mouse press, that was hiding context menu
}
if (_touchInProgress) return;
if (e->touchPoints().isEmpty()) return;
_touchInProgress = true;
if (_touchScrollState == Ui::TouchScrollState::Auto) {
_touchScrollState = Ui::TouchScrollState::Acceleration;
_touchWaitingAcceleration = true;
_touchAccelerationTime = getms();
touchUpdateSpeed();
_touchStart = _touchPos;
} else {
_touchScroll = false;
_touchSelectTimer.start(QApplication::startDragTime());
}
_touchSelect = false;
_touchStart = _touchPrevPos = _touchPos;
break;
case QEvent::TouchUpdate:
if (!_touchInProgress) return;
if (_touchSelect) {
mouseActionUpdate(_touchPos);
} else if (!_touchScroll && (_touchPos - _touchStart).manhattanLength() >= QApplication::startDragDistance()) {
_touchSelectTimer.stop();
_touchScroll = true;
touchUpdateSpeed();
}
if (_touchScroll) {
if (_touchScrollState == Ui::TouchScrollState::Manual) {
touchScrollUpdated(_touchPos);
} else if (_touchScrollState == Ui::TouchScrollState::Acceleration) {
touchUpdateSpeed();
_touchInProgress = true;
if (_touchScrollState == Ui::TouchScrollState::Auto) {
_touchScrollState = Ui::TouchScrollState::Acceleration;
_touchWaitingAcceleration = true;
_touchAccelerationTime = getms();
if (_touchSpeed.isNull()) {
_touchScrollState = Ui::TouchScrollState::Manual;
touchUpdateSpeed();
_touchStart = _touchPos;
} else {
_touchScroll = false;
_touchSelectTimer.start(QApplication::startDragTime());
}
_touchSelect = false;
_touchStart = _touchPrevPos = _touchPos;
} break;
case QEvent::TouchUpdate: {
if (!_touchInProgress) return;
if (_touchSelect) {
mouseActionUpdate(_touchPos);
} else if (!_touchScroll && (_touchPos - _touchStart).manhattanLength() >= QApplication::startDragDistance()) {
_touchSelectTimer.stop();
_touchScroll = true;
touchUpdateSpeed();
}
if (_touchScroll) {
if (_touchScrollState == Ui::TouchScrollState::Manual) {
touchScrollUpdated(_touchPos);
} else if (_touchScrollState == Ui::TouchScrollState::Acceleration) {
touchUpdateSpeed();
_touchAccelerationTime = getms();
if (_touchSpeed.isNull()) {
_touchScrollState = Ui::TouchScrollState::Manual;
}
}
}
}
break;
} break;
case QEvent::TouchEnd:
if (!_touchInProgress) return;
_touchInProgress = false;
if (_touchSelect) {
mouseActionFinish(_touchPos, Qt::RightButton);
QContextMenuEvent contextMenu(QContextMenuEvent::Mouse, mapFromGlobal(_touchPos), _touchPos);
showContextMenu(&contextMenu, true);
_touchScroll = false;
} else if (_touchScroll) {
if (_touchScrollState == Ui::TouchScrollState::Manual) {
_touchScrollState = Ui::TouchScrollState::Auto;
_touchPrevPosValid = false;
_touchScrollTimer.start(15);
_touchTime = getms();
} else if (_touchScrollState == Ui::TouchScrollState::Auto) {
_touchScrollState = Ui::TouchScrollState::Manual;
case QEvent::TouchEnd: {
if (!_touchInProgress) return;
_touchInProgress = false;
auto weak = make_weak(this);
if (_touchSelect) {
mouseActionFinish(_touchPos, Qt::RightButton);
QContextMenuEvent contextMenu(QContextMenuEvent::Mouse, mapFromGlobal(_touchPos), _touchPos);
showContextMenu(&contextMenu, true);
_touchScroll = false;
touchResetSpeed();
} else if (_touchScrollState == Ui::TouchScrollState::Acceleration) {
_touchScrollState = Ui::TouchScrollState::Auto;
_touchWaitingAcceleration = false;
_touchPrevPosValid = false;
} else if (_touchScroll) {
if (_touchScrollState == Ui::TouchScrollState::Manual) {
_touchScrollState = Ui::TouchScrollState::Auto;
_touchPrevPosValid = false;
_touchScrollTimer.start(15);
_touchTime = getms();
} else if (_touchScrollState == Ui::TouchScrollState::Auto) {
_touchScrollState = Ui::TouchScrollState::Manual;
_touchScroll = false;
touchResetSpeed();
} else if (_touchScrollState == Ui::TouchScrollState::Acceleration) {
_touchScrollState = Ui::TouchScrollState::Auto;
_touchWaitingAcceleration = false;
_touchPrevPosValid = false;
}
} else { // One short tap is like left mouse click.
mouseActionStart(_touchPos, Qt::LeftButton);
mouseActionFinish(_touchPos, Qt::LeftButton);
}
} else { // One short tap is like left mouse click.
mouseActionStart(_touchPos, Qt::LeftButton);
mouseActionFinish(_touchPos, Qt::LeftButton);
}
_touchSelectTimer.stop();
_touchSelect = false;
break;
if (weak) {
_touchSelectTimer.stop();
_touchSelect = false;
}
} break;
}
}

View File

@ -2657,35 +2657,36 @@ void MediaView::contextMenuEvent(QContextMenuEvent *e) {
void MediaView::touchEvent(QTouchEvent *e) {
switch (e->type()) {
case QEvent::TouchBegin:
case QEvent::TouchBegin: {
if (_touchPress || e->touchPoints().isEmpty()) return;
_touchTimer.start(QApplication::startDragTime());
_touchPress = true;
_touchMove = _touchRightButton = false;
_touchStart = e->touchPoints().cbegin()->screenPos().toPoint();
break;
} break;
case QEvent::TouchUpdate:
case QEvent::TouchUpdate: {
if (!_touchPress || e->touchPoints().isEmpty()) return;
if (!_touchMove && (e->touchPoints().cbegin()->screenPos().toPoint() - _touchStart).manhattanLength() >= QApplication::startDragDistance()) {
_touchMove = true;
}
break;
} break;
case QEvent::TouchEnd:
case QEvent::TouchEnd: {
if (!_touchPress) return;
auto weak = make_weak(this);
if (!_touchMove) {
Qt::MouseButton btn(_touchRightButton ? Qt::RightButton : Qt::LeftButton);
auto mapped = mapFromGlobal(_touchStart);
QMouseEvent pressEvent(QEvent::MouseButtonPress, mapped, mapped, _touchStart, btn, Qt::MouseButtons(btn), Qt::KeyboardModifiers());
pressEvent.accept();
mousePressEvent(&pressEvent);
if (weak) mousePressEvent(&pressEvent);
QMouseEvent releaseEvent(QEvent::MouseButtonRelease, mapped, mapped, _touchStart, btn, Qt::MouseButtons(btn), Qt::KeyboardModifiers());
mouseReleaseEvent(&releaseEvent);
if (weak) mouseReleaseEvent(&releaseEvent);
if (_touchRightButton) {
if (weak && _touchRightButton) {
QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart);
contextMenuEvent(&contextEvent);
}
@ -2697,14 +2698,16 @@ void MediaView::touchEvent(QTouchEvent *e) {
}
}
}
_touchTimer.stop();
_touchPress = _touchMove = _touchRightButton = false;
break;
if (weak) {
_touchTimer.stop();
_touchPress = _touchMove = _touchRightButton = false;
}
} break;
case QEvent::TouchCancel:
case QEvent::TouchCancel: {
_touchPress = false;
_touchTimer.stop();
break;
} break;
}
}

View File

@ -278,40 +278,43 @@ bool FlatTextarea::viewportEvent(QEvent *e) {
void FlatTextarea::touchEvent(QTouchEvent *e) {
switch (e->type()) {
case QEvent::TouchBegin:
if (_touchPress || e->touchPoints().isEmpty()) return;
_touchTimer.start(QApplication::startDragTime());
_touchPress = true;
_touchMove = _touchRightButton = false;
_touchStart = e->touchPoints().cbegin()->screenPos().toPoint();
break;
case QEvent::TouchBegin: {
if (_touchPress || e->touchPoints().isEmpty()) return;
_touchTimer.start(QApplication::startDragTime());
_touchPress = true;
_touchMove = _touchRightButton = false;
_touchStart = e->touchPoints().cbegin()->screenPos().toPoint();
} break;
case QEvent::TouchUpdate:
if (!_touchPress || e->touchPoints().isEmpty()) return;
if (!_touchMove && (e->touchPoints().cbegin()->screenPos().toPoint() - _touchStart).manhattanLength() >= QApplication::startDragDistance()) {
_touchMove = true;
}
break;
case QEvent::TouchEnd:
if (!_touchPress) return;
if (!_touchMove && window()) {
Qt::MouseButton btn(_touchRightButton ? Qt::RightButton : Qt::LeftButton);
QPoint mapped(mapFromGlobal(_touchStart)), winMapped(window()->mapFromGlobal(_touchStart));
if (_touchRightButton) {
QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart);
contextMenuEvent(&contextEvent);
case QEvent::TouchUpdate: {
if (!_touchPress || e->touchPoints().isEmpty()) return;
if (!_touchMove && (e->touchPoints().cbegin()->screenPos().toPoint() - _touchStart).manhattanLength() >= QApplication::startDragDistance()) {
_touchMove = true;
}
}
_touchTimer.stop();
_touchPress = _touchMove = _touchRightButton = false;
break;
} break;
case QEvent::TouchCancel:
_touchPress = false;
_touchTimer.stop();
break;
case QEvent::TouchEnd: {
if (!_touchPress) return;
auto weak = make_weak(this);
if (!_touchMove && window()) {
Qt::MouseButton btn(_touchRightButton ? Qt::RightButton : Qt::LeftButton);
QPoint mapped(mapFromGlobal(_touchStart)), winMapped(window()->mapFromGlobal(_touchStart));
if (_touchRightButton) {
QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart);
contextMenuEvent(&contextEvent);
}
}
if (weak) {
_touchTimer.stop();
_touchPress = _touchMove = _touchRightButton = false;
}
} break;
case QEvent::TouchCancel: {
_touchPress = false;
_touchTimer.stop();
} break;
}
}
@ -1523,23 +1526,24 @@ bool FlatInput::event(QEvent *e) {
void FlatInput::touchEvent(QTouchEvent *e) {
switch (e->type()) {
case QEvent::TouchBegin:
case QEvent::TouchBegin: {
if (_touchPress || e->touchPoints().isEmpty()) return;
_touchTimer.start(QApplication::startDragTime());
_touchPress = true;
_touchMove = _touchRightButton = false;
_touchStart = e->touchPoints().cbegin()->screenPos().toPoint();
break;
} break;
case QEvent::TouchUpdate:
case QEvent::TouchUpdate: {
if (!_touchPress || e->touchPoints().isEmpty()) return;
if (!_touchMove && (e->touchPoints().cbegin()->screenPos().toPoint() - _touchStart).manhattanLength() >= QApplication::startDragDistance()) {
_touchMove = true;
}
break;
} break;
case QEvent::TouchEnd:
case QEvent::TouchEnd: {
if (!_touchPress) return;
auto weak = make_weak(this);
if (!_touchMove && window()) {
Qt::MouseButton btn(_touchRightButton ? Qt::RightButton : Qt::LeftButton);
QPoint mapped(mapFromGlobal(_touchStart)), winMapped(window()->mapFromGlobal(_touchStart));
@ -1549,14 +1553,16 @@ void FlatInput::touchEvent(QTouchEvent *e) {
contextMenuEvent(&contextEvent);
}
}
_touchTimer.stop();
_touchPress = _touchMove = _touchRightButton = false;
break;
if (weak) {
_touchTimer.stop();
_touchPress = _touchMove = _touchRightButton = false;
}
} break;
case QEvent::TouchCancel:
case QEvent::TouchCancel: {
_touchPress = false;
_touchTimer.stop();
break;
} break;
}
}
@ -1857,23 +1863,24 @@ bool InputArea::Inner::viewportEvent(QEvent *e) {
void InputArea::touchEvent(QTouchEvent *e) {
switch (e->type()) {
case QEvent::TouchBegin:
case QEvent::TouchBegin: {
if (_touchPress || e->touchPoints().isEmpty()) return;
_touchTimer.start(QApplication::startDragTime());
_touchPress = true;
_touchMove = _touchRightButton = false;
_touchStart = e->touchPoints().cbegin()->screenPos().toPoint();
break;
} break;
case QEvent::TouchUpdate:
case QEvent::TouchUpdate: {
if (!_touchPress || e->touchPoints().isEmpty()) return;
if (!_touchMove && (e->touchPoints().cbegin()->screenPos().toPoint() - _touchStart).manhattanLength() >= QApplication::startDragDistance()) {
_touchMove = true;
}
break;
} break;
case QEvent::TouchEnd:
case QEvent::TouchEnd: {
if (!_touchPress) return;
auto weak = make_weak(this);
if (!_touchMove && window()) {
Qt::MouseButton btn(_touchRightButton ? Qt::RightButton : Qt::LeftButton);
QPoint mapped(mapFromGlobal(_touchStart)), winMapped(window()->mapFromGlobal(_touchStart));
@ -1883,14 +1890,16 @@ void InputArea::touchEvent(QTouchEvent *e) {
contextMenuEvent(&contextEvent);
}
}
_touchTimer.stop();
_touchPress = _touchMove = _touchRightButton = false;
break;
if (weak) {
_touchTimer.stop();
_touchPress = _touchMove = _touchRightButton = false;
}
} break;
case QEvent::TouchCancel:
case QEvent::TouchCancel: {
_touchPress = false;
_touchTimer.stop();
break;
} break;
}
}
@ -2593,23 +2602,25 @@ bool InputField::Inner::viewportEvent(QEvent *e) {
void InputField::touchEvent(QTouchEvent *e) {
switch (e->type()) {
case QEvent::TouchBegin:
case QEvent::TouchBegin: {
if (_touchPress || e->touchPoints().isEmpty()) return;
_touchTimer.start(QApplication::startDragTime());
_touchPress = true;
_touchMove = _touchRightButton = false;
_touchStart = e->touchPoints().cbegin()->screenPos().toPoint();
break;
} break;
case QEvent::TouchUpdate:
case QEvent::TouchUpdate: {
if (!_touchPress || e->touchPoints().isEmpty()) return;
if (!_touchMove && (e->touchPoints().cbegin()->screenPos().toPoint() - _touchStart).manhattanLength() >= QApplication::startDragDistance()) {
_touchMove = true;
}
break;
} break;
case QEvent::TouchEnd:
{
if (!_touchPress) return;
auto weak = make_weak(this);
if (!_touchMove && window()) {
Qt::MouseButton btn(_touchRightButton ? Qt::RightButton : Qt::LeftButton);
QPoint mapped(mapFromGlobal(_touchStart)), winMapped(window()->mapFromGlobal(_touchStart));
@ -2619,14 +2630,16 @@ void InputField::touchEvent(QTouchEvent *e) {
contextMenuEvent(&contextEvent);
}
}
_touchTimer.stop();
_touchPress = _touchMove = _touchRightButton = false;
break;
if (weak) {
_touchTimer.stop();
_touchPress = _touchMove = _touchRightButton = false;
}
} break;
case QEvent::TouchCancel:
case QEvent::TouchCancel: {
_touchPress = false;
_touchTimer.stop();
break;
} break;
}
}
@ -3376,23 +3389,24 @@ bool MaskedInputField::eventHook(QEvent *e) {
void MaskedInputField::touchEvent(QTouchEvent *e) {
switch (e->type()) {
case QEvent::TouchBegin:
case QEvent::TouchBegin: {
if (_touchPress || e->touchPoints().isEmpty()) return;
_touchTimer.start(QApplication::startDragTime());
_touchPress = true;
_touchMove = _touchRightButton = false;
_touchStart = e->touchPoints().cbegin()->screenPos().toPoint();
break;
} break;
case QEvent::TouchUpdate:
case QEvent::TouchUpdate: {
if (!_touchPress || e->touchPoints().isEmpty()) return;
if (!_touchMove && (e->touchPoints().cbegin()->screenPos().toPoint() - _touchStart).manhattanLength() >= QApplication::startDragDistance()) {
_touchMove = true;
}
break;
} break;
case QEvent::TouchEnd:
case QEvent::TouchEnd: {
if (!_touchPress) return;
auto weak = make_weak(this);
if (!_touchMove && window()) {
Qt::MouseButton btn(_touchRightButton ? Qt::RightButton : Qt::LeftButton);
QPoint mapped(mapFromGlobal(_touchStart)), winMapped(window()->mapFromGlobal(_touchStart));
@ -3402,14 +3416,16 @@ void MaskedInputField::touchEvent(QTouchEvent *e) {
contextMenuEvent(&contextEvent);
}
}
_touchTimer.stop();
_touchPress = _touchMove = _touchRightButton = false;
break;
if (weak) {
_touchTimer.stop();
_touchPress = _touchMove = _touchRightButton = false;
}
} break;
case QEvent::TouchCancel:
case QEvent::TouchCancel: {
_touchPress = false;
_touchTimer.stop();
break;
} break;
}
}

View File

@ -483,42 +483,45 @@ void FlatLabel::touchEvent(QTouchEvent *e) {
}
switch (e->type()) {
case QEvent::TouchBegin:
if (_contextMenu) {
e->accept();
return; // ignore mouse press, that was hiding context menu
}
if (_touchInProgress) return;
if (e->touchPoints().isEmpty()) return;
case QEvent::TouchBegin: {
if (_contextMenu) {
e->accept();
return; // ignore mouse press, that was hiding context menu
}
if (_touchInProgress) return;
if (e->touchPoints().isEmpty()) return;
_touchInProgress = true;
_touchSelectTimer.start(QApplication::startDragTime());
_touchSelect = false;
_touchStart = _touchPrevPos = _touchPos;
break;
_touchInProgress = true;
_touchSelectTimer.start(QApplication::startDragTime());
_touchSelect = false;
_touchStart = _touchPrevPos = _touchPos;
} break;
case QEvent::TouchUpdate:
if (!_touchInProgress) return;
if (_touchSelect) {
_lastMousePos = _touchPos;
dragActionUpdate();
}
break;
case QEvent::TouchUpdate: {
if (!_touchInProgress) return;
if (_touchSelect) {
_lastMousePos = _touchPos;
dragActionUpdate();
}
} break;
case QEvent::TouchEnd:
if (!_touchInProgress) return;
_touchInProgress = false;
if (_touchSelect) {
dragActionFinish(_touchPos, Qt::RightButton);
QContextMenuEvent contextMenu(QContextMenuEvent::Mouse, mapFromGlobal(_touchPos), _touchPos);
showContextMenu(&contextMenu, ContextMenuReason::FromTouch);
} else { // one short tap -- like mouse click
dragActionStart(_touchPos, Qt::LeftButton);
dragActionFinish(_touchPos, Qt::LeftButton);
}
_touchSelectTimer.stop();
_touchSelect = false;
break;
case QEvent::TouchEnd: {
if (!_touchInProgress) return;
_touchInProgress = false;
auto weak = make_weak(this);
if (_touchSelect) {
dragActionFinish(_touchPos, Qt::RightButton);
QContextMenuEvent contextMenu(QContextMenuEvent::Mouse, mapFromGlobal(_touchPos), _touchPos);
showContextMenu(&contextMenu, ContextMenuReason::FromTouch);
} else { // one short tap -- like mouse click
dragActionStart(_touchPos, Qt::LeftButton);
dragActionFinish(_touchPos, Qt::LeftButton);
}
if (weak) {
_touchSelectTimer.stop();
_touchSelect = false;
}
} break;
}
}

View File

@ -526,7 +526,7 @@ void ScrollArea::touchEvent(QTouchEvent *e) {
}
switch (e->type()) {
case QEvent::TouchBegin:
case QEvent::TouchBegin: {
if (_touchPress || e->touchPoints().isEmpty()) return;
_touchPress = true;
if (_touchScrollState == TouchScrollState::Auto) {
@ -541,9 +541,9 @@ void ScrollArea::touchEvent(QTouchEvent *e) {
}
_touchStart = _touchPrevPos = _touchPos;
_touchRightButton = false;
break;
} break;
case QEvent::TouchUpdate:
case QEvent::TouchUpdate: {
if (!_touchPress) return;
if (!_touchScroll && (_touchPos - _touchStart).manhattanLength() >= QApplication::startDragDistance()) {
_touchTimer.stop();
@ -561,11 +561,12 @@ void ScrollArea::touchEvent(QTouchEvent *e) {
}
}
}
break;
} break;
case QEvent::TouchEnd:
case QEvent::TouchEnd: {
if (!_touchPress) return;
_touchPress = false;
auto weak = make_weak(this);
if (_touchScroll) {
if (_touchScrollState == TouchScrollState::Manual) {
_touchScrollState = TouchScrollState::Auto;
@ -584,11 +585,11 @@ void ScrollArea::touchEvent(QTouchEvent *e) {
} else if (window()) { // one short tap -- like left mouse click, one long tap -- like right mouse click
Qt::MouseButton btn(_touchRightButton ? Qt::RightButton : Qt::LeftButton);
sendSynteticMouseEvent(this, QEvent::MouseMove, Qt::NoButton, _touchStart);
sendSynteticMouseEvent(this, QEvent::MouseButtonPress, btn, _touchStart);
sendSynteticMouseEvent(this, QEvent::MouseButtonRelease, btn, _touchStart);
if (weak) sendSynteticMouseEvent(this, QEvent::MouseMove, Qt::NoButton, _touchStart);
if (weak) sendSynteticMouseEvent(this, QEvent::MouseButtonPress, btn, _touchStart);
if (weak) sendSynteticMouseEvent(this, QEvent::MouseButtonRelease, btn, _touchStart);
if (_touchRightButton) {
if (weak && _touchRightButton) {
auto windowHandle = window()->windowHandle();
auto localPoint = windowHandle->mapFromGlobal(_touchStart);
QContextMenuEvent ev(QContextMenuEvent::Mouse, localPoint, _touchStart, QGuiApplication::keyboardModifiers());
@ -596,16 +597,18 @@ void ScrollArea::touchEvent(QTouchEvent *e) {
QGuiApplication::sendEvent(windowHandle, &ev);
}
}
_touchTimer.stop();
_touchRightButton = false;
break;
if (weak) {
_touchTimer.stop();
_touchRightButton = false;
}
} break;
case QEvent::TouchCancel:
case QEvent::TouchCancel: {
_touchPress = false;
_touchScroll = false;
_touchScrollState = TouchScrollState::Manual;
_touchTimer.stop();
break;
} break;
}
}