Search code examples
eventstouchqt5waylandqtwayland

Touch doesnt work with Qt5.1.1 when used with Wayland & qtwayland


I want to make Qt 5.1.1 touch example application work with qtwayland module.

I get the window on display, and also I get the touch traces from Weston. I see qtwayland is also getting triggered with the callback function that is registered for touch-up, touch-down, touch-motion.

But, QT doesn't invoke the QPushButton handler in QT application.

Connect API I am using as below: connect(ui->b_audio, SIGNAL(pressed()), this, SLOT(on_b_audio_clicked()));

Any clue why this could happen? Please suggest probable problems so that I can explore and debug.

Thanks in Advance. Bhushan.


Solution

  • In QtWayland, QWaylandInputDevice::touch_frame() passes the touch points to Qt internal window system through QWindowSystemInterface::handleTouchEvent(). Weston does not send WL_TOUCH_FRAME event at all, so the buttons or the QML MouseArea never receive touch event. You can add the following line to the end of evdev_flush_motion() in weston/src/evdev.c:

    notify_touch(master, time, 0, 0, 0, WL_TOUCH_FRAME);
    

    And rewrite the notify_touch() in weston/src/input.c:

    WL_EXPORT void
    notify_touch(struct weston_seat *seat, uint32_t time, int touch_id,
             wl_fixed_t x, wl_fixed_t y, int touch_type)
    {
      struct weston_compositor *ec = seat->compositor;
      struct weston_touch *touch = seat->touch;
      struct weston_touch_grab *grab = touch->grab;
      struct weston_surface *es;
      wl_fixed_t sx, sy;
      struct weston_touch *grab_touch = grab->touch;
    
      /* Update grab's global coordinates. */
      touch->grab_x = x;
      touch->grab_y = y;
    
      switch (touch_type) {
      case WL_TOUCH_DOWN:
        weston_compositor_idle_inhibit(ec);
    
        seat->num_tp++;
    
        /* the first finger down picks the surface, and all further go
         * to that surface for the remainder of the touch session i.e.
         * until all touch points are up again. */
        if (seat->num_tp == 1) {
          es = weston_compositor_pick_surface(ec, x, y, &sx, &sy);
          weston_touch_set_focus(seat, es);
        } else if (touch->focus) {
          es = (struct weston_surface *) touch->focus;
          weston_surface_from_global_fixed(es, x, y, &sx, &sy);
        } else {
          /* Unexpected condition: We have non-initial touch but
           * there is no focused surface.
           */
          weston_log("touch event received with %d points down"
               "but no surface focused\n", seat->num_tp);
          return;
        }
    
        grab->interface->down(grab, time, touch_id, sx, sy);
        if (seat->num_tp == 1) {
          touch->grab_serial =
            wl_display_get_serial(ec->wl_display);
          touch->grab_time = time;
          touch->grab_x = x;
          touch->grab_y = y;
        }
    
        break;
      case WL_TOUCH_MOTION:
        es = (struct weston_surface *) touch->focus;
        if (!es)
          break;
    
        weston_surface_from_global_fixed(es, x, y, &sx, &sy);
        grab->interface->motion(grab, time, touch_id, sx, sy);
        break;
      case WL_TOUCH_UP:
        weston_compositor_idle_release(ec);
        seat->num_tp--;
        grab->interface->up(grab, time, touch_id);
        break;
      case WL_TOUCH_FRAME:
        if (grab_touch->focus_resource) {
          wl_touch_send_frame(grab_touch->focus_resource);
          if (seat->num_tp == 0)
            weston_touch_set_focus(seat, NULL);
        }
      }
    }
    

    Meanwhile, I find that weston does not handle multi-touch properly because its mt structure (below) uses an int value 'slot' which can only track the current slot number.

    struct {
      int slot;
      int32_t x[MAX_SLOTS];
      int32_t y[MAX_SLOTS];
    } mt;
    

    In multi-touch protocol type B, each slot associates with a finger contact and you get multiple slot events in a touch frame, for example, a touch_down frame;

    ABS_MT_SLOT
    ABS_MT_TRACKING_ID
    ABS_MT_POSITION_X
    ABS_MT_POSITION_Y
    ABS_MT_SLOT
    ABS_MT_TRACKING_ID
    ABS_MT_POSITION_X
    ABS_MT_POSITION_Y
    EV_SYN
    

    weston handles events from first slot event to the EV_SYN event, and it call notify_touch() if EV_SYN is encountered. Therefore, weston cannot send the two touch down events sequentially via notify_touch() with different slot number parameter.

    In my reimplementation, I change the mt structure:

    struct {
      int current_slot;
      uint32_t num_down_event;
      uint32_t num_motion_event;
      uint32_t num_up_event;
      int slots[MAX_CONTACTS];
      int32_t x[MAX_SLOTS];
      int32_t y[MAX_SLOTS];
    } mt;
    
    • num_down_event: track how many fingers touch down
    • num_motion_event: track how many fingers move
    • num_up_event: track how many fingers lift up
    • slots: track slot numbers in every touch frame