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 Change-Id: I76d4b711a8297648780bdd079eb67405ab12be14 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> (cherry picked from commit 40bde8a572bd8ed039d3f5a5ab99b281de7410bd) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
5ebab802cc
commit
cd528d81f7
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -10449,11 +10449,24 @@ 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;
|
||||
@ -10463,7 +10476,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));
|
||||
@ -10473,7 +10486,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.
|
||||
|
@ -624,6 +624,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;
|
||||
@ -796,7 +797,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()); }
|
||||
|
@ -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;
|
||||
@ -884,11 +884,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
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user