]> git.eshelyaron.com Git - emacs.git/commitdiff
Expose the ``cancellation'' of touch events to Lisp
authorPo Lu <luangruo@yahoo.com>
Tue, 18 Jul 2023 01:27:27 +0000 (09:27 +0800)
committerPo Lu <luangruo@yahoo.com>
Tue, 18 Jul 2023 01:28:14 +0000 (09:28 +0800)
* 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
etc/NEWS
src/keyboard.c
src/termhooks.h
src/xfns.c
src/xterm.c
src/xterm.h

index cd1745614ebfd3beaa514107cbb507d35947f1c3..037f42124ccc8d2b704f096eace9efd9ef31de2b 100644 (file)
@@ -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
index 3cfc36e10daec37428273dfe24adb7c4702d2559..c50f560282a3798391bf808f8a75c940650dccf4 100644 (file)
--- 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
index b61b1766856d3b9c4bc4b2bd9076d163247c81d7..41cda2e65de5d7b4b1893be02c3d34485043261a 100644 (file)
@@ -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;
index ba04a6b7759d87a9a1f51277387284e408f9819f..c8345c2715ff903ef2df4951f49c911897e65e71 100644 (file)
@@ -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
index fd4807fd5f524f9421ac60afb00e36c95cfb7372..55bcfb8e20ed22d306a5dd8102f6704b68737b38 100644 (file)
@@ -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)
index 5cc2dfdae1d33824d0d72d76d6b99fd9ffd6a139..130a2c93b64da8938dd702748aa1b64b3059fe35 100644 (file)
@@ -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));
index 34a713ea2ca3e23853d01bee1a36f51b6c8d0b3f..c7db54e2bcfffb09326905f77388d685cf2e1187 100644 (file)
@@ -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