[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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- master 9ad601e7d76: Expose the ``cancellation'' of touch events to Lisp,
Po Lu <=