1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2025-02-01 20:06:00 +00:00

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.
This commit is contained in:
Po Lu 2022-04-08 13:37:16 +08:00
parent e984993954
commit ac2708bf6f
4 changed files with 250 additions and 107 deletions

View File

@ -2434,6 +2434,7 @@ monitors."
(frames . ,(frames-on-display-list display)))))))))
(declare-function x-device-class (name) "x-win.el")
(declare-function pgtk-device-class (name) "pgtk-win.el")
(defun device-class (frame name)
"Return the class of the device NAME for an event generated on FRAME.
@ -2488,6 +2489,8 @@ symbols."
(let ((frame-type (framep-on-display frame)))
(cond ((eq frame-type 'x)
(x-device-class name))
((eq frame-type 'pgtk)
(pgtk-device-class name))
(t (cond
((string= name "Virtual core pointer")
'core-pointer)

View File

@ -367,6 +367,27 @@ This uses `icon-map-list' to map icon file names to stock icon names."
(t
(popup-menu (mouse-menu-bar-map) last-nonmenu-event))))
(defun pgtk-device-class (name)
"Return the device class of NAME.
Users should not call this function; see `device-class' instead."
(cond
((string-match-p "XTEST" name) 'test)
((string= "Virtual core pointer" name) 'core-pointer)
((string= "Virtual core keyboard" name) 'core-keyboard)
(t (let ((number (ignore-errors
(string-to-number name))))
(when number
(cl-case number
(0 'mouse)
(1 'pen)
(2 'eraser)
(3 'puck)
(4 'keyboard)
(5 'touchscreen)
(6 'touchpad)
(7 'trackpoint)
(8 'pad)))))))
(defvaralias 'x-gtk-use-system-tooltips 'use-system-tooltips)
(provide 'pgtk-win)

View File

@ -98,15 +98,124 @@ static Time ignore_next_mouse_click_timeout;
static Lisp_Object xg_default_icon_file;
static void pgtk_delete_display (struct pgtk_display_info *dpyinfo);
static void pgtk_clear_frame_area (struct frame *f, int x, int y, int width,
int height);
static void pgtk_fill_rectangle (struct frame *f, unsigned long color, int x,
int y, int width, int height,
bool respect_alpha_background);
static void pgtk_clip_to_row (struct window *w, struct glyph_row *row,
enum glyph_row_area area, cairo_t * cr);
static struct frame *pgtk_any_window_to_frame (GdkWindow *window);
static void pgtk_delete_display (struct pgtk_display_info *);
static void pgtk_clear_frame_area (struct frame *, int, int, int, int);
static void pgtk_fill_rectangle (struct frame *, unsigned long, int, int,
int, int, bool);
static void pgtk_clip_to_row (struct window *, struct glyph_row *,
enum glyph_row_area, cairo_t *);
static struct frame *pgtk_any_window_to_frame (GdkWindow *);
static void pgtk_regenerate_devices (struct pgtk_display_info *);
static void
pgtk_device_added_or_removal_cb (GdkSeat *seat, GdkDevice *device,
gpointer user_data)
{
pgtk_regenerate_devices (user_data);
}
static void
pgtk_seat_added_cb (GdkDisplay *dpy, GdkSeat *seat,
gpointer user_data)
{
pgtk_regenerate_devices (user_data);
g_signal_connect (G_OBJECT (seat), "device-added",
G_CALLBACK (pgtk_device_added_or_removal_cb),
user_data);
g_signal_connect (G_OBJECT (seat), "device-removed",
G_CALLBACK (pgtk_device_added_or_removal_cb),
user_data);
}
static void
pgtk_seat_removed_cb (GdkDisplay *dpy, GdkSeat *seat,
gpointer user_data)
{
pgtk_regenerate_devices (user_data);
g_signal_handlers_disconnect_by_func (G_OBJECT (seat),
G_CALLBACK (pgtk_device_added_or_removal_cb),
user_data);
}
static void
pgtk_enumerate_devices (struct pgtk_display_info *dpyinfo,
bool initial_p)
{
struct pgtk_device_t *rec;
GList *all_seats, *devices_on_seat, *tem, *t1;
GdkSeat *seat;
char printbuf[1026]; /* Believe it or not, some device names are
actually almost this long. */
block_input ();
all_seats = gdk_display_list_seats (dpyinfo->gdpy);
for (tem = all_seats; tem; tem = tem->next)
{
seat = GDK_SEAT (tem->data);
if (initial_p)
{
g_signal_connect (G_OBJECT (seat), "device-added",
G_CALLBACK (pgtk_device_added_or_removal_cb),
dpyinfo);
g_signal_connect (G_OBJECT (seat), "device-removed",
G_CALLBACK (pgtk_device_added_or_removal_cb),
dpyinfo);
}
/* We only want slaves, not master devices. */
devices_on_seat = gdk_seat_get_slaves (seat,
GDK_SEAT_CAPABILITY_ALL);
for (t1 = devices_on_seat; t1; t1 = t1->next)
{
rec = xmalloc (sizeof *rec);
rec->seat = g_object_ref (seat);
rec->device = GDK_DEVICE (t1->data);
snprintf (printbuf, 1026, "%u:%s",
gdk_device_get_source (rec->device),
gdk_device_get_name (rec->device));
rec->name = build_string (printbuf);
rec->next = dpyinfo->devices;
dpyinfo->devices = rec;
}
g_list_free (devices_on_seat);
}
g_list_free (all_seats);
unblock_input ();
}
static void
pgtk_free_devices (struct pgtk_display_info *dpyinfo)
{
struct pgtk_device_t *last, *tem;
tem = dpyinfo->devices;
while (tem)
{
last = tem;
tem = tem->next;
g_object_unref (last->seat);
xfree (last);
}
dpyinfo->devices = NULL;
}
static void
pgtk_regenerate_devices (struct pgtk_display_info *dpyinfo)
{
pgtk_free_devices (dpyinfo);
pgtk_enumerate_devices (dpyinfo, false);
}
static void
pgtk_toolkit_position (struct frame *f, int x, int y,
@ -136,6 +245,27 @@ pgtk_toolkit_position (struct frame *f, int x, int y,
}
}
static Lisp_Object
pgtk_get_device_for_event (struct pgtk_display_info *dpyinfo,
GdkEvent *event)
{
struct pgtk_device_t *tem;
GdkDevice *device;
device = gdk_event_get_source_device (event);
if (!device)
return Qt;
for (tem = dpyinfo->devices; tem; tem = tem->next)
{
if (tem->device == device)
return tem->name;
}
return Qt;
}
/* This is not a flip context in the same sense as gpu rendering
scenes, it only occurs when a new context was required due to a
resize or other fundamental change. This is called when that
@ -205,8 +335,11 @@ evq_flush (struct input_event *hold_quit)
void
mark_pgtkterm (void)
{
struct pgtk_display_info *dpyinfo;
struct pgtk_device_t *device;
struct event_queue_t *evq = &event_q;
int i, n = evq->nr;
for (i = 0; i < n; i++)
{
union buffered_input_event *ev = &evq->q[i];
@ -215,6 +348,14 @@ mark_pgtkterm (void)
mark_object (ev->ie.frame_or_window);
mark_object (ev->ie.arg);
}
for (dpyinfo = x_display_list; dpyinfo;
dpyinfo = dpyinfo->next)
{
for (device = dpyinfo->devices; device;
device = device->next)
mark_object (device->name);
}
}
char *
@ -4460,11 +4601,20 @@ pgtk_delete_terminal (struct terminal *terminal)
g_clear_object (&dpyinfo->vertical_scroll_bar_cursor);
g_clear_object (&dpyinfo->horizontal_scroll_bar_cursor);
g_clear_object (&dpyinfo->invisible_cursor);
if (dpyinfo->last_click_event != NULL) {
gdk_event_free (dpyinfo->last_click_event);
dpyinfo->last_click_event = NULL;
}
if (dpyinfo->last_click_event != NULL)
{
gdk_event_free (dpyinfo->last_click_event);
dpyinfo->last_click_event = NULL;
}
/* Disconnect these handlers before the display closes so
useless removal signals don't fire. */
g_signal_handlers_disconnect_by_func (G_OBJECT (dpyinfo->gdpy),
G_CALLBACK (pgtk_seat_added_cb),
dpyinfo);
g_signal_handlers_disconnect_by_func (G_OBJECT (dpyinfo->gdpy),
G_CALLBACK (pgtk_seat_removed_cb),
dpyinfo);
xg_display_close (dpyinfo->gdpy);
dpyinfo->gdpy = NULL;
@ -4889,6 +5039,8 @@ pgtk_handle_event (GtkWidget *widget, GdkEvent *event, gpointer *data)
make_float (event->touchpad_pinch.angle_delta));
inev.ie.modifiers = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f),
event->touchpad_pinch.state);
inev.ie.device
= pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
evq_enqueue (&inev);
}
@ -5227,7 +5379,7 @@ pgtk_enqueue_preedit (struct frame *f, Lisp_Object preedit)
}
static gboolean
key_press_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
key_press_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data)
{
struct coding_system coding;
union buffered_input_event inev;
@ -5237,8 +5389,6 @@ key_press_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
USE_SAFE_ALLOCA;
EVENT_INIT (inev.ie);
inev.ie.kind = NO_EVENT;
inev.ie.arg = Qnil;
struct frame *f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
hlinfo = MOUSE_HL_INFO (f);
@ -5321,6 +5471,9 @@ key_press_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
{
inev.ie.kind = ASCII_KEYSTROKE_EVENT;
inev.ie.code = keysym;
inev.ie.device
= pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
goto done;
}
@ -5332,6 +5485,9 @@ key_press_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
else
inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
inev.ie.code = keysym & 0xFFFFFF;
inev.ie.device
= pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
goto done;
}
@ -5344,6 +5500,9 @@ key_press_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
? ASCII_KEYSTROKE_EVENT
: MULTIBYTE_CHAR_KEYSTROKE_EVENT);
inev.ie.code = XFIXNAT (c);
inev.ie.device
= pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
goto done;
}
@ -5427,6 +5586,9 @@ key_press_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
key. */
inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT;
inev.ie.code = keysym;
inev.ie.device
= pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
goto done;
}
@ -5478,6 +5640,8 @@ key_press_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
? ASCII_KEYSTROKE_EVENT
: MULTIBYTE_CHAR_KEYSTROKE_EVENT);
inev.ie.code = ch;
inev.ie.device
= pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
evq_enqueue (&inev);
}
@ -5859,7 +6023,8 @@ focus_out_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
another motion event, so we can check again the next time it moves. */
static bool
note_mouse_movement (struct frame *frame, const GdkEventMotion * event)
note_mouse_movement (struct frame *frame,
const GdkEventMotion *event)
{
XRectangle *r;
struct pgtk_display_info *dpyinfo;
@ -5879,6 +6044,9 @@ note_mouse_movement (struct frame *frame, const GdkEventMotion * event)
dpyinfo->last_mouse_scroll_bar = NULL;
note_mouse_highlight (frame, -1, -1);
dpyinfo->last_mouse_glyph_frame = NULL;
frame->last_mouse_device
= pgtk_get_device_for_event (FRAME_DISPLAY_INFO (frame),
(GdkEvent *) event);
return true;
}
@ -5895,6 +6063,9 @@ note_mouse_movement (struct frame *frame, const GdkEventMotion * event)
/* Remember which glyph we're now on. */
remember_mouse_glyph (frame, event->x, event->y, r);
dpyinfo->last_mouse_glyph_frame = frame;
frame->last_mouse_device
= pgtk_get_device_for_event (FRAME_DISPLAY_INFO (frame),
(GdkEvent *) event);
return true;
}
@ -6010,26 +6181,6 @@ motion_notify_event (GtkWidget * widget, GdkEvent * event,
return TRUE;
}
/* Mouse clicks and mouse movement. Rah.
Formerly, we used PointerMotionHintMask (in standard_event_mask)
so that we would have to call XQueryPointer after each MotionNotify
event to ask for another such event. However, this made mouse tracking
slow, and there was a bug that made it eventually stop.
Simply asking for MotionNotify all the time seems to work better.
In order to avoid asking for motion events and then throwing most
of them away or busy-polling the server for mouse positions, we ask
the server for pointer motion hints. This means that we get only
one event per group of mouse movements. "Groups" are delimited by
other kinds of events (focus changes and button clicks, for
example), or by XQueryPointer calls; when one of these happens, we
get another MotionNotify event the next time the mouse moves. This
is at least as efficient as getting motion events when mouse
tracking is on, and I suspect only negligibly worse when tracking
is off. */
/* Prepare a mouse-event in *RESULT for placement in the input queue.
If the event is a button press, then note that we have grabbed
@ -6037,7 +6188,8 @@ motion_notify_event (GtkWidget * widget, GdkEvent * event,
static Lisp_Object
construct_mouse_click (struct input_event *result,
const GdkEventButton * event, struct frame *f)
const GdkEventButton *event,
struct frame *f)
{
/* Make the event type NO_EVENT; we'll change that when we decide
otherwise. */
@ -6052,11 +6204,15 @@ construct_mouse_click (struct input_event *result,
XSETINT (result->y, event->y);
XSETFRAME (result->frame_or_window, f);
result->arg = Qnil;
result->device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f),
(GdkEvent *) event);
return Qnil;
}
static gboolean
button_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
button_event (GtkWidget *widget,
GdkEvent *event,
gpointer *user_data)
{
union buffered_input_event inev;
struct frame *f, *frame;
@ -6175,7 +6331,7 @@ button_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
}
static gboolean
scroll_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
scroll_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data)
{
union buffered_input_event inev;
struct frame *f, *frame;
@ -6207,6 +6363,8 @@ scroll_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
if (gdk_event_is_scroll_stop_event (event))
{
inev.ie.kind = TOUCH_END_EVENT;
inev.ie.device
= pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
evq_enqueue (&inev);
return TRUE;
}
@ -6300,14 +6458,17 @@ scroll_event (GtkWidget * widget, GdkEvent * event, gpointer * user_data)
}
if (inev.ie.kind != NO_EVENT)
evq_enqueue (&inev);
{
inev.ie.device
= pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
evq_enqueue (&inev);
}
return TRUE;
}
static void
drag_data_received (GtkWidget * widget, GdkDragContext * context,
gint x, gint y,
GtkSelectionData * data,
drag_data_received (GtkWidget *widget, GdkDragContext *context,
gint x, gint y, GtkSelectionData *data,
guint info, guint time, gpointer user_data)
{
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)
pgtk_im_init (dpyinfo);
g_signal_connect (G_OBJECT (dpyinfo->gdpy), "seat-added",
G_CALLBACK (pgtk_seat_added_cb), dpyinfo);
g_signal_connect (G_OBJECT (dpyinfo->gdpy), "seat-removed",
G_CALLBACK (pgtk_seat_removed_cb), dpyinfo);
pgtk_enumerate_devices (dpyinfo, true);
unblock_input ();
return dpyinfo;
@ -6749,6 +6916,7 @@ pgtk_delete_display (struct pgtk_display_info *dpyinfo)
tail->next = tail->next->next;
}
pgtk_free_devices (dpyinfo);
xfree (dpyinfo);
}

View File

@ -40,8 +40,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <cairo-svg.h>
#endif
/* could use list to store these, but rest of emacs has a big infrastructure
for managing a table of bitmap "records" */
struct pgtk_bitmap_record
{
void *img;
@ -51,6 +49,15 @@ struct pgtk_bitmap_record
cairo_pattern_t *pattern;
};
struct pgtk_device_t
{
GdkSeat *seat;
GdkDevice *device;
Lisp_Object name;
struct pgtk_device_t *next;
};
#define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b))
#define ARGB_TO_ULONG(a, r, g, b) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
@ -112,8 +119,6 @@ struct scroll_bar
bool horizontal;
};
/* init'd in pgtk_initialize_display_info () */
struct pgtk_display_info
{
/* Chain of all pgtk_display_info structures. */
@ -208,13 +213,14 @@ struct pgtk_display_info
/* The scroll bar in which the last motion event occurred. */
void *last_mouse_scroll_bar;
/* The invisible cursor used for pointer blanking.
Unused if this display supports Xfixes extension. */
/* The invisible cursor used for pointer blanking. */
Emacs_Cursor invisible_cursor;
/* The GDK cursor for scroll bars and popup menus. */
GdkCursor *xg_cursor;
/* List of all devices for all seats on this display. */
struct pgtk_device_t *devices;
/* The frame where the mouse was last time we reported a mouse position. */
struct frame *last_mouse_glyph_frame;
@ -225,7 +231,7 @@ struct pgtk_display_info
/* The last click event. */
GdkEvent *last_click_event;
/* input method */
/* IM context data. */
struct
{
GtkIMContext *context;
@ -246,10 +252,6 @@ extern struct pgtk_display_info *x_display_list;
struct pgtk_output
{
#if 0
void *view;
void *miniimage;
#endif
unsigned long foreground_color;
unsigned long background_color;
void *toolbar;
@ -406,7 +408,7 @@ struct pgtk_output
struct atimer *scale_factor_atimer;
};
/* this dummy decl needed to support TTYs */
/* Satisfy term.c. */
struct x_output
{
int unused;
@ -452,59 +454,8 @@ enum
/* Turning a lisp vector value into a pointer to a struct scroll_bar. */
#define XSCROLL_BAR(vec) ((struct scroll_bar *) XVECTOR (vec))
#define PGTK_FACE_FOREGROUND(f) ((f)->foreground)
#define PGTK_FACE_BACKGROUND(f) ((f)->background)
#define FRAME_DEFAULT_FACE(f) FACE_FROM_ID_OR_NULL (f, DEFAULT_FACE_ID)
/* Compute pixel height of the frame's titlebar. */
#define FRAME_PGTK_TITLEBAR_HEIGHT(f) 0
/* Compute pixel size for vertical scroll bars */
#define PGTK_SCROLL_BAR_WIDTH(f) \
(FRAME_HAS_VERTICAL_SCROLL_BARS (f) \
? rint (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0 \
? FRAME_CONFIG_SCROLL_BAR_WIDTH (f) \
: (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f))) \
: 0)
/* Compute pixel size for horizontal scroll bars */
#define PGTK_SCROLL_BAR_HEIGHT(f) \
(FRAME_HAS_HORIZONTAL_SCROLL_BARS (f) \
? rint (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0 \
? FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) \
: (FRAME_SCROLL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f))) \
: 0)
/* Difference btwn char-column-calculated and actual SB widths.
This is only a concern for rendering when SB on left. */
#define PGTK_SCROLL_BAR_ADJUST(w, f) \
(WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w) ? \
(FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f) \
- PGTK_SCROLL_BAR_WIDTH (f)) : 0)
/* Difference btwn char-line-calculated and actual SB heights.
This is only a concern for rendering when SB on top. */
#define PGTK_SCROLL_BAR_ADJUST_HORIZONTALLY(w, f) \
(WINDOW_HAS_HORIZONTAL_SCROLL_BARS (w) ? \
(FRAME_SCROLL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f) \
- PGTK_SCROLL_BAR_HEIGHT (f)) : 0)
#define FRAME_MENUBAR_HEIGHT(f) (FRAME_X_OUTPUT (f)->menubar_height)
/* Calculate system coordinates of the left and top of the parent
window or, if there is no parent window, the screen. */
#define PGTK_PARENT_WINDOW_LEFT_POS(f) \
(FRAME_PARENT_FRAME (f) != NULL \
? [[FRAME_PGTK_VIEW (f) window] parentWindow].frame.origin.x : 0)
#define PGTK_PARENT_WINDOW_TOP_POS(f) \
(FRAME_PARENT_FRAME (f) != NULL \
? ([[FRAME_PGTK_VIEW (f) window] parentWindow].frame.origin.y \
+ [[FRAME_PGTK_VIEW (f) window] parentWindow].frame.size.height \
- FRAME_PGTK_TITLEBAR_HEIGHT (FRAME_PARENT_FRAME (f))) \
: [[[PGTKScreen screepgtk] objectAtIndex: 0] frame].size.height)
#define FRAME_PGTK_FONT_TABLE(f) (FRAME_DISPLAY_INFO (f)->font_table)
#define FRAME_TOOLBAR_TOP_HEIGHT(f) ((f)->output_data.pgtk->toolbar_top_height)
#define FRAME_TOOLBAR_BOTTOM_HEIGHT(f) \
((f)->output_data.pgtk->toolbar_bottom_height)