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,
}
}
+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
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];
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 *
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;
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);
}
}
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;
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);
{
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;
}
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;
}
? 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;
}
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;
}
? 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);
}
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;
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;
}
/* 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;
}
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
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. */
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;
}
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;
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;
}
}
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));
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;
tail->next = tail->next->next;
}
+ pgtk_free_devices (dpyinfo);
xfree (dpyinfo);
}
#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;
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))
bool horizontal;
};
-
-/* init'd in pgtk_initialize_display_info () */
struct pgtk_display_info
{
/* Chain of all pgtk_display_info structures. */
/* 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;
/* The last click event. */
GdkEvent *last_click_event;
- /* input method */
+ /* IM context data. */
struct
{
GtkIMContext *context;
struct pgtk_output
{
-#if 0
- void *view;
- void *miniimage;
-#endif
unsigned long foreground_color;
unsigned long background_color;
void *toolbar;
struct atimer *scale_factor_atimer;
};
-/* this dummy decl needed to support TTYs */
+/* Satisfy term.c. */
struct x_output
{
int unused;
/* 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)