aboutsummaryrefslogtreecommitdiffstats
path: root/src/pgtkterm.c
diff options
context:
space:
mode:
authorPo Lu2022-04-08 13:37:16 +0800
committerPo Lu2022-04-08 13:37:16 +0800
commitac2708bf6f83dfb965694381c4e9d0c71f61bd0c (patch)
tree93c26be2946195cd3380eef81401d33a440a27e8 /src/pgtkterm.c
parente9849939549010529e180ffb2509922f1bcc4843 (diff)
downloademacs-ac2708bf6f83dfb965694381c4e9d0c71f61bd0c.tar.gz
emacs-ac2708bf6f83dfb965694381c4e9d0c71f61bd0c.zip
Implement support for reporting device names on PGTK
* lisp/frame.el (device-class): Add new function. * lisp/term/pgtk-win.el (pgtk-device-class): New function. * src/pgtkterm.c (pgtk_device_added_or_removal_cb) (pgtk_seat_added_cb, pgtk_seat_removed_cb) (pgtk_enumerate_devices) (pgtk_free_devices, pgtk_regenerate_devices) (pgtk_get_device_for_event): New functions. (mark_pgtkterm): Mark device data. (pgtk_delete_terminal): Delete device data. (pgtk_handle_event, key_press_event, note_mouse_movement) (construct_mouse_click, button_event, scroll_event) (drag_data_received): Set device correctly. (pgtk_term_init): Initialize device data and seat tracking. (pgtk_delete_display): Delete device data. * src/pgtkterm.h (struct pgtk_device_t): New struct. (struct pgtk_display_info): New field `devices'. Delete lots of unused macros and reformat comments.
Diffstat (limited to 'src/pgtkterm.c')
-rw-r--r--src/pgtkterm.c256
1 files changed, 212 insertions, 44 deletions
diff --git a/src/pgtkterm.c b/src/pgtkterm.c
index b2816aa04af..d8c6dad2f9d 100644
--- a/src/pgtkterm.c
+++ b/src/pgtkterm.c
@@ -98,15 +98,124 @@ static Time ignore_next_mouse_click_timeout;
98 98
99static Lisp_Object xg_default_icon_file; 99static Lisp_Object xg_default_icon_file;
100 100
101static void pgtk_delete_display (struct pgtk_display_info *dpyinfo); 101static void pgtk_delete_display (struct pgtk_display_info *);
102static void pgtk_clear_frame_area (struct frame *f, int x, int y, int width, 102static void pgtk_clear_frame_area (struct frame *, int, int, int, int);
103 int height); 103static void pgtk_fill_rectangle (struct frame *, unsigned long, int, int,
104static void pgtk_fill_rectangle (struct frame *f, unsigned long color, int x, 104 int, int, bool);
105 int y, int width, int height, 105static void pgtk_clip_to_row (struct window *, struct glyph_row *,
106 bool respect_alpha_background); 106 enum glyph_row_area, cairo_t *);
107static void pgtk_clip_to_row (struct window *w, struct glyph_row *row, 107static struct frame *pgtk_any_window_to_frame (GdkWindow *);
108 enum glyph_row_area area, cairo_t * cr); 108static void pgtk_regenerate_devices (struct pgtk_display_info *);
109static struct frame *pgtk_any_window_to_frame (GdkWindow *window); 109
110static void
111pgtk_device_added_or_removal_cb (GdkSeat *seat, GdkDevice *device,
112 gpointer user_data)
113{
114 pgtk_regenerate_devices (user_data);
115}
116
117static void
118pgtk_seat_added_cb (GdkDisplay *dpy, GdkSeat *seat,
119 gpointer user_data)
120{
121 pgtk_regenerate_devices (user_data);
122
123 g_signal_connect (G_OBJECT (seat), "device-added",
124 G_CALLBACK (pgtk_device_added_or_removal_cb),
125 user_data);
126 g_signal_connect (G_OBJECT (seat), "device-removed",
127 G_CALLBACK (pgtk_device_added_or_removal_cb),
128 user_data);
129}
130
131static void
132pgtk_seat_removed_cb (GdkDisplay *dpy, GdkSeat *seat,
133 gpointer user_data)
134{
135 pgtk_regenerate_devices (user_data);
136
137 g_signal_handlers_disconnect_by_func (G_OBJECT (seat),
138 G_CALLBACK (pgtk_device_added_or_removal_cb),
139 user_data);
140}
141
142static void
143pgtk_enumerate_devices (struct pgtk_display_info *dpyinfo,
144 bool initial_p)
145{
146 struct pgtk_device_t *rec;
147 GList *all_seats, *devices_on_seat, *tem, *t1;
148 GdkSeat *seat;
149 char printbuf[1026]; /* Believe it or not, some device names are
150 actually almost this long. */
151
152 block_input ();
153 all_seats = gdk_display_list_seats (dpyinfo->gdpy);
154
155 for (tem = all_seats; tem; tem = tem->next)
156 {
157 seat = GDK_SEAT (tem->data);
158
159 if (initial_p)
160 {
161 g_signal_connect (G_OBJECT (seat), "device-added",
162 G_CALLBACK (pgtk_device_added_or_removal_cb),
163 dpyinfo);
164 g_signal_connect (G_OBJECT (seat), "device-removed",
165 G_CALLBACK (pgtk_device_added_or_removal_cb),
166 dpyinfo);
167 }
168
169 /* We only want slaves, not master devices. */
170 devices_on_seat = gdk_seat_get_slaves (seat,
171 GDK_SEAT_CAPABILITY_ALL);
172
173 for (t1 = devices_on_seat; t1; t1 = t1->next)
174 {
175 rec = xmalloc (sizeof *rec);
176 rec->seat = g_object_ref (seat);
177 rec->device = GDK_DEVICE (t1->data);
178
179 snprintf (printbuf, 1026, "%u:%s",
180 gdk_device_get_source (rec->device),
181 gdk_device_get_name (rec->device));
182
183 rec->name = build_string (printbuf);
184 rec->next = dpyinfo->devices;
185 dpyinfo->devices = rec;
186 }
187
188 g_list_free (devices_on_seat);
189 }
190
191 g_list_free (all_seats);
192 unblock_input ();
193}
194
195static void
196pgtk_free_devices (struct pgtk_display_info *dpyinfo)
197{
198 struct pgtk_device_t *last, *tem;
199
200 tem = dpyinfo->devices;
201 while (tem)
202 {
203 last = tem;
204 tem = tem->next;
205
206 g_object_unref (last->seat);
207 xfree (last);
208 }
209
210 dpyinfo->devices = NULL;
211}
212
213static void
214pgtk_regenerate_devices (struct pgtk_display_info *dpyinfo)
215{
216 pgtk_free_devices (dpyinfo);
217 pgtk_enumerate_devices (dpyinfo, false);
218}
110 219
111static void 220static void
112pgtk_toolkit_position (struct frame *f, int x, int y, 221pgtk_toolkit_position (struct frame *f, int x, int y,
@@ -136,6 +245,27 @@ pgtk_toolkit_position (struct frame *f, int x, int y,
136 } 245 }
137} 246}
138 247
248static Lisp_Object
249pgtk_get_device_for_event (struct pgtk_display_info *dpyinfo,
250 GdkEvent *event)
251{
252 struct pgtk_device_t *tem;
253 GdkDevice *device;
254
255 device = gdk_event_get_source_device (event);
256
257 if (!device)
258 return Qt;
259
260 for (tem = dpyinfo->devices; tem; tem = tem->next)
261 {
262 if (tem->device == device)
263 return tem->name;
264 }
265
266 return Qt;
267}
268
139/* This is not a flip context in the same sense as gpu rendering 269/* This is not a flip context in the same sense as gpu rendering
140 scenes, it only occurs when a new context was required due to a 270 scenes, it only occurs when a new context was required due to a
141 resize or other fundamental change. This is called when that 271 resize or other fundamental change. This is called when that
@@ -205,8 +335,11 @@ evq_flush (struct input_event *hold_quit)
205void 335void
206mark_pgtkterm (void) 336mark_pgtkterm (void)
207{ 337{
338 struct pgtk_display_info *dpyinfo;
339 struct pgtk_device_t *device;
208 struct event_queue_t *evq = &event_q; 340 struct event_queue_t *evq = &event_q;
209 int i, n = evq->nr; 341 int i, n = evq->nr;
342
210 for (i = 0; i < n; i++) 343 for (i = 0; i < n; i++)
211 { 344 {
212 union buffered_input_event *ev = &evq->q[i]; 345 union buffered_input_event *ev = &evq->q[i];
@@ -215,6 +348,14 @@ mark_pgtkterm (void)
215 mark_object (ev->ie.frame_or_window); 348 mark_object (ev->ie.frame_or_window);
216 mark_object (ev->ie.arg); 349 mark_object (ev->ie.arg);
217 } 350 }
351
352 for (dpyinfo = x_display_list; dpyinfo;
353 dpyinfo = dpyinfo->next)
354 {
355 for (device = dpyinfo->devices; device;
356 device = device->next)
357 mark_object (device->name);
358 }
218} 359}
219 360
220char * 361char *
@@ -4460,11 +4601,20 @@ pgtk_delete_terminal (struct terminal *terminal)
4460 g_clear_object (&dpyinfo->vertical_scroll_bar_cursor); 4601 g_clear_object (&dpyinfo->vertical_scroll_bar_cursor);
4461 g_clear_object (&dpyinfo->horizontal_scroll_bar_cursor); 4602 g_clear_object (&dpyinfo->horizontal_scroll_bar_cursor);
4462 g_clear_object (&dpyinfo->invisible_cursor); 4603 g_clear_object (&dpyinfo->invisible_cursor);
4463 if (dpyinfo->last_click_event != NULL) { 4604 if (dpyinfo->last_click_event != NULL)
4464 gdk_event_free (dpyinfo->last_click_event); 4605 {
4465 dpyinfo->last_click_event = NULL; 4606 gdk_event_free (dpyinfo->last_click_event);
4466 } 4607 dpyinfo->last_click_event = NULL;
4608 }
4467 4609
4610 /* Disconnect these handlers before the display closes so
4611 useless removal signals don't fire. */
4612 g_signal_handlers_disconnect_by_func (G_OBJECT (dpyinfo->gdpy),
4613 G_CALLBACK (pgtk_seat_added_cb),
4614 dpyinfo);
4615 g_signal_handlers_disconnect_by_func (G_OBJECT (dpyinfo->gdpy),
4616 G_CALLBACK (pgtk_seat_removed_cb),
4617 dpyinfo);
4468 xg_display_close (dpyinfo->gdpy); 4618 xg_display_close (dpyinfo->gdpy);
4469 4619
4470 dpyinfo->gdpy = NULL; 4620 dpyinfo->gdpy = NULL;
@@ -4889,6 +5039,8 @@ pgtk_handle_event (GtkWidget *widget, GdkEvent *event, gpointer *data)
4889 make_float (event->touchpad_pinch.angle_delta)); 5039 make_float (event->touchpad_pinch.angle_delta));
4890 inev.ie.modifiers = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), 5040 inev.ie.modifiers = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f),
4891 event->touchpad_pinch.state); 5041 event->touchpad_pinch.state);
5042 inev.ie.device
5043 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
4892 evq_enqueue (&inev); 5044 evq_enqueue (&inev);
4893 } 5045 }
4894 5046
@@ -5227,7 +5379,7 @@ pgtk_enqueue_preedit (struct frame *f, Lisp_Object preedit)
5227} 5379}
5228 5380
5229static gboolean 5381static gboolean
5230key_press_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data) 5382key_press_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data)
5231{ 5383{
5232 struct coding_system coding; 5384 struct coding_system coding;
5233 union buffered_input_event inev; 5385 union buffered_input_event inev;
@@ -5237,8 +5389,6 @@ key_press_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
5237 USE_SAFE_ALLOCA; 5389 USE_SAFE_ALLOCA;
5238 5390
5239 EVENT_INIT (inev.ie); 5391 EVENT_INIT (inev.ie);
5240 inev.ie.kind = NO_EVENT;
5241 inev.ie.arg = Qnil;
5242 5392
5243 struct frame *f = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); 5393 struct frame *f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
5244 hlinfo = MOUSE_HL_INFO (f); 5394 hlinfo = MOUSE_HL_INFO (f);
@@ -5321,6 +5471,9 @@ key_press_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
5321 { 5471 {
5322 inev.ie.kind = ASCII_KEYSTROKE_EVENT; 5472 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
5323 inev.ie.code = keysym; 5473 inev.ie.code = keysym;
5474
5475 inev.ie.device
5476 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
5324 goto done; 5477 goto done;
5325 } 5478 }
5326 5479
@@ -5332,6 +5485,9 @@ key_press_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
5332 else 5485 else
5333 inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; 5486 inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
5334 inev.ie.code = keysym & 0xFFFFFF; 5487 inev.ie.code = keysym & 0xFFFFFF;
5488
5489 inev.ie.device
5490 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
5335 goto done; 5491 goto done;
5336 } 5492 }
5337 5493
@@ -5344,6 +5500,9 @@ key_press_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
5344 ? ASCII_KEYSTROKE_EVENT 5500 ? ASCII_KEYSTROKE_EVENT
5345 : MULTIBYTE_CHAR_KEYSTROKE_EVENT); 5501 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
5346 inev.ie.code = XFIXNAT (c); 5502 inev.ie.code = XFIXNAT (c);
5503
5504 inev.ie.device
5505 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
5347 goto done; 5506 goto done;
5348 } 5507 }
5349 5508
@@ -5427,6 +5586,9 @@ key_press_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
5427 key. */ 5586 key. */
5428 inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT; 5587 inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT;
5429 inev.ie.code = keysym; 5588 inev.ie.code = keysym;
5589
5590 inev.ie.device
5591 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
5430 goto done; 5592 goto done;
5431 } 5593 }
5432 5594
@@ -5478,6 +5640,8 @@ key_press_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
5478 ? ASCII_KEYSTROKE_EVENT 5640 ? ASCII_KEYSTROKE_EVENT
5479 : MULTIBYTE_CHAR_KEYSTROKE_EVENT); 5641 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
5480 inev.ie.code = ch; 5642 inev.ie.code = ch;
5643 inev.ie.device
5644 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
5481 evq_enqueue (&inev); 5645 evq_enqueue (&inev);
5482 } 5646 }
5483 5647
@@ -5859,7 +6023,8 @@ focus_out_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
5859 another motion event, so we can check again the next time it moves. */ 6023 another motion event, so we can check again the next time it moves. */
5860 6024
5861static bool 6025static bool
5862note_mouse_movement (struct frame *frame, const GdkEventMotion * event) 6026note_mouse_movement (struct frame *frame,
6027 const GdkEventMotion *event)
5863{ 6028{
5864 XRectangle *r; 6029 XRectangle *r;
5865 struct pgtk_display_info *dpyinfo; 6030 struct pgtk_display_info *dpyinfo;
@@ -5879,6 +6044,9 @@ note_mouse_movement (struct frame *frame, const GdkEventMotion * event)
5879 dpyinfo->last_mouse_scroll_bar = NULL; 6044 dpyinfo->last_mouse_scroll_bar = NULL;
5880 note_mouse_highlight (frame, -1, -1); 6045 note_mouse_highlight (frame, -1, -1);
5881 dpyinfo->last_mouse_glyph_frame = NULL; 6046 dpyinfo->last_mouse_glyph_frame = NULL;
6047 frame->last_mouse_device
6048 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (frame),
6049 (GdkEvent *) event);
5882 return true; 6050 return true;
5883 } 6051 }
5884 6052
@@ -5895,6 +6063,9 @@ note_mouse_movement (struct frame *frame, const GdkEventMotion * event)
5895 /* Remember which glyph we're now on. */ 6063 /* Remember which glyph we're now on. */
5896 remember_mouse_glyph (frame, event->x, event->y, r); 6064 remember_mouse_glyph (frame, event->x, event->y, r);
5897 dpyinfo->last_mouse_glyph_frame = frame; 6065 dpyinfo->last_mouse_glyph_frame = frame;
6066 frame->last_mouse_device
6067 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (frame),
6068 (GdkEvent *) event);
5898 return true; 6069 return true;
5899 } 6070 }
5900 6071
@@ -6010,26 +6181,6 @@ motion_notify_event (GtkWidget * widget, GdkEvent * event,
6010 return TRUE; 6181 return TRUE;
6011} 6182}
6012 6183
6013/* Mouse clicks and mouse movement. Rah.
6014
6015 Formerly, we used PointerMotionHintMask (in standard_event_mask)
6016 so that we would have to call XQueryPointer after each MotionNotify
6017 event to ask for another such event. However, this made mouse tracking
6018 slow, and there was a bug that made it eventually stop.
6019
6020 Simply asking for MotionNotify all the time seems to work better.
6021
6022 In order to avoid asking for motion events and then throwing most
6023 of them away or busy-polling the server for mouse positions, we ask
6024 the server for pointer motion hints. This means that we get only
6025 one event per group of mouse movements. "Groups" are delimited by
6026 other kinds of events (focus changes and button clicks, for
6027 example), or by XQueryPointer calls; when one of these happens, we
6028 get another MotionNotify event the next time the mouse moves. This
6029 is at least as efficient as getting motion events when mouse
6030 tracking is on, and I suspect only negligibly worse when tracking
6031 is off. */
6032
6033/* Prepare a mouse-event in *RESULT for placement in the input queue. 6184/* Prepare a mouse-event in *RESULT for placement in the input queue.
6034 6185
6035 If the event is a button press, then note that we have grabbed 6186 If the event is a button press, then note that we have grabbed
@@ -6037,7 +6188,8 @@ motion_notify_event (GtkWidget * widget, GdkEvent * event,
6037 6188
6038static Lisp_Object 6189static Lisp_Object
6039construct_mouse_click (struct input_event *result, 6190construct_mouse_click (struct input_event *result,
6040 const GdkEventButton * event, struct frame *f) 6191 const GdkEventButton *event,
6192 struct frame *f)
6041{ 6193{
6042 /* Make the event type NO_EVENT; we'll change that when we decide 6194 /* Make the event type NO_EVENT; we'll change that when we decide
6043 otherwise. */ 6195 otherwise. */
@@ -6052,11 +6204,15 @@ construct_mouse_click (struct input_event *result,
6052 XSETINT (result->y, event->y); 6204 XSETINT (result->y, event->y);
6053 XSETFRAME (result->frame_or_window, f); 6205 XSETFRAME (result->frame_or_window, f);
6054 result->arg = Qnil; 6206 result->arg = Qnil;
6207 result->device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f),
6208 (GdkEvent *) event);
6055 return Qnil; 6209 return Qnil;
6056} 6210}
6057 6211
6058static gboolean 6212static gboolean
6059button_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data) 6213button_event (GtkWidget *widget,
6214 GdkEvent *event,
6215 gpointer *user_data)
6060{ 6216{
6061 union buffered_input_event inev; 6217 union buffered_input_event inev;
6062 struct frame *f, *frame; 6218 struct frame *f, *frame;
@@ -6175,7 +6331,7 @@ button_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
6175} 6331}
6176 6332
6177static gboolean 6333static gboolean
6178scroll_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data) 6334scroll_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data)
6179{ 6335{
6180 union buffered_input_event inev; 6336 union buffered_input_event inev;
6181 struct frame *f, *frame; 6337 struct frame *f, *frame;
@@ -6207,6 +6363,8 @@ scroll_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
6207 if (gdk_event_is_scroll_stop_event (event)) 6363 if (gdk_event_is_scroll_stop_event (event))
6208 { 6364 {
6209 inev.ie.kind = TOUCH_END_EVENT; 6365 inev.ie.kind = TOUCH_END_EVENT;
6366 inev.ie.device
6367 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
6210 evq_enqueue (&inev); 6368 evq_enqueue (&inev);
6211 return TRUE; 6369 return TRUE;
6212 } 6370 }
@@ -6300,14 +6458,17 @@ scroll_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
6300 } 6458 }
6301 6459
6302 if (inev.ie.kind != NO_EVENT) 6460 if (inev.ie.kind != NO_EVENT)
6303 evq_enqueue (&inev); 6461 {
6462 inev.ie.device
6463 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
6464 evq_enqueue (&inev);
6465 }
6304 return TRUE; 6466 return TRUE;
6305} 6467}
6306 6468
6307static void 6469static void
6308drag_data_received (GtkWidget * widget, GdkDragContext * context, 6470drag_data_received (GtkWidget *widget, GdkDragContext *context,
6309 gint x, gint y, 6471 gint x, gint y, GtkSelectionData *data,
6310 GtkSelectionData * data,
6311 guint info, guint time, gpointer user_data) 6472 guint info, guint time, gpointer user_data)
6312{ 6473{
6313 struct frame *f = pgtk_any_window_to_frame (gtk_widget_get_window (widget)); 6474 struct frame *f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
@@ -6716,6 +6877,12 @@ pgtk_term_init (Lisp_Object display_name, char *resource_name)
6716 6877
6717 pgtk_im_init (dpyinfo); 6878 pgtk_im_init (dpyinfo);
6718 6879
6880 g_signal_connect (G_OBJECT (dpyinfo->gdpy), "seat-added",
6881 G_CALLBACK (pgtk_seat_added_cb), dpyinfo);
6882 g_signal_connect (G_OBJECT (dpyinfo->gdpy), "seat-removed",
6883 G_CALLBACK (pgtk_seat_removed_cb), dpyinfo);
6884 pgtk_enumerate_devices (dpyinfo, true);
6885
6719 unblock_input (); 6886 unblock_input ();
6720 6887
6721 return dpyinfo; 6888 return dpyinfo;
@@ -6749,6 +6916,7 @@ pgtk_delete_display (struct pgtk_display_info *dpyinfo)
6749 tail->next = tail->next->next; 6916 tail->next = tail->next->next;
6750 } 6917 }
6751 6918
6919 pgtk_free_devices (dpyinfo);
6752 xfree (dpyinfo); 6920 xfree (dpyinfo);
6753} 6921}
6754 6922