aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2024-06-01 15:41:54 +0800
committerPo Lu2024-06-01 15:41:54 +0800
commit2b7056db424ab0f8bf9e96b5a3c6aa12a3debf48 (patch)
tree2e1bb7731a0e25001b2df993b2c218f797b00df9 /src
parentb1692e23edc32ce8938d3af200c0c42c8aa6b313 (diff)
downloademacs-2b7056db424ab0f8bf9e96b5a3c6aa12a3debf48.tar.gz
emacs-2b7056db424ab0f8bf9e96b5a3c6aa12a3debf48.zip
Implement touch screen events on PGTK
* etc/NEWS: Better qualify entry for touch screen events. * lisp/loadup.el (featurep 'pgtk): Load touch-screen.el. * lisp/touch-screen.el: Revise list of systems where touch screen events are reported. * src/gtkutil.c (xg_create_frame_widgets): Request GDK_TOUCH_MASK. * src/pgtkfns.c (pgtk_frame_parm_handlers, tip_window): Pacify compiler warning. * src/pgtkterm.c (pgtk_free_frame_resources): Free touch points linked to this frame. (pgtk_link_touch_point, pgtk_unlink_touch_point) (pgtk_unlink_touch_points, pgtk_find_touch_point): New functions, ported from X. (touch_event_cb): New event callback. (pgtk_set_event_handler): Register `touch_event_cb' as handler for `touch-event'. (pgtk_delete_display): Free residual touch points on this display. * src/pgtkterm.h (struct pgtk_touch_point): New structure. (struct pgtk_display_info) <touchpoints>: New field.
Diffstat (limited to 'src')
-rw-r--r--src/gtkutil.c1
-rw-r--r--src/pgtkfns.c3
-rw-r--r--src/pgtkterm.c241
-rw-r--r--src/pgtkterm.h32
4 files changed, 274 insertions, 3 deletions
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 7de8eba0aa1..d57627f152f 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -1669,6 +1669,7 @@ xg_create_frame_widgets (struct frame *f)
1669#ifdef HAVE_PGTK 1669#ifdef HAVE_PGTK
1670 | GDK_SCROLL_MASK 1670 | GDK_SCROLL_MASK
1671 | GDK_SMOOTH_SCROLL_MASK 1671 | GDK_SMOOTH_SCROLL_MASK
1672 | GDK_TOUCH_MASK
1672#endif 1673#endif
1673 | GDK_VISIBILITY_NOTIFY_MASK); 1674 | GDK_VISIBILITY_NOTIFY_MASK);
1674 1675
diff --git a/src/pgtkfns.c b/src/pgtkfns.c
index 6a8efb6d0bf..bdc6c5836fa 100644
--- a/src/pgtkfns.c
+++ b/src/pgtkfns.c
@@ -945,6 +945,7 @@ unless TYPE is `png'. */)
945 return pgtk_cr_export_frames (frames, surface_type); 945 return pgtk_cr_export_frames (frames, surface_type);
946} 946}
947 947
948extern frame_parm_handler pgtk_frame_parm_handlers[];
948frame_parm_handler pgtk_frame_parm_handlers[] = 949frame_parm_handler pgtk_frame_parm_handlers[] =
949 { 950 {
950 gui_set_autoraise, /* generic OK */ 951 gui_set_autoraise, /* generic OK */
@@ -2619,7 +2620,7 @@ static Lisp_Object tip_frame;
2619 2620
2620/* The window-system window corresponding to the frame of the 2621/* The window-system window corresponding to the frame of the
2621 currently visible tooltip. */ 2622 currently visible tooltip. */
2622GtkWidget *tip_window; 2623static GtkWidget *tip_window;
2623 2624
2624/* A timer that hides or deletes the currently visible tooltip when it 2625/* A timer that hides or deletes the currently visible tooltip when it
2625 fires. */ 2626 fires. */
diff --git a/src/pgtkterm.c b/src/pgtkterm.c
index 8d9a47b932f..886f115c391 100644
--- a/src/pgtkterm.c
+++ b/src/pgtkterm.c
@@ -450,6 +450,8 @@ pgtk_frame_raise_lower (struct frame *f, bool raise_flag)
450 450
451/* Free X resources of frame F. */ 451/* Free X resources of frame F. */
452 452
453static void pgtk_unlink_touch_points (struct frame *);
454
453void 455void
454pgtk_free_frame_resources (struct frame *f) 456pgtk_free_frame_resources (struct frame *f)
455{ 457{
@@ -462,6 +464,7 @@ pgtk_free_frame_resources (struct frame *f)
462 464
463 block_input (); 465 block_input ();
464 466
467 pgtk_unlink_touch_points (f);
465#ifdef HAVE_XWIDGETS 468#ifdef HAVE_XWIDGETS
466 kill_frame_xwidget_views (f); 469 kill_frame_xwidget_views (f);
467#endif 470#endif
@@ -6524,6 +6527,230 @@ drag_drop (GtkWidget *widget, GdkDragContext *context,
6524 return TRUE; 6527 return TRUE;
6525} 6528}
6526 6529
6530
6531
6532/* Touch screen events. */
6533
6534/* Record a touch sequence with the identifier DETAIL from the given
6535 FRAME on the specified DPYINFO. Round X and Y and record them as its
6536 current position, assign an identifier to the touch sequence suitable
6537 for reporting to Lisp, and return the same. */
6538
6539static EMACS_INT
6540pgtk_link_touch_point (struct pgtk_display_info *dpyinfo,
6541 GdkEventSequence *detail, gdouble x,
6542 gdouble y, struct frame *frame)
6543{
6544 struct pgtk_touch_point *touchpoint;
6545 static EMACS_INT local_detail;
6546
6547 /* Assign an identifier suitable for reporting to Lisp. On builds
6548 with 64-bit Lisp_Object, this is largely a theoretical problem, but
6549 CARD32s easily overflow 32-bit systems, as they are not specific to
6550 X clients (e.g. Emacs) but grow uniformly across all of them. */
6551
6552 if (FIXNUM_OVERFLOW_P (local_detail))
6553 local_detail = 0;
6554
6555 touchpoint = xmalloc (sizeof *touchpoint);
6556 touchpoint->next = dpyinfo->touchpoints;
6557 touchpoint->x = lrint (x);
6558 touchpoint->y = lrint (y);
6559 touchpoint->number = detail;
6560 touchpoint->local_detail = local_detail++;
6561 touchpoint->frame = frame;
6562 dpyinfo->touchpoints = touchpoint;
6563 return touchpoint->local_detail;
6564}
6565
6566/* Free and remove the touch sequence with the identifier DETAIL.
6567 DPYINFO is the display in which the touch sequence should be
6568 recorded. If such a touch sequence exists, return its local
6569 identifier in *LOCAL_DETAIL.
6570
6571 Value is 0 if no touch sequence by that identifier exists inside
6572 DPYINFO, or 1 if a touch sequence has been found. */
6573
6574static int
6575pgtk_unlink_touch_point (GdkEventSequence *detail,
6576 struct pgtk_display_info *dpyinfo,
6577 EMACS_INT *local_detail)
6578{
6579 struct pgtk_touch_point *last, *tem;
6580
6581 for (last = NULL, tem = dpyinfo->touchpoints; tem;
6582 last = tem, tem = tem->next)
6583 {
6584 if (tem->number == detail)
6585 {
6586 if (!last)
6587 dpyinfo->touchpoints = tem->next;
6588 else
6589 last->next = tem->next;
6590
6591 *local_detail = tem->local_detail;
6592 xfree (tem);
6593
6594 return 1;
6595 }
6596 }
6597
6598 return 0;
6599}
6600
6601/* Unlink all touch points associated with the frame F. This is done
6602 upon destroying F's window (or its being destroyed), because touch
6603 point delivery after that point is undefined. */
6604
6605static void
6606pgtk_unlink_touch_points (struct frame *f)
6607{
6608 struct pgtk_touch_point **next, *last;
6609 struct pgtk_display_info *dpyinfo;
6610
6611 /* Now unlink all touch points on F's display matching F. */
6612
6613 dpyinfo = FRAME_DISPLAY_INFO (f);
6614 for (next = &dpyinfo->touchpoints; (last = *next);)
6615 {
6616 if (last->frame == f)
6617 {
6618 *next = last->next;
6619 xfree (last);
6620 }
6621 else
6622 next = &last->next;
6623 }
6624}
6625
6626/* Return the data associated with a touch sequence DETAIL recorded by
6627 `pgtk_link_touch_point' from DPYINFO, or NULL if it can't be
6628 found. */
6629
6630static struct pgtk_touch_point *
6631pgtk_find_touch_point (struct pgtk_display_info *dpyinfo,
6632 GdkEventSequence *detail)
6633{
6634 struct pgtk_touch_point *point;
6635
6636 for (point = dpyinfo->touchpoints; point; point = point->next)
6637 {
6638 if (point->number == detail)
6639 return point;
6640 }
6641
6642 return NULL;
6643}
6644
6645static bool
6646touch_event_cb (GtkWidget *self, GdkEvent *event, gpointer user_data)
6647{
6648 struct pgtk_display_info *dpyinfo;
6649 struct frame *f;
6650 EMACS_INT local_detail;
6651 union buffered_input_event inev;
6652 struct pgtk_touch_point *touchpoint;
6653 Lisp_Object arg = Qnil;
6654 int state;
6655
6656 EVENT_INIT (inev.ie);
6657
6658 f = pgtk_any_window_to_frame (gtk_widget_get_window (self));
6659 eassert (f);
6660 dpyinfo = FRAME_DISPLAY_INFO (f);
6661 switch (event->type)
6662 {
6663 case GDK_TOUCH_BEGIN:
6664
6665 /* Verify that no touch point with this identifier is already at
6666 large. */
6667 if (pgtk_find_touch_point (dpyinfo, event->touch.sequence))
6668 break;
6669
6670 /* Record this in the display structure. */
6671 local_detail = pgtk_link_touch_point (dpyinfo, event->touch.sequence,
6672 event->touch.x, event->touch.y,
6673 f);
6674 /* Generate the input event. */
6675 inev.ie.kind = TOUCHSCREEN_BEGIN_EVENT;
6676 inev.ie.timestamp = event->touch.time;
6677 XSETFRAME (inev.ie.frame_or_window, f);
6678 XSETINT (inev.ie.x, lrint (event->touch.x));
6679 XSETINT (inev.ie.y, lrint (event->touch.y));
6680 XSETINT (inev.ie.arg, local_detail);
6681 break;
6682
6683 case GDK_TOUCH_UPDATE:
6684 touchpoint = pgtk_find_touch_point (dpyinfo,
6685 event->touch.sequence);
6686
6687 if (!touchpoint
6688 /* Don't send this event if nothing has changed
6689 either. */
6690 || (touchpoint->x == lrint (event->touch.x)
6691 && touchpoint->y == lrint (event->touch.y)))
6692 break;
6693
6694 /* Construct the input event. */
6695 touchpoint->x = lrint (event->touch.x);
6696 touchpoint->y = lrint (event->touch.y);
6697 inev.ie.kind = TOUCHSCREEN_UPDATE_EVENT;
6698 inev.ie.timestamp = event->touch.time;
6699 XSETFRAME (inev.ie.frame_or_window, f);
6700
6701 for (touchpoint = dpyinfo->touchpoints;
6702 touchpoint; touchpoint = touchpoint->next)
6703 {
6704 if (touchpoint->frame == f)
6705 arg = Fcons (list3i (touchpoint->x, touchpoint->y,
6706 touchpoint->local_detail),
6707 arg);
6708 }
6709
6710 inev.ie.arg = arg;
6711 break;
6712
6713 case GDK_TOUCH_END:
6714 case GDK_TOUCH_CANCEL:
6715 /* Remove this touch point's record, also establishing its
6716 existence. */
6717 state = pgtk_unlink_touch_point (event->touch.sequence,
6718 dpyinfo, &local_detail);
6719 /* If it did exist... */
6720 if (state)
6721 {
6722 /* ... generate a suitable event. */
6723 inev.ie.kind = TOUCHSCREEN_END_EVENT;
6724 inev.ie.timestamp = event->touch.time;
6725 inev.ie.modifiers = (event->type != GDK_TOUCH_END);
6726
6727 XSETFRAME (inev.ie.frame_or_window, f);
6728 XSETINT (inev.ie.x, lrint (event->touch.x));
6729 XSETINT (inev.ie.y, lrint (event->touch.y));
6730 XSETINT (inev.ie.arg, local_detail);
6731 }
6732 break;
6733
6734 default:
6735 break;
6736 }
6737
6738 /* If the above produced a workable event, report the name of the
6739 device that gave rise to it. */
6740
6741 if (inev.ie.kind != NO_EVENT)
6742 {
6743 inev.ie.device = pgtk_get_device_for_event (dpyinfo, event);
6744 evq_enqueue (&inev);
6745 }
6746
6747 return inev.ie.kind != NO_EVENT;
6748}
6749
6750
6751
6752/* Callbacks for sundries. */
6753
6527static void 6754static void
6528pgtk_monitors_changed_cb (GdkScreen *screen, gpointer user_data) 6755pgtk_monitors_changed_cb (GdkScreen *screen, gpointer user_data)
6529{ 6756{
@@ -6540,6 +6767,8 @@ pgtk_monitors_changed_cb (GdkScreen *screen, gpointer user_data)
6540 6767
6541static gboolean pgtk_selection_event (GtkWidget *, GdkEvent *, gpointer); 6768static gboolean pgtk_selection_event (GtkWidget *, GdkEvent *, gpointer);
6542 6769
6770
6771
6543void 6772void
6544pgtk_set_event_handler (struct frame *f) 6773pgtk_set_event_handler (struct frame *f)
6545{ 6774{
@@ -6609,6 +6838,8 @@ pgtk_set_event_handler (struct frame *f)
6609 G_CALLBACK (pgtk_selection_event), NULL); 6838 G_CALLBACK (pgtk_selection_event), NULL);
6610 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "selection-notify-event", 6839 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "selection-notify-event",
6611 G_CALLBACK (pgtk_selection_event), NULL); 6840 G_CALLBACK (pgtk_selection_event), NULL);
6841 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "touch-event",
6842 G_CALLBACK (touch_event_cb), NULL);
6612 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "event", 6843 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "event",
6613 G_CALLBACK (pgtk_handle_event), NULL); 6844 G_CALLBACK (pgtk_handle_event), NULL);
6614} 6845}
@@ -7028,6 +7259,7 @@ static void
7028pgtk_delete_display (struct pgtk_display_info *dpyinfo) 7259pgtk_delete_display (struct pgtk_display_info *dpyinfo)
7029{ 7260{
7030 struct terminal *t; 7261 struct terminal *t;
7262 struct pgtk_touch_point *last, *tem;
7031 7263
7032 /* Close all frames and delete the generic struct terminal for this 7264 /* Close all frames and delete the generic struct terminal for this
7033 X display. */ 7265 X display. */
@@ -7049,6 +7281,15 @@ pgtk_delete_display (struct pgtk_display_info *dpyinfo)
7049 tail->next = tail->next->next; 7281 tail->next = tail->next->next;
7050 } 7282 }
7051 7283
7284 /* Free remaining touchpoints. */
7285 tem = dpyinfo->touchpoints;
7286 while (tem)
7287 {
7288 last = tem;
7289 tem = tem->next;
7290 xfree (last);
7291 }
7292
7052 pgtk_free_devices (dpyinfo); 7293 pgtk_free_devices (dpyinfo);
7053 xfree (dpyinfo); 7294 xfree (dpyinfo);
7054} 7295}
diff --git a/src/pgtkterm.h b/src/pgtkterm.h
index 8072d963691..90ca2aa22d4 100644
--- a/src/pgtkterm.h
+++ b/src/pgtkterm.h
@@ -50,13 +50,38 @@ struct pgtk_bitmap_record
50 50
51struct pgtk_device_t 51struct pgtk_device_t
52{ 52{
53 /* Lisp name of the device. */
54 Lisp_Object name;
55
56 /* Seat to which this device appertains. */
53 GdkSeat *seat; 57 GdkSeat *seat;
58
59 /* Pointer to this device's GdkDevice object. */
54 GdkDevice *device; 60 GdkDevice *device;
55 61
56 Lisp_Object name; 62 /* Next device in this chain. */
57 struct pgtk_device_t *next; 63 struct pgtk_device_t *next;
58}; 64};
59 65
66struct pgtk_touch_point
67{
68 /* The detail code reported to Lisp. */
69 EMACS_INT local_detail;
70
71 /* The frame associated with this touch point. */
72 struct frame *frame;
73
74 /* The next touch point in this list. */
75 struct pgtk_touch_point *next;
76
77 /* The touchpoint detail. This purports to be a pointer, but is a
78 number. */
79 GdkEventSequence *number;
80
81 /* The last known rounded X and Y positions of the touchpoint. */
82 int x, y;
83};
84
60#define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b)) 85#define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b))
61#define ARGB_TO_ULONG(a, r, g, b) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) 86#define ARGB_TO_ULONG(a, r, g, b) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
62 87
@@ -131,10 +156,13 @@ struct pgtk_display_info
131 /* This says how to access this display through GDK. */ 156 /* This says how to access this display through GDK. */
132 GdkDisplay *gdpy; 157 GdkDisplay *gdpy;
133 158
134 /* An alias defined to make porting X code easier. */ 159 /* An alias defined to facilitate porting X code. */
135 GdkDisplay *display; 160 GdkDisplay *display;
136 }; 161 };
137 162
163 /* List of active touch-points. */
164 struct pgtk_touch_point *touchpoints;
165
138 /* This is a cons cell of the form (NAME . FONT-LIST-CACHE). */ 166 /* This is a cons cell of the form (NAME . FONT-LIST-CACHE). */
139 Lisp_Object name_list_element; 167 Lisp_Object name_list_element;
140 168