emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 9ad601e7d76: Expose the ``cancellation'' of touch events to Lisp


From: Po Lu
Subject: master 9ad601e7d76: Expose the ``cancellation'' of touch events to Lisp
Date: Mon, 17 Jul 2023 21:28:30 -0400 (EDT)

branch: master
commit 9ad601e7d762f47d3469692b8135cc72b8301365
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Expose the ``cancellation'' of touch events to Lisp
    
    * doc/lispref/commands.texi (Touchscreen Events):
    * etc/NEWS: Describe new event parameter `canceled'.
    * src/keyboard.c (make_lispy_event) <TOUCHSCREEN_END_EVENT>:
    If event->modifiers, set canceled to t.
    
    * src/termhooks.h (enum event_kind): Describe meaning of
    modifiers in TOUCHSCREEN_END_EVENTs.
    * src/xfns.c (setup_xi_event_mask): Select for
    XI_TouchOwnership.
    * src/xterm.c (xi_link_touch_point): Round X and Y and clear
    ownership.
    (xi_unlink_touch_point): Return 1 if the touch point is not
    owned by Emacs, 2 otherwise.
    (handle_one_xevent): Handle XI_TouchOwnership events and report
    ownership correctly.
    * src/xterm.h (enum xi_touch_ownership): New enum.  Write
    commentary on XI touch sequence ownership.
    (struct xi_touch_point_t): Use integer X and Y.  New field
    `ownership'.  Adjust for alignment.
---
 doc/lispref/commands.texi |  7 +++-
 etc/NEWS                  |  6 ++++
 src/keyboard.c            | 20 ++++++++++-
 src/termhooks.h           |  6 +++-
 src/xfns.c                |  1 +
 src/xterm.c               | 92 ++++++++++++++++++++++++++++++++++++++---------
 src/xterm.h               | 62 +++++++++++++++++++++++++++++---
 7 files changed, 169 insertions(+), 25 deletions(-)

diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
index cd1745614eb..037f42124cc 100644
--- a/doc/lispref/commands.texi
+++ b/doc/lispref/commands.texi
@@ -2018,10 +2018,15 @@ position.  @var{points} is a list of touch points 
containing the
 up-to-date positions of each touch point currently on the touchscreen.
 
 @cindex @code{touchscreen-end} event
-@item (touchscreen-end @var{point})
+@item (touchscreen-end @var{point} @var{canceled})
 This event is sent when @var{point} is no longer present on the
 display, because another program took the grab, or because the user
 raised the finger from the touchscreen.
+
+@var{canceled} is non-@code{nil} if the touch sequence has been
+intercepted by another program (such as the window manager), and Emacs
+should undo or avoid any editing commands that would otherwise result
+from the touch sequence.
 @end table
 
 @node Focus Events
diff --git a/etc/NEWS b/etc/NEWS
index 3cfc36e10da..c50f560282a 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -615,6 +615,12 @@ provokes an error if used numerically.
 This user option names directories in which Emacs will treat all
 directory-local variables as safe.
 
++++
+** New parameter to 'touchscreen-end' events.
+CANCEL non-nil establishes that the touch sequence has been
+intercepted by programs such as window managers and should be ignored
+with Emacs.
+
 ** New variable 'inhibit-auto-fill' to temporarily prevent auto-fill.
 
 ** Functions and variables to transpose sexps
diff --git a/src/keyboard.c b/src/keyboard.c
index b61b1766856..41cda2e65de 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -6404,7 +6404,6 @@ make_lispy_event (struct input_event *event)
       }
 
     case TOUCHSCREEN_BEGIN_EVENT:
-    case TOUCHSCREEN_END_EVENT:
       {
        Lisp_Object x, y, id, position;
        struct frame *f = XFRAME (event->frame_or_window);
@@ -6422,6 +6421,25 @@ make_lispy_event (struct input_event *event)
                      Fcons (id, position));
       }
 
+    case TOUCHSCREEN_END_EVENT:
+      {
+       Lisp_Object x, y, id, position;
+       struct frame *f = XFRAME (event->frame_or_window);
+
+       id = event->arg;
+       x = event->x;
+       y = event->y;
+
+       position = make_lispy_position (f, x, y, event->timestamp);
+
+       return list3 (((event->kind
+                       == TOUCHSCREEN_BEGIN_EVENT)
+                      ? Qtouchscreen_begin
+                      : Qtouchscreen_end),
+                     Fcons (id, position),
+                     event->modifiers ? Qt : Qnil);
+      }
+
     case PINCH_EVENT:
       {
        Lisp_Object x, y, position;
diff --git a/src/termhooks.h b/src/termhooks.h
index ba04a6b7759..c8345c2715f 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -307,7 +307,11 @@ enum event_kind
 
      In TOUCHSCREEN_BEGIN_EVENT and TOUCHSCREEN_END_EVENT, ARG is the
      unique ID of the touchpoint, and X and Y are the frame-relative
-     positions of the touchpoint.  */
+     positions of the touchpoint.
+
+     In TOUCHSCREEN_END_EVENT, non-0 modifiers means that the
+     touchpoint has been canceled.  (See (elisp)Touchscreen
+     Events.)  */
 
   , TOUCHSCREEN_UPDATE_EVENT
   , TOUCHSCREEN_BEGIN_EVENT
diff --git a/src/xfns.c b/src/xfns.c
index fd4807fd5f5..55bcfb8e20e 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -4107,6 +4107,7 @@ setup_xi_event_mask (struct frame *f)
       XISetMask (m, XI_TouchBegin);
       XISetMask (m, XI_TouchUpdate);
       XISetMask (m, XI_TouchEnd);
+      XISetMask (m, XI_TouchOwnership);
 
 #if defined HAVE_XINPUT2_4 && defined USE_GTK3
       if (FRAME_DISPLAY_INFO (f)->xi2_version >= 4)
diff --git a/src/xterm.c b/src/xterm.c
index 5cc2dfdae1d..130a2c93b64 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -5742,6 +5742,10 @@ xi_device_from_id (struct x_display_info *dpyinfo, int 
deviceid)
 
 #ifdef HAVE_XINPUT2_2
 
+/* Record a touch sequence with the identifier DETAIL from the given
+   FRAME on the specified DEVICE.  Round X and Y and record them as
+   its current position.  */
+
 static void
 xi_link_touch_point (struct xi_device_t *device,
                     int detail, double x, double y,
@@ -5751,19 +5755,28 @@ xi_link_touch_point (struct xi_device_t *device,
 
   touchpoint = xmalloc (sizeof *touchpoint);
   touchpoint->next = device->touchpoints;
-  touchpoint->x = x;
-  touchpoint->y = y;
+  touchpoint->x = lrint (x);
+  touchpoint->y = lrint (y);
   touchpoint->number = detail;
   touchpoint->frame = frame;
+  touchpoint->ownership = TOUCH_OWNERSHIP_NONE;
 
   device->touchpoints = touchpoint;
 }
 
-static bool
-xi_unlink_touch_point (int detail,
-                      struct xi_device_t *device)
+/* Free and remove the touch sequence with the identifier DETAIL.
+   DEVICE is the device in which the touch sequence should be
+   recorded.
+
+   Value is 0 if no touch sequence by that identifier exists inside
+   DEVICE, 1 if a touch sequence has been found but is not owned by
+   Emacs, and 2 otherwise.  */
+
+static int
+xi_unlink_touch_point (int detail, struct xi_device_t *device)
 {
   struct xi_touch_point_t *last, *tem;
+  enum xi_touch_ownership ownership;
 
   for (last = NULL, tem = device->touchpoints; tem;
        last = tem, tem = tem->next)
@@ -5775,12 +5788,17 @@ xi_unlink_touch_point (int detail,
          else
            last->next = tem->next;
 
+         ownership = tem->ownership;
          xfree (tem);
-         return true;
+
+         if (ownership == TOUCH_OWNERSHIP_SELF)
+           return 2;
+
+         return 1;
        }
     }
 
-  return false;
+  return 0;
 }
 
 /* Unlink all touch points associated with the frame F.
@@ -5813,6 +5831,10 @@ xi_unlink_touch_points (struct frame *f)
     }
 }
 
+/* Return the data associated with a touch sequence DETAIL recorded by
+   `xi_link_touch_point' from DEVICE, or NULL if it can't be
+   found.  */
+
 static struct xi_touch_point_t *
 xi_find_touch_point (struct xi_device_t *device, int detail)
 {
@@ -24422,12 +24444,48 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              goto XI_OTHER;
            }
 
+         case XI_TouchOwnership:
+           {
+             struct xi_device_t *device;
+             struct xi_touch_point_t *touchpoint;
+             XITouchOwnershipEvent *event;
+
+             /* All grabbing clients have decided to reject ownership
+                of this touch sequence.  */
+
+             event  = (XITouchOwnershipEvent *) xi_event;
+             device = xi_device_from_id (dpyinfo, event->deviceid);
+
+             if (!device || device->use == XIMasterPointer)
+               goto XI_OTHER;
+
+             touchpoint = xi_find_touch_point (device, event->touchid);
+
+             if (!touchpoint)
+               goto XI_OTHER;
+
+             /* As a result, Emacs should complete whatever editing
+                operations result from this touch sequence.  */
+             touchpoint->ownership = TOUCH_OWNERSHIP_SELF;
+           }
+
          case XI_TouchUpdate:
            {
              struct xi_device_t *device, *source;
              struct xi_touch_point_t *touchpoint;
              Lisp_Object arg = Qnil;
 
+             /* If flags & TouchPendingEnd, the touch sequence has
+                already ended, but some grabbing clients remain
+                undecided as to whether they will obtain ownership of
+                the touch sequence.
+
+                Wait for them to make their decision, resulting in
+                TouchOwnership and TouchEnd events being sent.  */
+
+             if (xev->flags & XITouchPendingEnd)
+               goto XI_OTHER;
+
              device = xi_device_from_id (dpyinfo, xev->deviceid);
              source = xi_device_from_id (dpyinfo, xev->sourceid);
              x_display_set_last_user_time (dpyinfo, xev->time,
@@ -24439,7 +24497,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                 detached, and master pointers may also represent
                 dependent touch devices.  */
 
-             if (!device)
+             if (!device || device->use == XIMasterPointer)
                goto XI_OTHER;
 
              touchpoint = xi_find_touch_point (device, xev->detail);
@@ -24447,12 +24505,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              if (!touchpoint
                  /* Don't send this event if nothing has changed
                     either.  */
-                 || (touchpoint->x == (int) xev->event_x
-                     && touchpoint->y == (int) xev->event_y))
+                 || (touchpoint->x == lrint (xev->event_x)
+                     && touchpoint->y == lrint (xev->event_y)))
                goto XI_OTHER;
 
-             touchpoint->x = xev->event_x;
-             touchpoint->y = xev->event_y;
+             touchpoint->x = lrint (xev->event_x);
+             touchpoint->y = lrint (xev->event_y);
 
              f = x_window_to_frame (dpyinfo, xev->event);
 
@@ -24466,8 +24524,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                       touchpoint; touchpoint = touchpoint->next)
                    {
                      if (touchpoint->frame == f)
-                       arg = Fcons (list3i (lrint (touchpoint->x),
-                                            lrint (touchpoint->y),
+                       arg = Fcons (list3i (touchpoint->x, touchpoint->y,
                                             lrint (touchpoint->number)),
                                     arg);
                    }
@@ -24484,7 +24541,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
          case XI_TouchEnd:
            {
              struct xi_device_t *device, *source;
-             bool unlinked_p;
+             int state;
 
              device = xi_device_from_id (dpyinfo, xev->deviceid);
              source = xi_device_from_id (dpyinfo, xev->sourceid);
@@ -24500,9 +24557,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              if (!device || device->use == XIMasterPointer)
                goto XI_OTHER;
 
-             unlinked_p = xi_unlink_touch_point (xev->detail, device);
+             state = xi_unlink_touch_point (xev->detail, device);
 
-             if (unlinked_p)
+             if (state)
                {
                  f = x_window_to_frame (dpyinfo, xev->event);
 
@@ -24510,6 +24567,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                    {
                      inev.ie.kind = TOUCHSCREEN_END_EVENT;
                      inev.ie.timestamp = xev->time;
+                     inev.ie.modifiers = state != 2;
 
                      XSETFRAME (inev.ie.frame_or_window, f);
                      XSETINT (inev.ie.x, lrint (xev->event_x));
diff --git a/src/xterm.h b/src/xterm.h
index 34a713ea2ca..c7db54e2bcf 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -255,19 +255,71 @@ struct xi_scroll_valuator_t
 
 #ifdef HAVE_XINPUT2_2
 
+/* Enum describing the ownership of a touch point.
+
+   The input extension allows other clients to intercept touch
+   sequences destined for a client window through passively grabbing
+   for touch events on a parent window.
+
+   When a passive touch grab for an XI_TouchBegin event activates, one
+   grabbing client is designated the ``owner'' of the touch sequence
+   started by the grabbed event.  Touch events are then delivered to
+   both the grabbing client and other clients that have selected for
+   touch events on the subwindow.
+
+   The X server will not deliver TouchEnd events to clients other than
+   the owner until one grabbing client decides to take over processing
+   the touch event sequence, or no more grabbing clients remain.
+   Instead, a TouchUpdate event with the TouchPendingEnd flag is sent,
+   and the TouchEnd event is postponed until the decision is made and
+   all XI_TouchOwnership events are sent.
+
+   If the owner decides to take over processing the touch sequence, an
+   XI_TouchEnd event is delivered to all other clients receiving
+   events for the current touch sequence, who are then expected to
+   cancel or undo any actions which have taken place in reaction to
+   events from that sequence.
+
+   If the owner decides to relinquish ownership over the touch
+   sequence, the X server looks for another grabbing client, and
+   transfers touch ownership to that client instead.  Nothing changes
+   from the perspective of clients who have merely selected for events
+   from the subwindow, while an XI_TouchEnd event is delivered to the
+   old owner, and an XI_TouchOwnership event is delivered to the new
+   owner.
+
+   If all grabbing clients reject ownership over the touch sequence,
+   the X server delivers an XI_TouchOwnership event to the client that
+   has selected for touch events on the subwindow, the only client
+   that will receive events for this touch sequence from this time
+   forward.  */
+
+enum xi_touch_ownership
+  {
+    /* Emacs doesn't own this touch sequence.  */
+    TOUCH_OWNERSHIP_NONE,
+
+    /* Emacs owns this touch sequence.  */
+    TOUCH_OWNERSHIP_SELF,
+  };
+
 struct xi_touch_point_t
 {
-  /* The next touch point in this list.  */
-  struct xi_touch_point_t *next;
-
   /* The touchpoint detail.  */
   int number;
 
-  /* The last known X and Y position of the touchpoint.  */
-  double x, y;
+  /* Whether or not Emacs has ``exclusive'' access to this touch
+     point.  */
+  enum xi_touch_ownership ownership;
+
+  /* The last known rounded X and Y positions of the touchpoint.  */
+  int x, y;
 
   /* The frame associated with this touch point.  */
   struct frame *frame;
+
+  /* The next touch point in this list.  */
+  struct xi_touch_point_t *next;
 };
 
 #endif



reply via email to

[Prev in Thread] Current Thread [Next in Thread]