]> git.eshelyaron.com Git - emacs.git/commitdiff
Implement function for sending events to widgets
authorPo Lu <luangruo@yahoo.com>
Thu, 4 Nov 2021 10:51:28 +0000 (18:51 +0800)
committerLars Ingebrigtsen <larsi@gnus.org>
Sun, 7 Nov 2021 01:59:40 +0000 (02:59 +0100)
* doc/lispref/display.texi (Xwidgets): Document changes.
* src/keyboard.c (lispy_function_keys): Make non-static on X.
* src/keyboard.h (lispy_function_keys): Expose lispy_function_keys on
X.
* src/xterm.c (x_emacs_to_x_modifiers): Export function.
* src/xterm.h (x_emacs_to_x_modifiers): Likewise.
* src/xwidget.c (Fxwidget_perform_lispy_event)
(find_suitable_keyboard): New functions.
(syms_of_xwidget): Define new subr.

doc/lispref/display.texi
src/keyboard.c
src/keyboard.h
src/xterm.c
src/xterm.h
src/xwidget.c

index 22528a1b0fd032800b220e20f0c6898b10ff116c..eab2c56dffab84202c2ca2626daa843558df5e3b 100644 (file)
@@ -6878,6 +6878,21 @@ This function returns the current setting of @var{xwidget}s
 query-on-exit flag, either @code{t} or @code{nil}.
 @end defun
 
+@defun xwidget-perform-lispy-event xwidget event frame
+Send an input event @var{event} to @var{xwidget}.  The precise action
+performed is platform-specific.  See @ref{Input Events}.
+
+You can optionally pass the frame the event was generated from via
+@var{frame}.  On X11, modifier keys in key events will not be
+considered if @var{frame} is @code{nil}, and the selected frame is not
+an X-Windows frame.
+
+On GTK, only keyboard and function key events are implemented.  Mouse,
+motion, and click events are dispatched to the xwidget without going
+through Lisp code, and as such shouldn't require this function to be
+sent.
+@end defun
+
 @node Buttons
 @section Buttons
 @cindex buttons in buffers
index aa6a4b9e976c3e0f298fa09af154f1e5f899b87f..46dce5755a876a9c31ada71161de76012557bb8d 100644 (file)
@@ -4897,7 +4897,7 @@ static const char *const lispy_kana_keys[] =
 
 /* You'll notice that this table is arranged to be conveniently
    indexed by X Windows keysym values.  */
-static const char *const lispy_function_keys[] =
+const char *const lispy_function_keys[] =
   {
     /* X Keysym value */
 
index 8bdffaa2bff5f08d717ff2767993bc894ac9b464..21c51ec38622c09a68c9770fe17d871e91366c57 100644 (file)
@@ -491,7 +491,7 @@ extern void process_pending_signals (void);
 extern struct timespec timer_check (void);
 extern void mark_kboards (void);
 
-#ifdef HAVE_NTGUI
+#if defined HAVE_NTGUI || defined HAVE_X_WINDOWS
 extern const char *const lispy_function_keys[];
 #endif
 
index 12dad6ae8064adcc9f5ce36562cc5bf5a70e5ff7..fa7dd9b9ca01cf562d3f0c62d61c3ddba6e4273c 100644 (file)
@@ -5087,7 +5087,7 @@ x_x_to_emacs_modifiers (struct x_display_info *dpyinfo, int state)
             | ((state & dpyinfo->hyper_mod_mask)       ? mod_hyper     : 0));
 }
 
-static int
+int
 x_emacs_to_x_modifiers (struct x_display_info *dpyinfo, intmax_t state)
 {
   EMACS_INT mod_ctrl = ctrl_modifier;
@@ -9278,7 +9278,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                            event->xbutton.x, event->xbutton.y,
                            event->xbutton.button, event->xbutton.state,
                            event->xbutton.time);
-
+           goto OTHER;
          }
 #endif
         /* If we decide we want to generate an event to be seen
index de6ea50385ddc1d28c25aab2e49784556f1a9dba..9d9534dd629b157a7c2038d97dbe4afa935bb01f 100644 (file)
@@ -1108,6 +1108,7 @@ extern void x_mouse_leave (struct x_display_info *);
 extern int x_dispatch_event (XEvent *, Display *);
 #endif
 extern int x_x_to_emacs_modifiers (struct x_display_info *, int);
+extern int x_emacs_to_x_modifiers (struct x_display_info *, intmax_t);
 #ifdef USE_CAIRO
 extern void x_cr_destroy_frame_context (struct frame *);
 extern void x_cr_update_surface_desired_size (struct frame *, int, int);
index 5a4cb36ee477a7092557dd42dee390afc6dd5647..ff7d09549bf98d9a831899c3c40051e5270cea88 100644 (file)
@@ -47,7 +47,8 @@ static uint32_t xwidget_counter = 0;
 #ifdef USE_GTK
 static Lisp_Object x_window_to_xwv_map;
 static gboolean offscreen_damage_event (GtkWidget *, GdkEvent *, gpointer);
-static void synthesize_focus_in_event (GtkWidget *offscreen_window);
+static void synthesize_focus_in_event (GtkWidget *);
+static GdkDevice *find_suitable_keyboard (struct frame *);
 #endif
 
 static struct xwidget *
@@ -208,6 +209,88 @@ Returns the newly constructed xwidget, or nil if construction fails.  */)
   return val;
 }
 
+DEFUN ("xwidget-perform-lispy-event",
+       Fxwidget_perform_lispy_event, Sxwidget_perform_lispy_event,
+       2, 3, 0, doc: /* Send a lispy event to XWIDGET.
+EVENT should be the event that will be sent.  FRAME should be the
+frame which generated the event, or nil.  On X11, modifier keys will
+not be processed if FRAME is nil and the selected frame is not an
+X-Windows frame.  */)
+  (Lisp_Object xwidget, Lisp_Object event, Lisp_Object frame)
+{
+  struct xwidget *xw;
+  struct frame *f = NULL;
+  int character = -1, keycode = -1;
+  int modifiers = 0;
+  GdkEvent *xg_event;
+
+  CHECK_XWIDGET (xwidget);
+  xw = XXWIDGET (xwidget);
+
+  if (!NILP (frame))
+    f = decode_window_system_frame (frame);
+  else if (FRAME_X_P (SELECTED_FRAME ()))
+    f = SELECTED_FRAME ();
+
+#ifdef USE_GTK
+  if (RANGED_FIXNUMP (0, event, INT_MAX))
+    {
+      character = XFIXNUM (event);
+      modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f), character);
+    }
+  else if (SYMBOLP (event))
+    {
+      Lisp_Object decoded = parse_modifiers (event);
+      Lisp_Object decoded_name = SYMBOL_NAME (XCAR (decoded));
+      int off = 0;
+      bool found = false;
+
+      while (off < 256)
+       {
+         puts (SSDATA (decoded_name));
+         if (lispy_function_keys[off]
+             && !strcmp (lispy_function_keys[off],
+                         SSDATA (decoded_name)))
+           {
+             found = true;
+             break;
+           }
+         ++off;
+       }
+
+      if (found)
+       keycode = off + 0xff00;
+    }
+
+  if (character == -1 && keycode == -1)
+    return Qnil;
+
+  block_input ();
+  xg_event = gdk_event_new (GDK_KEY_PRESS);
+  xg_event->any.window = gtk_widget_get_window (xw->widget_osr);
+  g_object_ref (xg_event->any.window);
+
+  if (character > -1)
+    xg_event->key.keyval = gdk_unicode_to_keyval (character & ~(1 << 21));
+  else if (keycode > -1)
+    xg_event->key.keyval = keycode;
+
+  xg_event->key.state = modifiers;
+
+  if (f)
+    gdk_event_set_device (xg_event,
+                         find_suitable_keyboard (SELECTED_FRAME ()));
+
+  gtk_main_do_event (xg_event);
+  xg_event->type = GDK_KEY_RELEASE;
+  gtk_main_do_event (xg_event);
+  gdk_event_free (xg_event);
+  unblock_input ();
+#endif
+
+  return Qnil;
+}
+
 DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets, Sget_buffer_xwidgets,
        1, 1, 0,
        doc: /* Return a list of xwidgets associated with BUFFER.
@@ -265,6 +348,18 @@ find_suitable_pointer (struct frame *f)
   return gdk_seat_get_pointer (seat);
 }
 
+static GdkDevice *
+find_suitable_keyboard (struct frame *f)
+{
+  GdkSeat *seat = gdk_display_get_default_seat
+    (gtk_widget_get_display (FRAME_GTK_WIDGET (f)));
+
+  if (!seat)
+    return NULL;
+
+  return gdk_seat_get_keyboard (seat);
+}
+
 static void
 xwidget_button_1 (struct xwidget_view *view,
                  bool down_p, int x, int y, int button,
@@ -1382,6 +1477,7 @@ syms_of_xwidget (void)
   defsubr (&Sxwidget_plist);
   defsubr (&Sxwidget_buffer);
   defsubr (&Sset_xwidget_plist);
+  defsubr (&Sxwidget_perform_lispy_event);
 
   DEFSYM (QCxwidget, ":xwidget");
   DEFSYM (QCtitle, ":title");