Skip to content

GitLab

  • Menu
Projects Groups Snippets
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • gtk gtk
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 1,468
    • Issues 1,468
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 247
    • Merge requests 247
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Monitor
    • Monitor
    • Incidents
  • Packages & Registries
    • Packages & Registries
    • Container Registry
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • GNOME
  • gtkgtk
  • Issues
  • #4809

Closed
Open
Created Apr 01, 2022 by hemidark@hemidarkContributor

gdk_motion_event_push_history discards position information for some devices

Summary

gdk_motion_event_push_history silently discards position data for certain extended input devices.

Event history relies on the GdkTimeCoord structure, but this structure stores the axes and not the event position. For devices which do not populate X and Y axis data, the position information from the original event is lost.

When this happens, it makes the event history obtained via gdk_event_get_history or gtk_gesture_stylus_get_backlog completely unusable.

Steps to reproduce

  1. Find an extended input device that doesn't report X and Y position as axes (e.g. Wacom Intuos 4 on Linux)
  2. Run the attached demo program from the console example.c
  3. Scribble on the window with the stylus
  4. Note the console messages about missing X and Y position information, for example:
BUG: event[6]/backlog[0] has no XY position (GdkTimeCoord::flags = 000002e0)

Motion events received: 6
Backlog events received: 4
Backlog events missing XY position: 4

Current behavior

For such devices, GdkEvent::history does not contain any X or Y position information, making the backlog unusable for most purposes.

Expected outcome

X and Y position should always be recorded in GdkTimeCoord using GDK_AXIS_X and GDK_AXIS_Y (and GdkTimeCoord::flags should reflect this), even if the underlying device does not report X and Y as axes itself.

Version information

GTK 4.4.0 Distributor ID: Ubuntu Description: Ubuntu 21.10 Release: 21.10 Codename: impish

Additional information

One the face of it, the existing behavior is correct, in that the GDK API does not promise that X and Y position will be available as axes; users of the API are cautioned not to rely on it. This is reflected in gdkenums.h:

/**
 * GdkAxisUse:
 * ...
 *
 * Note that the X and Y axes are not really needed; pointer devices
 * report their location via the x/y members of events regardless. Whether
 * X and Y are present as axes depends on the GDK backend.
 */

However, in the case of GdkTimeCoord, there's nowhere else to record the X and Y position!

In fact, for plain input devices, synthetic X and Y axis data is already populated (from gdkevents.c):

if (tool)
    {
      hist.flags = gdk_device_tool_get_axes (tool);
      for (i = GDK_AXIS_X; i < GDK_AXIS_LAST; i++)
        gdk_event_get_axis (history_event, i, &hist.axes[i]);
    }
  else
    {
      hist.flags = GDK_AXIS_FLAG_X | GDK_AXIS_FLAG_Y;
      gdk_event_get_position (history_event, &hist.axes[GDK_AXIS_X], &hist.axes[GDK_AXIS_Y]);
    }

It would be simple to unconditionally populate the X and Y axes:

hist.flags = GDK_AXIS_FLAG_X | GDK_AXIS_FLAG_Y;
if (tool)
  {
    hist.flags |= gdk_device_tool_get_axes (tool);
    for (i = GDK_AXIS_X; i < GDK_AXIS_LAST; i++)
      gdk_event_get_axis (history_event, i, &hist.axes[i]);
  }
gdk_event_get_position (history_event, &hist.axes[GDK_AXIS_X], &hist.axes[GDK_AXIS_Y]);

Or, a more conservative approach would be to only add synthetic X and Y axes when they are missing:

hist.flags = 0;

if (tool)
  {
    hist.flags |= gdk_device_tool_get_axes (tool);
    for (i = GDK_AXIS_X; i < GDK_AXIS_LAST; i++)
      gdk_event_get_axis (history_event, i, &hist.axes[i]);
  }

if (!(hist.flags & (GDK_AXIS_FLAG_X | GDK_AXIS_FLAG_Y)))
  {
    hist.flags |= GDK_AXIS_FLAG_X | GDK_AXIS_FLAG_Y;
    gdk_event_get_position (history_event, &hist.axes[GDK_AXIS_X], &hist.axes[GDK_AXIS_Y]);
  }

This would still cover both cases:

  • extended input devices which don't provide XY axis data
  • devices which don't support extended input at all
Edited Apr 01, 2022 by hemidark
Assignee
Assign to
Time tracking