#include <X11/extensions/Xdbe.h>
#endif
-#ifdef HAVE_XINPUT2
-#include <X11/extensions/XInput2.h>
-#endif
-
/* Load sys/types.h if not already loaded.
In some systems loading it twice is suicidal. */
#ifndef makedev
static void x_check_fullscreen (struct frame *);
static void x_check_expected_move (struct frame *, int, int);
static void x_sync_with_move (struct frame *, int, int, bool);
-#ifndef HAVE_XINPUT2
static int handle_one_xevent (struct x_display_info *,
const XEvent *, int *,
struct input_event *);
-#else
-static int handle_one_xevent (struct x_display_info *,
- XEvent *, int *,
- struct input_event *);
-#endif
#if ! (defined USE_X_TOOLKIT || defined USE_MOTIF) && defined USE_GTK
static int x_dispatch_event (XEvent *, Display *);
#endif
dpyinfo->ext_codes = ext_codes;
}
-
-#ifdef HAVE_XINPUT2
-
-/* Free all XI2 devices on dpyinfo. */
-static void
-x_free_xi_devices (struct x_display_info *dpyinfo)
-{
- block_input ();
-
- if (dpyinfo->num_devices)
- {
- for (int i = 0; i < dpyinfo->num_devices; ++i)
- xfree (dpyinfo->devices[i].valuators);
-
- xfree (dpyinfo->devices);
- dpyinfo->devices = NULL;
- dpyinfo->num_devices = 0;
- }
-
- unblock_input ();
-}
-
-/* Setup valuator tracking for XI2 master devices on
- DPYINFO->display. */
-
-static void
-x_init_master_valuators (struct x_display_info *dpyinfo)
-{
- int ndevices;
- XIDeviceInfo *infos;
-
- block_input ();
- x_free_xi_devices (dpyinfo);
- infos = XIQueryDevice (dpyinfo->display,
- XIAllMasterDevices,
- &ndevices);
-
- if (!ndevices)
- {
- XIFreeDeviceInfo (infos);
- unblock_input ();
- return;
- }
-
- int actual_devices = 0;
- dpyinfo->devices = xmalloc (sizeof *dpyinfo->devices * ndevices);
-
- for (int i = 0; i < ndevices; ++i)
- {
- XIDeviceInfo *device = &infos[i];
-
- if (device->enabled)
- {
- int actual_valuator_count = 0;
- struct xi_device_t *xi_device =
- &dpyinfo->devices[actual_devices++];
- xi_device->device_id = device->deviceid;
- xi_device->valuators =
- xmalloc (sizeof *xi_device->valuators * device->num_classes);
-
- for (int c = 0; c < device->num_classes; ++c)
- {
- switch (device->classes[c]->type)
- {
-#ifdef XIScrollClass /* XInput 2.1 */
- case XIScrollClass:
- {
- XIScrollClassInfo *info =
- (XIScrollClassInfo *) device->classes[c];
- struct xi_scroll_valuator_t *valuator =
- &xi_device->valuators[actual_valuator_count++];
-
- valuator->horizontal = (info->scroll_type == XIScrollTypeHorizontal);
- valuator->invalid_p = true;
- valuator->emacs_value = DBL_MIN;
- valuator->increment = info->increment;
- valuator->number = info->number;
- break;
- }
-#endif
- default:
- break;
- }
- }
- xi_device->scroll_valuator_count = actual_valuator_count;
- }
- }
-
- dpyinfo->num_devices = actual_devices;
- XIFreeDeviceInfo (infos);
- unblock_input ();
-}
-
-/* Return the delta of the scroll valuator VALUATOR_NUMBER under
- DEVICE_ID in the display DPYINFO with VALUE. The valuator's
- valuator will be set to VALUE afterwards. In case no scroll
- valuator is found, or if device_id is not known to Emacs, DBL_MAX
- is returned. Otherwise, the valuator is returned in
- VALUATOR_RETURN. */
-static double
-x_get_scroll_valuator_delta (struct x_display_info *dpyinfo, int device_id,
- int valuator_number, double value,
- struct xi_scroll_valuator_t **valuator_return)
-{
- block_input ();
-
- for (int i = 0; i < dpyinfo->num_devices; ++i)
- {
- struct xi_device_t *device = &dpyinfo->devices[i];
-
- if (device->device_id == device_id)
- {
- for (int j = 0; j < device->scroll_valuator_count; ++j)
- {
- struct xi_scroll_valuator_t *sv = &device->valuators[j];
-
- if (sv->number == valuator_number)
- {
- if (sv->invalid_p)
- {
- sv->current_value = value;
- sv->invalid_p = false;
- *valuator_return = sv;
-
- unblock_input ();
- return 0.0;
- }
- else
- {
- double delta = sv->current_value - value;
- sv->current_value = value;
- *valuator_return = sv;
-
- unblock_input ();
- return delta / sv->increment;
- }
- }
- }
-
- unblock_input ();
- return DBL_MAX;
- }
- }
-
- unblock_input ();
- return DBL_MAX;
-}
-
-#endif
-
void
x_cr_destroy_frame_context (struct frame *f)
{
x_menubar_window_to_frame (struct x_display_info *dpyinfo,
const XEvent *event)
{
- Window wdesc;
-#ifdef HAVE_XINPUT2
- if (event->type == GenericEvent
- && dpyinfo->supports_xi2
- && (event->xcookie.evtype == XI_ButtonPress
- || event->xcookie.evtype == XI_ButtonRelease))
- wdesc = ((XIDeviceEvent *) event->xcookie.data)->event;
- else
-#endif
- wdesc = event->xany.window;
+ Window wdesc = event->xany.window;
Lisp_Object tail, frame;
struct frame *f;
struct x_output *x;
}
break;
-#ifdef HAVE_XINPUT2
- case GenericEvent:
- {
- XIEvent *xi_event = (XIEvent *) event;
-
- struct frame *focus_frame = dpyinfo->x_focus_event_frame;
- int focus_state
- = focus_frame ? focus_frame->output_data.x->focus_state : 0;
-
- if (!((xi_event->evtype == XI_Enter
- || xi_event->evtype == XI_Leave)
- && (focus_state & FOCUS_EXPLICIT)))
- x_focus_changed ((xi_event->evtype == XI_Enter
- || xi_event->evtype == XI_FocusIn
- ? FocusIn : FocusOut),
- (xi_event->evtype == XI_Enter
- || xi_event->evtype == XI_Leave
- ? FOCUS_IMPLICIT : FOCUS_EXPLICIT),
- dpyinfo, frame, bufp);
- break;
- }
-#endif
-
case FocusIn:
case FocusOut:
/* Ignore transient focus events from hotkeys, window manager
static int
handle_one_xevent (struct x_display_info *dpyinfo,
-#ifndef HAVE_XINPUT2
const XEvent *event,
-#else
- XEvent *event,
-#endif
int *finish, struct input_event *hold_quit)
{
union buffered_input_event inev;
inev.ie.kind = NO_EVENT;
inev.ie.arg = Qnil;
-#ifdef HAVE_XINPUT2
- if (event->type != GenericEvent)
-#endif
- any = x_any_window_to_frame (dpyinfo, event->xany.window);
-#ifdef HAVE_XINPUT2
- else
- any = NULL;
-#endif
+ any = x_any_window_to_frame (dpyinfo, event->xany.window);
if (any && any->wait_event_type == event->type)
any->wait_event_type = 0; /* Indicates we got it. */
goto OTHER;
case MapNotify:
-#if defined HAVE_XINPUT2 && defined HAVE_GTK3
- if (xg_is_menu_window (dpyinfo->display, event->xmap.window))
- popup_activated_flag = 1;
-#endif
/* We use x_top_window_to_frame because map events can
come for sub-windows and they don't mean that the
frame is visible. */
case DestroyNotify:
xft_settings_event (dpyinfo, event);
break;
-#ifdef HAVE_XINPUT2
- case GenericEvent:
- {
- if (!dpyinfo->supports_xi2)
- goto OTHER;
- if (event->xgeneric.extension != dpyinfo->xi2_opcode)
- /* Not an XI2 event. */
- goto OTHER;
- bool must_free_data = false;
- XIEvent *xi_event = (XIEvent *) event->xcookie.data;
- /* Sometimes the event is already claimed by GTK, which
- will free its data in due course. */
- if (!xi_event && XGetEventData (dpyinfo->display, &event->xcookie))
- {
- must_free_data = true;
- xi_event = (XIEvent *) event->xcookie.data;
- }
-
- XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
- XILeaveEvent *leave = (XILeaveEvent *) xi_event;
- XIEnterEvent *enter = (XIEnterEvent *) xi_event;
- XIFocusInEvent *focusin = (XIFocusInEvent *) xi_event;
- XIFocusOutEvent *focusout = (XIFocusOutEvent *) xi_event;
- XIValuatorState *states;
- double *values;
- bool found_valuator = false;
-
- /* A fake XMotionEvent for x_note_mouse_movement. */
- XMotionEvent ev;
- /* A fake XButtonEvent for x_construct_mouse_click. */
- XButtonEvent bv;
-
- if (!xi_event)
- {
- eassert (!must_free_data);
- goto OTHER;
- }
-
- switch (event->xcookie.evtype)
- {
- case XI_FocusIn:
- any = x_any_window_to_frame (dpyinfo, focusin->event);
-#ifndef USE_GTK
- /* Some WMs (e.g. Mutter in Gnome Shell), don't unmap
- minimized/iconified windows; thus, for those WMs we won't get
- a MapNotify when unminimizing/deconifying. Check here if we
- are deiconizing a window (Bug42655).
-
- But don't do that on GTK since it may cause a plain invisible
- frame get reported as iconified, compare
- https://lists.gnu.org/archive/html/emacs-devel/2017-02/msg00133.html.
- That is fixed above but bites us here again. */
- f = any;
- if (f && FRAME_ICONIFIED_P (f))
- {
- SET_FRAME_VISIBLE (f, 1);
- SET_FRAME_ICONIFIED (f, false);
- f->output_data.x->has_been_visible = true;
- inev.ie.kind = DEICONIFY_EVENT;
- XSETFRAME (inev.ie.frame_or_window, f);
- }
-#endif /* USE_GTK */
- x_detect_focus_change (dpyinfo, any, event, &inev.ie);
- goto XI_OTHER;
- case XI_FocusOut:
- any = x_any_window_to_frame (dpyinfo, focusout->event);
- x_detect_focus_change (dpyinfo, any, event, &inev.ie);
- goto XI_OTHER;
- case XI_Enter:
- any = x_any_window_to_frame (dpyinfo, enter->event);
- ev.x = lrint (enter->event_x);
- ev.y = lrint (enter->event_y);
- ev.window = leave->event;
-
- x_display_set_last_user_time (dpyinfo, xi_event->time);
- x_detect_focus_change (dpyinfo, any, event, &inev.ie);
- f = any;
-
- if (f && x_mouse_click_focus_ignore_position)
- ignore_next_mouse_click_timeout = xi_event->time + 200;
-
- /* EnterNotify counts as mouse movement,
- so update things that depend on mouse position. */
- if (f && !f->output_data.x->hourglass_p)
- x_note_mouse_movement (f, &ev);
-#ifdef USE_GTK
- /* We may get an EnterNotify on the buttons in the toolbar. In that
- case we moved out of any highlighted area and need to note this. */
- if (!f && dpyinfo->last_mouse_glyph_frame)
- x_note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &ev);
-#endif
- goto XI_OTHER;
- case XI_Leave:
- ev.x = lrint (leave->event_x);
- ev.y = lrint (leave->event_y);
- ev.window = leave->event;
- any = x_any_window_to_frame (dpyinfo, leave->event);
-
- x_display_set_last_user_time (dpyinfo, xi_event->time);
- x_detect_focus_change (dpyinfo, any, event, &inev.ie);
-
- f = x_top_window_to_frame (dpyinfo, leave->event);
- if (f)
- {
- if (f == hlinfo->mouse_face_mouse_frame)
- {
- /* If we move outside the frame, then we're
- certainly no longer on any text in the frame. */
- clear_mouse_face (hlinfo);
- hlinfo->mouse_face_mouse_frame = 0;
- }
-
- /* Generate a nil HELP_EVENT to cancel a help-echo.
- Do it only if there's something to cancel.
- Otherwise, the startup message is cleared when
- the mouse leaves the frame. */
- if (any_help_event_p)
- do_help = -1;
- }
-#ifdef USE_GTK
- /* See comment in EnterNotify above */
- else if (dpyinfo->last_mouse_glyph_frame)
- x_note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &ev);
-#endif
- goto XI_OTHER;
- case XI_Motion:
- /* First test if there is some kind of scroll event
- here! */
- states = &xev->valuators;
- values = states->values;
-
- x_display_set_last_user_time (dpyinfo, xi_event->time);
-
- for (int i = 0; i < states->mask_len * 8; i++)
- {
- if (XIMaskIsSet (states->mask, i))
- {
- block_input ();
-
- struct xi_scroll_valuator_t *val;
- double delta =
- x_get_scroll_valuator_delta (dpyinfo, xev->deviceid,
- i, *values, &val);
-
- if (delta != DBL_MAX)
- {
- /* TODO: Figure out how pixelwise scrolling should work.
- Until that happens, this will have to do. */
- delta *= 10;
-
- f = mouse_or_wdesc_frame (dpyinfo, xev->event);
- found_valuator = true;
- if (signbit (delta) != signbit (val->emacs_value))
- val->emacs_value = DBL_MIN;
-
- val->emacs_value += delta;
-
- if (!f)
- {
- f = x_any_window_to_frame (dpyinfo, xev->event);
-
- if (!f)
- {
- unblock_input ();
- goto XI_OTHER;
- }
- }
-
- if ((val->horizontal
- && fabs (val->emacs_value) >= FRAME_COLUMN_WIDTH (f))
- || (!val->horizontal
- && fabs (val->emacs_value) >= FRAME_LINE_HEIGHT (f)))
- {
- Lisp_Object tab_bar_arg = Qnil;
- bool tab_bar_p = false;
- bool tool_bar_p = false;
- bool s = signbit (val->emacs_value);
-
- bv.button = !val->horizontal ? (s ? 5 : 4) : (s ? 7 : 6);
- bv.type = ButtonPress;
-
- bv.x = lrint (xev->event_x);
- bv.y = lrint (xev->event_y);
- bv.window = xev->event;
- bv.state = xev->mods.base
- | xev->mods.effective
- | xev->mods.latched
- | xev->mods.locked;
-
- /* Is this in the tab-bar? */
- if (WINDOWP (f->tab_bar_window)
- && WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)))
- {
- Lisp_Object window;
- int x = bv.x;
- int y = bv.y;
-
- window = window_from_coordinates (f, x, y, 0, true, true);
- tab_bar_p = EQ (window, f->tab_bar_window);
-
- if (tab_bar_p)
- {
- tab_bar_arg = handle_tab_bar_click
- (f, x, y, true, x_x_to_emacs_modifiers (dpyinfo, bv.state));
- tab_bar_arg = handle_tab_bar_click
- (f, x, y, false, x_x_to_emacs_modifiers (dpyinfo, bv.state));
- }
- }
-
- if (!NILP (tab_bar_arg))
- inev.ie.arg = tab_bar_arg;
-
- if (!tool_bar_p && !(NILP (tab_bar_arg) && tab_bar_p))
- {
- if (ignore_next_mouse_click_timeout)
- {
- if (xev->time > ignore_next_mouse_click_timeout)
- {
- /* XXX: Wouldn't it be better
- to just use wheel events
- instead of pretending to be
- X here? */
- x_construct_mouse_click (&inev.ie, &bv, f);
- if (!NILP (tab_bar_arg))
- inev.ie.arg = tab_bar_arg;
- kbd_buffer_store_event (&inev.ie);
- inev.ie.modifiers &= ~down_modifier;
- inev.ie.modifiers |= up_modifier;
- kbd_buffer_store_event (&inev.ie);
- }
- ignore_next_mouse_click_timeout = 0;
- }
- else
- {
- x_construct_mouse_click (&inev.ie, &bv, f);
- kbd_buffer_store_event (&inev.ie);
- inev.ie.modifiers &= ~down_modifier;
- inev.ie.modifiers |= up_modifier;
- kbd_buffer_store_event (&inev.ie);
- }
- }
-
- val->emacs_value = DBL_MIN;
- }
- }
- unblock_input ();
- values++;
- }
-
- inev.ie.kind = NO_EVENT;
- }
-
- if (found_valuator)
- goto XI_OTHER;
-
- ev.x = lrint (xev->event_x);
- ev.y = lrint (xev->event_y);
- ev.window = xev->event;
-
- previous_help_echo_string = help_echo_string;
- help_echo_string = Qnil;
-
- if (hlinfo->mouse_face_hidden)
- {
- hlinfo->mouse_face_hidden = false;
- clear_mouse_face (hlinfo);
- }
-
- f = mouse_or_wdesc_frame (dpyinfo, xev->event);
-
-#ifdef USE_GTK
- if (f && xg_event_is_for_scrollbar (f, event))
- f = 0;
-#endif
- if (f)
- {
- /* Maybe generate a SELECT_WINDOW_EVENT for
- `mouse-autoselect-window' but don't let popup menus
- interfere with this (Bug#1261). */
- if (!NILP (Vmouse_autoselect_window)
- && !popup_activated ()
- /* Don't switch if we're currently in the minibuffer.
- This tries to work around problems where the
- minibuffer gets unselected unexpectedly, and where
- you then have to move your mouse all the way down to
- the minibuffer to select it. */
- && !MINI_WINDOW_P (XWINDOW (selected_window))
- /* With `focus-follows-mouse' non-nil create an event
- also when the target window is on another frame. */
- && (f == XFRAME (selected_frame)
- || !NILP (focus_follows_mouse)))
- {
- static Lisp_Object last_mouse_window;
- Lisp_Object window = window_from_coordinates (f, ev.x, ev.y, 0, false, false);
-
- /* A window will be autoselected only when it is not
- selected now and the last mouse movement event was
- not in it. The remainder of the code is a bit vague
- wrt what a "window" is. For immediate autoselection,
- the window is usually the entire window but for GTK
- where the scroll bars don't count. For delayed
- autoselection the window is usually the window's text
- area including the margins. */
- if (WINDOWP (window)
- && !EQ (window, last_mouse_window)
- && !EQ (window, selected_window))
- {
- inev.ie.kind = SELECT_WINDOW_EVENT;
- inev.ie.frame_or_window = window;
- }
-
- /* Remember the last window where we saw the mouse. */
- last_mouse_window = window;
- }
-
- if (!x_note_mouse_movement (f, &ev))
- help_echo_string = previous_help_echo_string;
- }
- else
- {
-#ifndef USE_TOOLKIT_SCROLL_BARS
- struct scroll_bar *bar
- = x_window_to_scroll_bar (xi_event->display, xev->event, 2);
-
- if (bar)
- x_scroll_bar_note_movement (bar, &ev);
-#endif /* USE_TOOLKIT_SCROLL_BARS */
-
- /* If we move outside the frame, then we're
- certainly no longer on any text in the frame. */
- clear_mouse_face (hlinfo);
- }
-
- /* If the contents of the global variable help_echo_string
- has changed, generate a HELP_EVENT. */
- if (!NILP (help_echo_string)
- || !NILP (previous_help_echo_string))
- do_help = 1;
- goto XI_OTHER;
- case XI_ButtonRelease:
- case XI_ButtonPress:
- {
- /* If we decide we want to generate an event to be seen
- by the rest of Emacs, we put it here. */
- Lisp_Object tab_bar_arg = Qnil;
- bool tab_bar_p = false;
- bool tool_bar_p = false;
-
- /* Ignore emulated scroll events when XI2 native
- scroll events are present. */
- if (dpyinfo->xi2_version >= 1 && xev->detail >= 4
- && xev->detail <= 8)
- goto XI_OTHER;
-
- bv.button = xev->detail;
- bv.type = xev->evtype == XI_ButtonPress ? ButtonPress : ButtonRelease;
- bv.x = lrint (xev->event_x);
- bv.y = lrint (xev->event_y);
- bv.window = xev->event;
- bv.state = xev->mods.base
- | xev->mods.effective
- | xev->mods.latched
- | xev->mods.locked;
-
- memset (&compose_status, 0, sizeof (compose_status));
- dpyinfo->last_mouse_glyph_frame = NULL;
- x_display_set_last_user_time (dpyinfo, xev->time);
-
- f = mouse_or_wdesc_frame (dpyinfo, xev->event);
-
- if (f && xev->evtype == XI_ButtonPress
- && !popup_activated ()
- && !x_window_to_scroll_bar (xev->display, xev->event, 2)
- && !FRAME_NO_ACCEPT_FOCUS (f))
- {
- /* When clicking into a child frame or when clicking
- into a parent frame with the child frame selected and
- `no-accept-focus' is not set, select the clicked
- frame. */
- struct frame *hf = dpyinfo->highlight_frame;
-
- if (FRAME_PARENT_FRAME (f) || (hf && frame_ancestor_p (f, hf)))
- {
- block_input ();
- XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
- RevertToParent, CurrentTime);
- if (FRAME_PARENT_FRAME (f))
- XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
- unblock_input ();
- }
- }
-
-#ifdef USE_GTK
- if (f && xg_event_is_for_scrollbar (f, event))
- f = 0;
-#endif
-
- if (f)
- {
- /* Is this in the tab-bar? */
- if (WINDOWP (f->tab_bar_window)
- && WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)))
- {
- Lisp_Object window;
- int x = bv.x;
- int y = bv.y;
-
- window = window_from_coordinates (f, x, y, 0, true, true);
- tab_bar_p = EQ (window, f->tab_bar_window);
-
- if (tab_bar_p)
- tab_bar_arg = handle_tab_bar_click
- (f, x, y, xev->evtype == XI_ButtonPress,
- x_x_to_emacs_modifiers (dpyinfo, bv.state));
- }
-
-#if ! defined (USE_GTK)
- /* Is this in the tool-bar? */
- if (WINDOWP (f->tool_bar_window)
- && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
- {
- Lisp_Object window;
- int x = bv.x;
- int y = bv.y;
-
- window = window_from_coordinates (f, x, y, 0, true, true);
- tool_bar_p = EQ (window, f->tool_bar_window);
-
- if (tool_bar_p && xev->detail < 4)
- handle_tool_bar_click
- (f, x, y, xev->evtype == XI_ButtonPress,
- x_x_to_emacs_modifiers (dpyinfo, bv.state));
- }
-#endif /* !USE_GTK */
-
- if (!(tab_bar_p && NILP (tab_bar_arg)) && !tool_bar_p)
-#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
- if (! popup_activated ())
-#endif
- {
- if (ignore_next_mouse_click_timeout)
- {
- if (xev->evtype == XI_ButtonPress
- && xev->time > ignore_next_mouse_click_timeout)
- {
- ignore_next_mouse_click_timeout = 0;
- x_construct_mouse_click (&inev.ie, &bv, f);
- }
- if (xev->evtype == XI_ButtonRelease)
- ignore_next_mouse_click_timeout = 0;
- }
- else
- x_construct_mouse_click (&inev.ie, &bv, f);
-
- if (!NILP (tab_bar_arg))
- inev.ie.arg = tab_bar_arg;
- }
- if (FRAME_X_EMBEDDED_P (f))
- xembed_send_message (f, xev->time,
- XEMBED_REQUEST_FOCUS, 0, 0, 0);
- }
-
- if (xev->evtype == XI_ButtonPress)
- {
- dpyinfo->grabbed |= (1 << xev->detail);
- dpyinfo->last_mouse_frame = f;
- if (f && !tab_bar_p)
- f->last_tab_bar_item = -1;
-#if ! defined (USE_GTK)
- if (f && !tool_bar_p)
- f->last_tool_bar_item = -1;
-#endif /* not USE_GTK */
-
- }
- else
- dpyinfo->grabbed &= ~(1 << xev->detail);
-
- if (f)
- f->mouse_moved = false;
-
-#if defined (USE_GTK)
- /* No Xt toolkit currently available has support for XI2.
- So the code here assumes use of GTK. */
- f = x_menubar_window_to_frame (dpyinfo, event);
- if (f /* Gtk+ menus only react to the first three buttons. */
- && xev->detail < 3)
- {
- /* What is done with Core Input ButtonPressed is not
- possible here, because GenericEvents cannot be saved. */
- bool was_waiting_for_input = waiting_for_input;
- /* This hack was adopted from the NS port. Whether
- or not it is actually safe is a different story
- altogether. */
- if (waiting_for_input)
- waiting_for_input = 0;
- set_frame_menubar (f, true);
- waiting_for_input = was_waiting_for_input;
- }
-#endif
- goto XI_OTHER;
- }
- case XI_KeyPress:
- {
- int state = xev->mods.base
- | xev->mods.effective
- | xev->mods.latched
- | xev->mods.locked;
- Lisp_Object c;
-#ifdef HAVE_XKB
- unsigned int mods_rtrn;
-#endif
- int keycode = xev->detail;
- KeySym keysym;
- char copy_buffer[81];
- char *copy_bufptr = copy_buffer;
- unsigned char *copy_ubufptr;
-#ifdef HAVE_XKB
- int copy_bufsiz = sizeof (copy_buffer);
-#endif
- ptrdiff_t i;
- int nchars, len;
-
-#ifdef HAVE_XKB
- if (dpyinfo->xkb_desc)
- {
- if (!XkbTranslateKeyCode (dpyinfo->xkb_desc, keycode,
- state, &mods_rtrn, &keysym))
- goto XI_OTHER;
- }
- else
- {
-#endif
- int keysyms_per_keycode_return;
- KeySym *ksms = XGetKeyboardMapping (dpyinfo->display, keycode, 1,
- &keysyms_per_keycode_return);
- if (!(keysym = ksms[0]))
- {
- XFree (ksms);
- goto XI_OTHER;
- }
- XFree (ksms);
-#ifdef HAVE_XKB
- }
-#endif
-
- if (keysym == NoSymbol)
- goto XI_OTHER;
-
- x_display_set_last_user_time (dpyinfo, xev->time);
- ignore_next_mouse_click_timeout = 0;
-
-#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
- /* Dispatch XI_KeyPress events when in menu. */
- if (popup_activated ())
- goto XI_OTHER;
-#endif
-
- f = x_any_window_to_frame (dpyinfo, xev->event);
-
- /* If mouse-highlight is an integer, input clears out
- mouse highlighting. */
- if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight)
- && (f == 0
-#if ! defined (USE_GTK)
- || !EQ (f->tool_bar_window, hlinfo->mouse_face_window)
-#endif
- || !EQ (f->tab_bar_window, hlinfo->mouse_face_window))
- )
- {
- clear_mouse_face (hlinfo);
- hlinfo->mouse_face_hidden = true;
- }
-
- if (f != 0)
- {
-#ifdef USE_GTK
- /* Don't pass keys to GTK. A Tab will shift focus to the
- tool bar in GTK 2.4. Keys will still go to menus and
- dialogs because in that case popup_activated is nonzero
- (see above). */
- *finish = X_EVENT_DROP;
-#endif
- /* If not using XIM/XIC, and a compose sequence is in progress,
- we break here. Otherwise, chars_matched is always 0. */
- if (compose_status.chars_matched > 0 && nbytes == 0)
- goto XI_OTHER;
-
- memset (&compose_status, 0, sizeof (compose_status));
-
- XSETFRAME (inev.ie.frame_or_window, f);
- inev.ie.modifiers
- = x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), state);
- inev.ie.timestamp = xev->time;
-
- /* First deal with keysyms which have defined
- translations to characters. */
- if (keysym >= 32 && keysym < 128)
- /* Avoid explicitly decoding each ASCII character. */
- {
- inev.ie.kind = ASCII_KEYSTROKE_EVENT;
- inev.ie.code = keysym;
-
- goto xi_done_keysym;
- }
-
- /* Keysyms directly mapped to Unicode characters. */
- if (keysym >= 0x01000000 && keysym <= 0x0110FFFF)
- {
- if (keysym < 0x01000080)
- inev.ie.kind = ASCII_KEYSTROKE_EVENT;
- else
- inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
- inev.ie.code = keysym & 0xFFFFFF;
- goto xi_done_keysym;
- }
-
- /* Now non-ASCII. */
- if (HASH_TABLE_P (Vx_keysym_table)
- && (c = Fgethash (make_fixnum (keysym),
- Vx_keysym_table,
- Qnil),
- FIXNATP (c)))
- {
- inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c))
- ? ASCII_KEYSTROKE_EVENT
- : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
- inev.ie.code = XFIXNAT (c);
- goto xi_done_keysym;
- }
-
- /* Random non-modifier sorts of keysyms. */
- if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
- || keysym == XK_Delete
-#ifdef XK_ISO_Left_Tab
- || (keysym >= XK_ISO_Left_Tab
- && keysym <= XK_ISO_Enter)
-#endif
- || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
- || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
-#ifdef HPUX
- /* This recognizes the "extended function
- keys". It seems there's no cleaner way.
- Test IsModifierKey to avoid handling
- mode_switch incorrectly. */
- || (XK_Select <= keysym && keysym < XK_KP_Space)
-#endif
-#ifdef XK_dead_circumflex
- || keysym == XK_dead_circumflex
-#endif
-#ifdef XK_dead_grave
- || keysym == XK_dead_grave
-#endif
-#ifdef XK_dead_tilde
- || keysym == XK_dead_tilde
-#endif
-#ifdef XK_dead_diaeresis
- || keysym == XK_dead_diaeresis
-#endif
-#ifdef XK_dead_macron
- || keysym == XK_dead_macron
-#endif
-#ifdef XK_dead_degree
- || keysym == XK_dead_degree
-#endif
-#ifdef XK_dead_acute
- || keysym == XK_dead_acute
-#endif
-#ifdef XK_dead_cedilla
- || keysym == XK_dead_cedilla
-#endif
-#ifdef XK_dead_breve
- || keysym == XK_dead_breve
-#endif
-#ifdef XK_dead_ogonek
- || keysym == XK_dead_ogonek
-#endif
-#ifdef XK_dead_caron
- || keysym == XK_dead_caron
-#endif
-#ifdef XK_dead_doubleacute
- || keysym == XK_dead_doubleacute
-#endif
-#ifdef XK_dead_abovedot
- || keysym == XK_dead_abovedot
-#endif
- || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
- || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
- /* Any "vendor-specific" key is ok. */
- || (keysym & (1 << 28))
- || (keysym != NoSymbol && nbytes == 0))
- && ! (IsModifierKey (keysym)
- /* The symbols from XK_ISO_Lock
- to XK_ISO_Last_Group_Lock
- don't have real modifiers but
- should be treated similarly to
- Mode_switch by Emacs. */
-#if defined XK_ISO_Lock && defined XK_ISO_Last_Group_Lock
- || (XK_ISO_Lock <= keysym
- && keysym <= XK_ISO_Last_Group_Lock)
-#endif
- ))
- {
- STORE_KEYSYM_FOR_DEBUG (keysym);
- /* make_lispy_event will convert this to a symbolic
- key. */
- inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT;
- inev.ie.code = keysym;
- goto xi_done_keysym;
- }
-
-#ifdef HAVE_XKB
- int overflow = 0;
- KeySym sym = keysym;
-
- if (dpyinfo->xkb_desc)
- {
- if (!(nbytes = XkbTranslateKeySym (dpyinfo->display, &sym,
- state & ~mods_rtrn, copy_bufptr,
- copy_bufsiz, &overflow)))
- goto XI_OTHER;
- }
- else
-#else
- {
- block_input ();
- char *str = XKeysymToString (keysym);
- if (!str)
- {
- unblock_input ();
- goto XI_OTHER;
- }
- nbytes = strlen (str) + 1;
- copy_bufptr = alloca (nbytes);
- strcpy (copy_bufptr, str);
- unblock_input ();
- }
-#endif
-#ifdef HAVE_XKB
- if (overflow)
- {
- overflow = 0;
- copy_bufptr = alloca (copy_bufsiz + overflow);
- keysym = sym;
- if (!(nbytes = XkbTranslateKeySym (dpyinfo->display, &sym,
- state & ~mods_rtrn, copy_bufptr,
- copy_bufsiz + overflow, &overflow)))
- goto XI_OTHER;
-
- if (overflow)
- goto XI_OTHER;
- }
-#endif
-
- for (i = 0, nchars = 0; i < nbytes; i++)
- {
- if (ASCII_CHAR_P (copy_bufptr[i]))
- nchars++;
- STORE_KEYSYM_FOR_DEBUG (copy_bufptr[i]);
- }
-
- if (nchars < nbytes)
- {
- /* Decode the input data. */
-
- setup_coding_system (Vlocale_coding_system, &coding);
- coding.src_multibyte = false;
- coding.dst_multibyte = true;
- /* The input is converted to events, thus we can't
- handle composition. Anyway, there's no XIM that
- gives us composition information. */
- coding.common_flags &= ~CODING_ANNOTATION_MASK;
-
- SAFE_NALLOCA (coding.destination, MAX_MULTIBYTE_LENGTH,
- nbytes);
- coding.dst_bytes = MAX_MULTIBYTE_LENGTH * nbytes;
- coding.mode |= CODING_MODE_LAST_BLOCK;
- decode_coding_c_string (&coding, (unsigned char *) copy_bufptr, nbytes, Qnil);
- nbytes = coding.produced;
- nchars = coding.produced_char;
- copy_bufptr = (char *) coding.destination;
- }
-
- copy_ubufptr = (unsigned char *) copy_bufptr;
-
- /* Convert the input data to a sequence of
- character events. */
- for (i = 0; i < nbytes; i += len)
- {
- int ch;
- if (nchars == nbytes)
- ch = copy_ubufptr[i], len = 1;
- else
- ch = string_char_and_length (copy_ubufptr + i, &len);
- inev.ie.kind = (SINGLE_BYTE_CHAR_P (ch)
- ? ASCII_KEYSTROKE_EVENT
- : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
- inev.ie.code = ch;
- kbd_buffer_store_buffered_event (&inev, hold_quit);
- }
-
- inev.ie.kind = NO_EVENT;
- goto xi_done_keysym;
- }
- goto XI_OTHER;
- }
- case XI_KeyRelease:
- x_display_set_last_user_time (dpyinfo, xev->time);
- goto XI_OTHER;
- case XI_PropertyEvent:
- case XI_HierarchyChanged:
- case XI_DeviceChanged:
- x_init_master_valuators (dpyinfo);
- goto XI_OTHER;
- default:
- goto XI_OTHER;
- }
- xi_done_keysym:
- if (must_free_data)
- XFreeEventData (dpyinfo->display, &event->xcookie);
- goto done_keysym;
- XI_OTHER:
- if (must_free_data)
- XFreeEventData (dpyinfo->display, &event->xcookie);
- goto OTHER;
- }
-#endif
default:
OTHER:
dpyinfo->supports_xdbe = true;
#endif
-#ifdef HAVE_XINPUT2
- dpyinfo->supports_xi2 = false;
- int rc;
- int major = 2;
-#ifdef XI_BarrierHit /* XInput 2.3 */
- int minor = 3;
-#elif defined XI_TouchBegin /* XInput 2.2 */
- int minor = 2;
-#elif defined XIScrollClass /* XInput 1.1 */
- int minor = 1;
-#else /* Some old version of XI2 we're not interested in. */
- int minor = 0;
-#endif
- int fer, fee;
-
- if (XQueryExtension (dpyinfo->display, "XInputExtension",
- &dpyinfo->xi2_opcode, &fer, &fee))
- {
- rc = XIQueryVersion (dpyinfo->display, &major, &minor);
- if (rc == Success)
- {
- dpyinfo->supports_xi2 = true;
- x_init_master_valuators (dpyinfo);
- }
- }
- dpyinfo->xi2_version = minor;
-#endif
-
-#ifdef HAVE_XKB
- dpyinfo->xkb_desc = XkbGetMap (dpyinfo->display,
- XkbAllComponentsMask,
- XkbUseCoreKbd);
-#endif
-
#if defined USE_CAIRO || defined HAVE_XFT
{
/* If we are using Xft, the following precautions should be made:
XrmDestroyDatabase (dpyinfo->rdb);
#endif
-#ifdef HAVE_XKB
- if (dpyinfo->xkb_desc)
- XkbFreeKeyboard (dpyinfo->xkb_desc, XkbAllComponentsMask, True);
-#endif
-#ifdef HAVE_XINPUT2
- if (dpyinfo->supports_xi2)
- x_free_xi_devices (dpyinfo);
-#endif
#ifdef USE_GTK
xg_display_close (dpyinfo->display);
#else
void
init_xterm (void)
{
-#ifndef HAVE_XINPUT2
- /* Emacs can handle only core input events when built without XI2
- support, so make sure Gtk doesn't use Xinput or Xinput2
- extensions. */
+ /* Emacs can handle only core input events, so make sure
+ Gtk doesn't use Xinput or Xinput2 extensions. */
xputenv ("GDK_CORE_DEVICE_EVENTS=1");
-#endif
}
#endif