-
Bug
-
Resolution: Unresolved
-
P2: Important
-
None
-
5.15.14, 6.5.0
-
None
This bug is like in the attached video,can be reproduced like this
Reproduced
1. Setting a MouseArea in window, and set the cursorShape
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Rectangle{
width: 100
height: 100
color: "red"
MouseArea{
anchors.fill:parent
cursorShape: Qt.BusyCursor
}
}
}
2. Put the mouse in the window before the window starts, when the window opens, the mouse will change to the shape set at (0, 0) coordinates
Analyze
Root case:
The static method QCursor:pos() will read the `mLastPos` in QWaylandCursor. It is only updated when the MouseEvent occurs. When entering for the first time, only enter event, so its value is the default {0,0}. At {0,0}, the mouse is set to a new shape, so it appears made a mistake
Related code:
in qtdeclarative/src/quick/items/qquickwindow.cpp, it use QCursor:pos() to updateCursor
case QEvent::Enter: {
if (!d->contentItem)
return false;
QEnterEvent *enter = static_cast<QEnterEvent*>(e);
bool accepted = enter->isAccepted();
bool delivered = d->deliverHoverEvent(d->contentItem, enter->windowPos(), d->lastMousePosition,
QGuiApplication::keyboardModifiers(), 0L, accepted);
d->lastMousePosition = enter->windowPos();
enter->setAccepted(accepted);
#if QT_CONFIG(cursor)
d->updateCursor(mapFromGlobal(QCursor::pos()));
#endif
return delivered;
final read the property, and it's just be changed in QWaylandCursor::pointerEvent
QPoint QWaylandCursor::pos() const { return mLastPos; } void QWaylandCursor::pointerEvent(const QMouseEvent &event) { mLastPos = event.globalPos(); }
And the pointerEvent is only called in MouseEvent `cursor->pointerEvent(ev)`
void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent *e){
````````
#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
``````
Due to the fact that the enter event does not trigger a MouseEvent, it will not be called here. The issue is caused by the default value of mLastPos being {0,0}.
I attempted to solve the issue by handling the MouseEvent in advance in the enter event of QtWayland, but I am not sure if this is a reasonable approach.
void QWaylandWindow::handleMouse(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e) { if (mWindowDecoration) { handleMouseEventWithDecoration(inputDevice, e); } else { switch (e.type) { case QEvent::Enter: // ADD QWindowSystemInterface::handleMouseEvent(window(), e.timestamp, e.local, e.global, e.buttons, e.button, e.type, e.modifiers); QWindowSystemInterface::handleEnterEvent(window(), e.local, e.global); break;
By the way, this issue was not reproduced on x11 because they retrieve the position of the coordinates in real time.
// qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp QPoint QXcbCursor::pos() const { QPoint p; queryPointer(connection(), nullptr, &p); return p; } void QXcbCursor::queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask) { if (pos) *pos = QPoint(); xcb_window_t root = c->primaryVirtualDesktop()->root(); auto reply = Q_XCB_REPLY(xcb_query_pointer, c->xcb_connection(), root); if (reply) { if (virtualDesktop) { const auto virtualDesktops = c->virtualDesktops(); for (QXcbVirtualDesktop *vd : virtualDesktops) { if (vd->root() == reply->root) { *virtualDesktop = vd; break; } } } if (pos) *pos = QPoint(reply->root_x, reply->root_y); if (keybMask) *keybMask = reply->mask; return; } }