void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent *e)
{
QEvent::Type type = QEvent::None;
Qt::MouseButton button = Qt::NoButton;
QWindow *window = e->window.data();
bool positionChanged = QGuiApplicationPrivate::lastCursorPosition != e->globalPos;
bool mouseMove = false;
bool mousePress = false;
if (e->enhancedMouseEvent()) {
type = e->buttonType;
button = e->button;
if (type == QEvent::NonClientAreaMouseMove || type == QEvent::MouseMove)
mouseMove = true;
else if (type == QEvent::NonClientAreaMouseButtonPress || type == QEvent::MouseButtonPress)
mousePress = true;
if (!mouseMove && positionChanged) {
QWindowSystemInterfacePrivate::MouseEvent moveEvent(window, e->timestamp,
e->localPos, e->globalPos, e->buttons ^ button, e->modifiers, Qt::NoButton,
e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove,
e->source, e->nonClientArea);
if (e->synthetic())
moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
processMouseEvent(&moveEvent); // mouse move excluding state change
processMouseEvent(e); // the original mouse event
return;
}
} else {
Qt::MouseButtons stateChange = e->buttons ^ mouse_buttons;
if (positionChanged && (stateChange != Qt::NoButton)) {
QWindowSystemInterfacePrivate::MouseEvent moveEvent(window, e->timestamp, e->localPos,
e->globalPos, mouse_buttons, e->modifiers, Qt::NoButton, QEvent::None, e->source,
e->nonClientArea);
if (e->synthetic())
moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
processMouseEvent(&moveEvent); // mouse move excluding state change
processMouseEvent(e); // the original mouse event
return;
}
// In the compatibility path we deduce event type and button that caused the event
if (positionChanged) {
mouseMove = true;
type = e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove;
} else {
// Check to see if a new button has been pressed/released.
for (uint mask = Qt::LeftButton; mask <= Qt::MaxMouseButton; mask <<= 1) {
if (stateChange & mask) {
button = Qt::MouseButton(mask);
break;
}
}
if (button == Qt::NoButton) {
// Ignore mouse events that don't change the current state. This shouldn't
// really happen, getting here can only mean that the stored button state
// is out of sync with the actual physical button state.
return;
}
if (button & e->buttons) {
mousePress = true;
type = e->nonClientArea ? QEvent::NonClientAreaMouseButtonPress
: QEvent::MouseButtonPress;
} else {
type = e->nonClientArea ? QEvent::NonClientAreaMouseButtonRelease
: QEvent::MouseButtonRelease;
}
}
}
modifier_buttons = e->modifiers;
QPointF localPoint = e->localPos;
QPointF globalPoint = e->globalPos;
bool doubleClick = false;
if (mouseMove) {
QGuiApplicationPrivate::lastCursorPosition = globalPoint;
const auto doubleClickDistance = e->source == Qt::MouseEventNotSynthesized ?
mouseDoubleClickDistance : touchDoubleTapDistance;
if (qAbs(globalPoint.x() - mousePressX) > doubleClickDistance ||
qAbs(globalPoint.y() - mousePressY) > doubleClickDistance)
mousePressButton = Qt::NoButton;
} else {
mouse_buttons = e->buttons;
if (mousePress) {
ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval());
doubleClick = e->timestamp - mousePressTime < doubleClickInterval && button == mousePressButton;
mousePressTime = e->timestamp;
mousePressButton = button;
const QPoint point = QGuiApplicationPrivate::lastCursorPosition.toPoint();
mousePressX = point.x();
mousePressY = point.y();
}
}
if (e->nullWindow()) {
window = QGuiApplication::topLevelAt(globalPoint.toPoint());
if (window) {
// Moves and the release following a press must go to the same
// window, even if the cursor has moved on over another window.
if (e->buttons != Qt::NoButton) {
if (!currentMousePressWindow)
currentMousePressWindow = window;
else
window = currentMousePressWindow;
} else if (currentMousePressWindow) {
window = currentMousePressWindow;
currentMousePressWindow = 0;
}
QPointF delta = globalPoint - globalPoint.toPoint();
localPoint = window->mapFromGlobal(globalPoint.toPoint()) + delta;
}
}
if (!window)
return;
#ifndef QT_NO_CURSOR
if (!e->synthetic()) {
if (const QScreen *screen = window->screen())
if (QPlatformCursor *cursor = screen->handle()->cursor()) {
const QPointF nativeLocalPoint = QHighDpi::toNativePixels(localPoint, screen);
const QPointF nativeGlobalPoint = QHighDpi::toNativePixels(globalPoint, screen);
QMouseEvent ev(type, nativeLocalPoint, nativeLocalPoint, nativeGlobalPoint,
button, e->buttons, e->modifiers, e->source);
ev.setTimestamp(e->timestamp);
cursor->pointerEvent(ev);
}
}
#endif
QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, e->buttons, e->modifiers, e->source);
ev.setTimestamp(e->timestamp);
if (window->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) {
// a modal window is blocking this window, don't allow mouse events through
return;
}
if (doubleClick && (ev.type() == QEvent::MouseButtonPress)) {
// QtBUG-25831, used to suppress delivery in qwidgetwindow.cpp
setMouseEventFlags(&ev, ev.flags() | Qt::MouseEventCreatedDoubleClick);
}
QGuiApplication::sendSpontaneousEvent(window, &ev);
e->eventAccepted = ev.isAccepted();
if (!e->synthetic() && !ev.isAccepted()
&& !e->nonClientArea
&& qApp->testAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents)) {
if (!m_fakeTouchDevice) {
m_fakeTouchDevice = new QTouchDevice;
QWindowSystemInterface::registerTouchDevice(m_fakeTouchDevice);
}
QList<QWindowSystemInterface::TouchPoint> points;
QWindowSystemInterface::TouchPoint point;
point.id = 1;
point.area = QRectF(globalPoint.x() - 2, globalPoint.y() - 2, 4, 4);
// only translate left button related events to
// avoid strange touch event sequences when several
// buttons are pressed
if (type == QEvent::MouseButtonPress && button == Qt::LeftButton) {
point.state = Qt::TouchPointPressed;
} else if (type == QEvent::MouseButtonRelease && button == Qt::LeftButton) {
point.state = Qt::TouchPointReleased;
} else if (type == QEvent::MouseMove && (e->buttons & Qt::LeftButton)) {
point.state = Qt::TouchPointMoved;
} else {
return;
}
points << point;
QEvent::Type type;
QList<QTouchEvent::TouchPoint> touchPoints =
QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, QTouchDevicePrivate::get(m_fakeTouchDevice)->id, &type);
QWindowSystemInterfacePrivate::TouchEvent fake(window, e->timestamp, type, m_fakeTouchDevice, touchPoints, e->modifiers);
fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
processTouchEvent(&fake);
}
if (doubleClick) {
mousePressButton = Qt::NoButton;
if (!e->window.isNull() || e->nullWindow()) { // QTBUG-36364, check if window closed in response to press
const QEvent::Type doubleClickType = e->nonClientArea ? QEvent::NonClientAreaMouseButtonDblClick : QEvent::MouseButtonDblClick;
QMouseEvent dblClickEvent(doubleClickType, localPoint, localPoint, globalPoint,
button, e->buttons, e->modifiers, e->source);
dblClickEvent.setTimestamp(e->timestamp);
QGuiApplication::sendSpontaneousEvent(window, &dblClickEvent);
}
}
}