diff options
author | David Faure <[email protected]> | 2024-08-27 19:41:53 +0200 |
---|---|---|
committer | David Faure <[email protected]> | 2024-08-30 18:39:36 +0200 |
commit | 40bde8a572bd8ed039d3f5a5ab99b281de7410bd (patch) | |
tree | d40d767b6238bfa36f2062dd283d2a7980729a8a | |
parent | 2a10a679a17de2f2ec83f676198936fcaaaa8fad (diff) |
QWidgetWindow: fix enter/leave events not sent due to fractional scaling
If widget A starts at y=0 and widget B starts at y=19, when the mouse
moves from y=15 to y=18.6667, the code was doing childAt(p) with a
rounded QPoint y=19 and finding B, but then the relative coord for B
was set to -0.33333 so B wasn't under the mouse and didn't get an enter
event (and since it's now the "last receiver", it doesn't get one later
either when y is bigger).
Add QWidget::childAt(QPointF) to fix this.
Fixes: QTBUG-128391
Pick-to: 6.8
Change-Id: I76d4b711a8297648780bdd079eb67405ab12be14
Reviewed-by: Volker Hilsheimer <[email protected]>
-rw-r--r-- | src/widgets/kernel/qapplication.cpp | 4 | ||||
-rw-r--r-- | src/widgets/kernel/qapplication_p.h | 2 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget.cpp | 19 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget.h | 3 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget_p.h | 15 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetwindow.cpp | 16 |
6 files changed, 38 insertions, 21 deletions
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 5e1d7923197..89d451589a8 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -2253,8 +2253,8 @@ bool QApplicationPrivate::modalState() /* \internal */ -QWidget *QApplicationPrivate::pickMouseReceiver(QWidget *candidate, const QPoint &windowPos, - QPoint *pos, QEvent::Type type, +QWidget *QApplicationPrivate::pickMouseReceiver(QWidget *candidate, const QPointF &windowPos, + QPointF *pos, QEvent::Type type, Qt::MouseButtons buttons, QWidget *buttonDown, QWidget *alienWidget) { diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h index 7de9f54b587..5f1d4ef13c3 100644 --- a/src/widgets/kernel/qapplication_p.h +++ b/src/widgets/kernel/qapplication_p.h @@ -168,7 +168,7 @@ public: static QString styleSheet; #endif static QPointer<QWidget> leaveAfterRelease; - static QWidget *pickMouseReceiver(QWidget *candidate, const QPoint &windowPos, QPoint *pos, + static QWidget *pickMouseReceiver(QWidget *candidate, const QPointF &windowPos, QPointF *pos, QEvent::Type type, Qt::MouseButtons buttons, QWidget *buttonDown, QWidget *alienWidget); static bool sendMouseEvent(QWidget *receiver, QMouseEvent *event, QWidget *alienWidget, diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 8b9513e2dd3..dcf53f0e84d 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -10453,10 +10453,23 @@ bool QWidget::hasHeightForWidth() const QWidget *QWidget::childAt(const QPoint &p) const { + return d_func()->childAt_helper(QPointF(p), false); +} + +/*! + \overload + \since 6.8 + + Returns the visible child widget at point \a p in the widget's own + coordinate system. +*/ + +QWidget *QWidget::childAt(const QPointF &p) const +{ return d_func()->childAt_helper(p, false); } -QWidget *QWidgetPrivate::childAt_helper(const QPoint &p, bool ignoreChildrenInDestructor) const +QWidget *QWidgetPrivate::childAt_helper(const QPointF &p, bool ignoreChildrenInDestructor) const { if (children.isEmpty()) return nullptr; @@ -10466,7 +10479,7 @@ QWidget *QWidgetPrivate::childAt_helper(const QPoint &p, bool ignoreChildrenInDe return childAtRecursiveHelper(p, ignoreChildrenInDestructor); } -QWidget *QWidgetPrivate::childAtRecursiveHelper(const QPoint &p, bool ignoreChildrenInDestructor) const +QWidget *QWidgetPrivate::childAtRecursiveHelper(const QPointF &p, bool ignoreChildrenInDestructor) const { for (int i = children.size() - 1; i >= 0; --i) { QWidget *child = qobject_cast<QWidget *>(children.at(i)); @@ -10476,7 +10489,7 @@ QWidget *QWidgetPrivate::childAtRecursiveHelper(const QPoint &p, bool ignoreChil } // Map the point 'p' from parent coordinates to child coordinates. - QPoint childPoint = p; + QPointF childPoint = p; childPoint -= child->data->crect.topLeft(); // Check if the point hits the child. diff --git a/src/widgets/kernel/qwidget.h b/src/widgets/kernel/qwidget.h index 7ee4412d881..faf2b31a832 100644 --- a/src/widgets/kernel/qwidget.h +++ b/src/widgets/kernel/qwidget.h @@ -627,6 +627,7 @@ public: static QWidget *find(WId); inline QWidget *childAt(int x, int y) const; QWidget *childAt(const QPoint &p) const; + QWidget *childAt(const QPointF &p) const; void setAttribute(Qt::WidgetAttribute, bool on = true); inline bool testAttribute(Qt::WidgetAttribute) const; @@ -799,7 +800,7 @@ template <> inline const QWidget *qobject_cast<const QWidget*>(const QObject *o) #endif // !Q_QDOC inline QWidget *QWidget::childAt(int ax, int ay) const -{ return childAt(QPoint(ax, ay)); } +{ return childAt(QPointF(ax, ay)); } inline Qt::WindowType QWidget::windowType() const { return static_cast<Qt::WindowType>((data->window_flags & Qt::WindowType_Mask).toInt()); } diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index 7394bcdbbf8..f8ac13ebb74 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -420,9 +420,9 @@ public: bool setMinimumSize_helper(int &minw, int &minh); bool setMaximumSize_helper(int &maxw, int &maxh); void setConstraints_sys(); - bool pointInsideRectAndMask(const QPoint &) const; - QWidget *childAt_helper(const QPoint &, bool) const; - QWidget *childAtRecursiveHelper(const QPoint &p, bool) const; + bool pointInsideRectAndMask(const QPointF &) const; + QWidget *childAt_helper(const QPointF &, bool) const; + QWidget *childAtRecursiveHelper(const QPointF &p, bool) const; void updateGeometry_helper(bool forceUpdate); void getLayoutItemMargins(int *left, int *top, int *right, int *bottom) const; @@ -885,11 +885,14 @@ inline void QWidgetPrivate::setSharedPainter(QPainter *painter) x->sharedPainter = painter; } -inline bool QWidgetPrivate::pointInsideRectAndMask(const QPoint &p) const +inline bool QWidgetPrivate::pointInsideRectAndMask(const QPointF &p) const { Q_Q(const QWidget); - return q->rect().contains(p) && (!extra || !extra->hasMask || q->testAttribute(Qt::WA_MouseNoMask) - || extra->mask.contains(p)); + // Use QRectF::contains so that (0, -0.1) isn't in, with p.toPoint() it would be + // The adjusted matches QRect semantics: (160,160) isn't contained in QRect(0, 0, 160, 160) + return QRectF(q->rect().adjusted(0, 0, -1, -1)).contains(p) + && (!extra || !extra->hasMask || q->testAttribute(Qt::WA_MouseNoMask) + || extra->mask.contains(p.toPoint() /* incorrect for the -0.1 case */)); } inline QWidgetRepaintManager *QWidgetPrivate::maybeRepaintManager() const diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 46871d0da16..e2f1776780d 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -450,7 +450,7 @@ void QWidgetWindow::handleEnterLeaveEvent(QEvent *event) } } else { const QEnterEvent *ee = static_cast<QEnterEvent *>(event); - QWidget *child = m_widget->childAt(ee->position().toPoint()); + QWidget *child = m_widget->childAt(ee->position()); QWidget *receiver = child ? child : m_widget.data(); QWidget *leave = nullptr; if (QApplicationPrivate::inPopupMode() && receiver == m_widget @@ -513,7 +513,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) if (activePopupWidget != m_widget) mapped = activePopupWidget->mapFromGlobal(event->globalPosition()); bool releaseAfter = false; - QWidget *popupChild = activePopupWidget->childAt(mapped.toPoint()); + QWidget *popupChild = activePopupWidget->childAt(mapped); if (activePopupWidget != qt_popup_down) { qt_button_down = nullptr; @@ -601,8 +601,8 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) return; // which child should have it? - QWidget *widget = m_widget->childAt(event->position().toPoint()); - QPoint mapped = event->position().toPoint(); + QWidget *widget = m_widget->childAt(event->position()); + QPointF mapped = event->position(); if (!widget) widget = m_widget; @@ -611,7 +611,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) if (event->type() == QEvent::MouseButtonPress && initialPress) qt_button_down = widget; - QWidget *receiver = QApplicationPrivate::pickMouseReceiver(m_widget, event->scenePosition().toPoint(), &mapped, event->type(), event->buttons(), + QWidget *receiver = QApplicationPrivate::pickMouseReceiver(m_widget, event->scenePosition(), &mapped, event->type(), event->buttons(), qt_button_down, widget); if (!receiver) return; @@ -637,7 +637,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) if (event->type() == QGuiApplicationPrivate::contextMenuEventType() && event->button() == Qt::RightButton && m_widget->rect().contains(event->position().toPoint())) { - QContextMenuEvent e(QContextMenuEvent::Mouse, mapped, event->globalPosition().toPoint(), event->modifiers()); + QContextMenuEvent e(QContextMenuEvent::Mouse, mapped.toPoint(), event->globalPosition().toPoint(), event->modifiers()); QGuiApplication::forwardEvent(receiver, &e, event); if (e.isAccepted()) event->accept(); @@ -867,7 +867,7 @@ void QWidgetWindow::handleWheelEvent(QWheelEvent *event) } // which child should have it? - QWidget *widget = rootWidget->childAt(pos.toPoint()); + QWidget *widget = rootWidget->childAt(pos); if (!widget) widget = rootWidget; @@ -1076,7 +1076,7 @@ void QWidgetWindow::handleTabletEvent(QTabletEvent *event) QWidget *widget = qt_tablet_target; if (!widget) { - widget = m_widget->childAt(event->position().toPoint()); + widget = m_widget->childAt(event->position()); if (!widget) widget = m_widget; if (event->type() == QEvent::TabletPress) |