emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: XInput 2 support (again)


From: Stefan Monnier
Subject: Re: XInput 2 support (again)
Date: Sat, 13 Nov 2021 10:04:04 -0500
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux)

> @@ -3074,6 +3078,35 @@ x_window (struct frame *f, long window_prompting)
>    class_hints.res_class = SSDATA (Vx_resource_class);
>    XSetClassHint (FRAME_X_DISPLAY (f), XtWindow (shell_widget), &class_hints);
>  
> +#ifdef HAVE_XINPUT2
> +  if (FRAME_DISPLAY_INFO (f)->supports_xi2)
> +    {
> +      XIEventMask mask;
> +      ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
> +      unsigned char *m;
> +      mask.mask = m = alloca (l);
> +      memset (m, 0, l);
> +      mask.mask_len = l;
> +      mask.deviceid = XIAllMasterDevices;
> +
> +      XISetMask (m, XI_ButtonPress);
> +      XISetMask (m, XI_ButtonRelease);
> +      XISetMask (m, XI_KeyPress);
> +      XISetMask (m, XI_KeyRelease);
> +      XISetMask (m, XI_Motion);
> +      XISetMask (m, XI_Enter);
> +      XISetMask (m, XI_Leave);
> +      XISetMask (m, XI_FocusIn);
> +      XISetMask (m, XI_FocusOut);
> +      XISetMask (m, XI_PropertyEvent);
> +      XISetMask (m, XI_HierarchyChanged);
> +      XISetMask (m, XI_DeviceChanged);
> +      XISelectEvents (FRAME_X_DISPLAY (f),
> +                   FRAME_X_WINDOW (f),
> +                   &mask, 1);
> +    }
> +#endif
> +
>  #ifdef HAVE_X_I18N
>    FRAME_XIC (f) = NULL;
>    if (use_xim)
> @@ -3254,6 +3287,35 @@ x_window (struct frame *f)
>      }
>  #endif /* HAVE_X_I18N */
>  
> +#ifdef HAVE_XINPUT2
> +  if (FRAME_DISPLAY_INFO (f)->supports_xi2)
> +    {
> +      XIEventMask mask;
> +      ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
> +      unsigned char *m;
> +      mask.mask = m = alloca (l);
> +      memset (m, 0, l);
> +      mask.mask_len = l;
> +      mask.deviceid = XIAllMasterDevices;
> +
> +      XISetMask (m, XI_ButtonPress);
> +      XISetMask (m, XI_ButtonRelease);
> +      XISetMask (m, XI_KeyPress);
> +      XISetMask (m, XI_KeyRelease);
> +      XISetMask (m, XI_Motion);
> +      XISetMask (m, XI_Enter);
> +      XISetMask (m, XI_Leave);
> +      XISetMask (m, XI_FocusIn);
> +      XISetMask (m, XI_FocusOut);
> +      XISetMask (m, XI_PropertyEvent);
> +      XISetMask (m, XI_HierarchyChanged);
> +      XISetMask (m, XI_DeviceChanged);
> +      XISelectEvents (FRAME_X_DISPLAY (f),
> +                   FRAME_X_WINDOW (f),
> +                   &mask, 1);
> +    }
> +#endif
> +

Any reason this isn't consolidated into a separate function to avoid the
code duplication?

> +       struct xi_device_t *xi_device =
> +         &dpyinfo->devices[actual_devices++];

The GNU coding standard encourages to cut lines just *before* infix
operators rather after.  E.g.:

          struct xi_device_t *xi_device
            = &dpyinfo->devices[actual_devices++];

> @@ -9518,6 +9772,833 @@ handle_one_xevent (struct x_display_info *dpyinfo,
>      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)
> +                   {
> +                     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 / val->increment) >= 1)
> +                         || (!val->horizontal
> +                             && fabs (val->emacs_value / val->increment) >= 
> 1))
> +                       {
> +                         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)
> +                                   {
> +                                     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;
> +           struct xi_device_t *device;
> +
> +           /* 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;
> +
> +           device = xi_device_from_id (dpyinfo, xev->deviceid);
> +
> +           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);
> +               device->grab |= (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);
> +               device->grab &= ~(1 << xev->detail);
> +             }
> +
> +           xi_grab_or_ungrab_device (device, dpyinfo, xev->event);
> +
> +           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

That's a damn large chunk of code to add into a function.

A lot of it is copy&pasted from other parts of `handle_one_xevent`.
Please avoid such code duplication (`handle_one_xevent` is already bad
enough from this point of view).

Also the code uses more than 80 columns at various places for no good
reason; that needs to be fixed.


        Stefan




reply via email to

[Prev in Thread] Current Thread [Next in Thread]