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

2.5k views Asked by At

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.

2

There are 2 answers

0
golwatt On BEST ANSWER

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
0
ecloud On

This is https://bugreports.qt-project.org/browse/QTBUG-36602 and we are planning to have a workaround in Qt 5.4.0. By the time that we did that, it seems that touch_frame is being sent for touch_motion but not for touch_up. (Testing with latest versions of wayland, weston and libinput)