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
|
\internal
|
||||||
*/
|
*/
|
||||||
QWidget *QApplicationPrivate::pickMouseReceiver(QWidget *candidate, const QPoint &windowPos,
|
QWidget *QApplicationPrivate::pickMouseReceiver(QWidget *candidate, const QPointF &windowPos,
|
||||||
QPoint *pos, QEvent::Type type,
|
QPointF *pos, QEvent::Type type,
|
||||||
Qt::MouseButtons buttons, QWidget *buttonDown,
|
Qt::MouseButtons buttons, QWidget *buttonDown,
|
||||||
QWidget *alienWidget)
|
QWidget *alienWidget)
|
||||||
{
|
{
|
||||||
|
@ -168,7 +168,7 @@ public:
|
|||||||
static QString styleSheet;
|
static QString styleSheet;
|
||||||
#endif
|
#endif
|
||||||
static QPointer<QWidget> leaveAfterRelease;
|
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,
|
QEvent::Type type, Qt::MouseButtons buttons,
|
||||||
QWidget *buttonDown, QWidget *alienWidget);
|
QWidget *buttonDown, QWidget *alienWidget);
|
||||||
static bool sendMouseEvent(QWidget *receiver, QMouseEvent *event, 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
|
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);
|
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())
|
if (children.isEmpty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -10463,7 +10476,7 @@ QWidget *QWidgetPrivate::childAt_helper(const QPoint &p, bool ignoreChildrenInDe
|
|||||||
return childAtRecursiveHelper(p, ignoreChildrenInDestructor);
|
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) {
|
for (int i = children.size() - 1; i >= 0; --i) {
|
||||||
QWidget *child = qobject_cast<QWidget *>(children.at(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.
|
// Map the point 'p' from parent coordinates to child coordinates.
|
||||||
QPoint childPoint = p;
|
QPointF childPoint = p;
|
||||||
childPoint -= child->data->crect.topLeft();
|
childPoint -= child->data->crect.topLeft();
|
||||||
|
|
||||||
// Check if the point hits the child.
|
// Check if the point hits the child.
|
||||||
|
@ -624,6 +624,7 @@ public:
|
|||||||
static QWidget *find(WId);
|
static QWidget *find(WId);
|
||||||
inline QWidget *childAt(int x, int y) const;
|
inline QWidget *childAt(int x, int y) const;
|
||||||
QWidget *childAt(const QPoint &p) const;
|
QWidget *childAt(const QPoint &p) const;
|
||||||
|
QWidget *childAt(const QPointF &p) const;
|
||||||
|
|
||||||
void setAttribute(Qt::WidgetAttribute, bool on = true);
|
void setAttribute(Qt::WidgetAttribute, bool on = true);
|
||||||
inline bool testAttribute(Qt::WidgetAttribute) const;
|
inline bool testAttribute(Qt::WidgetAttribute) const;
|
||||||
@ -796,7 +797,7 @@ template <> inline const QWidget *qobject_cast<const QWidget*>(const QObject *o)
|
|||||||
#endif // !Q_QDOC
|
#endif // !Q_QDOC
|
||||||
|
|
||||||
inline QWidget *QWidget::childAt(int ax, int ay) const
|
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
|
inline Qt::WindowType QWidget::windowType() const
|
||||||
{ return static_cast<Qt::WindowType>((data->window_flags & Qt::WindowType_Mask).toInt()); }
|
{ 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 setMinimumSize_helper(int &minw, int &minh);
|
||||||
bool setMaximumSize_helper(int &maxw, int &maxh);
|
bool setMaximumSize_helper(int &maxw, int &maxh);
|
||||||
void setConstraints_sys();
|
void setConstraints_sys();
|
||||||
bool pointInsideRectAndMask(const QPoint &) const;
|
bool pointInsideRectAndMask(const QPointF &) const;
|
||||||
QWidget *childAt_helper(const QPoint &, bool) const;
|
QWidget *childAt_helper(const QPointF &, bool) const;
|
||||||
QWidget *childAtRecursiveHelper(const QPoint &p, bool) const;
|
QWidget *childAtRecursiveHelper(const QPointF &p, bool) const;
|
||||||
void updateGeometry_helper(bool forceUpdate);
|
void updateGeometry_helper(bool forceUpdate);
|
||||||
|
|
||||||
void getLayoutItemMargins(int *left, int *top, int *right, int *bottom) const;
|
void getLayoutItemMargins(int *left, int *top, int *right, int *bottom) const;
|
||||||
@ -884,11 +884,14 @@ inline void QWidgetPrivate::setSharedPainter(QPainter *painter)
|
|||||||
x->sharedPainter = painter;
|
x->sharedPainter = painter;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool QWidgetPrivate::pointInsideRectAndMask(const QPoint &p) const
|
inline bool QWidgetPrivate::pointInsideRectAndMask(const QPointF &p) const
|
||||||
{
|
{
|
||||||
Q_Q(const QWidget);
|
Q_Q(const QWidget);
|
||||||
return q->rect().contains(p) && (!extra || !extra->hasMask || q->testAttribute(Qt::WA_MouseNoMask)
|
// Use QRectF::contains so that (0, -0.1) isn't in, with p.toPoint() it would be
|
||||||
|| extra->mask.contains(p));
|
// 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
|
inline QWidgetRepaintManager *QWidgetPrivate::maybeRepaintManager() const
|
||||||
|
@ -450,7 +450,7 @@ void QWidgetWindow::handleEnterLeaveEvent(QEvent *event)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const QEnterEvent *ee = static_cast<QEnterEvent *>(event);
|
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 *receiver = child ? child : m_widget.data();
|
||||||
QWidget *leave = nullptr;
|
QWidget *leave = nullptr;
|
||||||
if (QApplicationPrivate::inPopupMode() && receiver == m_widget
|
if (QApplicationPrivate::inPopupMode() && receiver == m_widget
|
||||||
@ -513,7 +513,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
|
|||||||
if (activePopupWidget != m_widget)
|
if (activePopupWidget != m_widget)
|
||||||
mapped = activePopupWidget->mapFromGlobal(event->globalPosition());
|
mapped = activePopupWidget->mapFromGlobal(event->globalPosition());
|
||||||
bool releaseAfter = false;
|
bool releaseAfter = false;
|
||||||
QWidget *popupChild = activePopupWidget->childAt(mapped.toPoint());
|
QWidget *popupChild = activePopupWidget->childAt(mapped);
|
||||||
|
|
||||||
if (activePopupWidget != qt_popup_down) {
|
if (activePopupWidget != qt_popup_down) {
|
||||||
qt_button_down = nullptr;
|
qt_button_down = nullptr;
|
||||||
@ -601,8 +601,8 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// which child should have it?
|
// which child should have it?
|
||||||
QWidget *widget = m_widget->childAt(event->position().toPoint());
|
QWidget *widget = m_widget->childAt(event->position());
|
||||||
QPoint mapped = event->position().toPoint();
|
QPointF mapped = event->position();
|
||||||
|
|
||||||
if (!widget)
|
if (!widget)
|
||||||
widget = m_widget;
|
widget = m_widget;
|
||||||
@ -611,7 +611,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
|
|||||||
if (event->type() == QEvent::MouseButtonPress && initialPress)
|
if (event->type() == QEvent::MouseButtonPress && initialPress)
|
||||||
qt_button_down = widget;
|
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);
|
qt_button_down, widget);
|
||||||
if (!receiver)
|
if (!receiver)
|
||||||
return;
|
return;
|
||||||
@ -637,7 +637,7 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
|
|||||||
if (event->type() == QGuiApplicationPrivate::contextMenuEventType()
|
if (event->type() == QGuiApplicationPrivate::contextMenuEventType()
|
||||||
&& event->button() == Qt::RightButton
|
&& event->button() == Qt::RightButton
|
||||||
&& m_widget->rect().contains(event->position().toPoint())) {
|
&& 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);
|
QGuiApplication::forwardEvent(receiver, &e, event);
|
||||||
if (e.isAccepted())
|
if (e.isAccepted())
|
||||||
event->accept();
|
event->accept();
|
||||||
@ -867,7 +867,7 @@ void QWidgetWindow::handleWheelEvent(QWheelEvent *event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// which child should have it?
|
// which child should have it?
|
||||||
QWidget *widget = rootWidget->childAt(pos.toPoint());
|
QWidget *widget = rootWidget->childAt(pos);
|
||||||
|
|
||||||
if (!widget)
|
if (!widget)
|
||||||
widget = rootWidget;
|
widget = rootWidget;
|
||||||
@ -1076,7 +1076,7 @@ void QWidgetWindow::handleTabletEvent(QTabletEvent *event)
|
|||||||
QWidget *widget = qt_tablet_target;
|
QWidget *widget = qt_tablet_target;
|
||||||
|
|
||||||
if (!widget) {
|
if (!widget) {
|
||||||
widget = m_widget->childAt(event->position().toPoint());
|
widget = m_widget->childAt(event->position());
|
||||||
if (!widget)
|
if (!widget)
|
||||||
widget = m_widget;
|
widget = m_widget;
|
||||||
if (event->type() == QEvent::TabletPress)
|
if (event->type() == QEvent::TabletPress)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user