Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-112970

When the mouse enters the screen, it gets wrong coordinates, on wayland platform

    XMLWordPrintable

Details

    • Linux/Wayland

    Description

       

      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;
          }
      } 

       

       

       

      录屏 2023年04月19日 11时33分31秒.webm

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            srutledg Shawn Rutledge
            nayuta JUNDA DU
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews

                There are no open Gerrit changes