]> git.eshelyaron.com Git - emacs.git/commitdiff
Support TTY child frames with GPM mouse
authorJared Finder <jared@finder.org>
Tue, 7 Jan 2025 04:52:11 +0000 (20:52 -0800)
committerEshel Yaron <me@eshelyaron.com>
Sat, 11 Jan 2025 11:19:42 +0000 (12:19 +0100)
* lisp/frame.el (x-list-fonts): Delete `frame-at', to move to
C implementation.
* lisp/xt-mouse.el (xterm-mouse-event): Call new `tty-frame-at'.
* src/term.c (tty_frame_at, Ftty_frame_at): New C function,
replacing `frame-at' only for TTYs.
(term_mouse_position): Use last_mouse_frame when it is set.
(handle_one_term_event): Call tty_frame_at to get frame under
mouse, store it in last_mouse_frame.  Alter event coordinates
based on mouse frame.
(syms_of_term): Add tty-frame-at, last_mouse_frame.
* src/termhooks.h: Make Gpm_Event parameter const.

(cherry picked from commit d018a26f9cfb29b166199e88ec6ee84d06733851)

lisp/frame.el
lisp/xt-mouse.el
src/term.c
src/termhooks.h

index d5d132cb6a5c57d51acdadac33c33586a7a207fe..eefa64119619fdcc2f47b461d23049e70a9b119c 100644 (file)
@@ -1506,13 +1506,6 @@ FRAME defaults to the selected frame."
   (let ((edges (frame-edges frame 'outer-edges)))
     (- (nth 3 edges) (nth 1 edges))))
 
-(defun frame-at (x y)
-  "Return frame containing pixel position X, Y."
-  (cl-loop for frame in (frame-list-z-order)
-           as (x0 y0 x1 y1) = (frame-edges frame)
-           when (and (<= x0 x (1- x1)) (<= y0 y (1- y1)))
-           return frame))
-
 (declare-function x-list-fonts "xfaces.c"
                   (pattern &optional face frame maximum width))
 
index ccb585ce63170cfc3a093464b348c7e0719595bc..19d688e4d1e35389b61424da6a7a15bf5e5f7e42 100644 (file)
@@ -298,7 +298,7 @@ which is the \"1006\" extension implemented in Xterm >= 277."
              ;; FIXME: The test for running in batch mode is here solely
              ;; for the sake of xt-mouse-tests where the only frame is
              ;; the initial frame.
-             (frame (unless noninteractive (frame-at x y)))
+             (frame (unless noninteractive (tty-frame-at x y)))
              ;;(_ (message (format "*** %S" frame)))
              (frame-pos (frame-position frame))
              ;;(_ (message (format "*** %S" frame-pos)))
index 368e20803e11e7f2fb19de46d87f9b4d1cd26fa0..10380eba4b90d05735d85f91719bc3a67ed94ea4 100644 (file)
@@ -141,6 +141,7 @@ static int max_frame_cols;
 struct tty_display_info *gpm_tty = NULL;
 
 /* Last recorded mouse coordinates.  */
+static Lisp_Object last_mouse_frame;
 static int last_mouse_x, last_mouse_y;
 #endif /* HAVE_GPM */
 
@@ -2593,6 +2594,35 @@ tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *row,
 
 #endif
 
+static Lisp_Object
+tty_frame_at (int x, int y)
+{
+  for (Lisp_Object frames = Ftty_frame_list_z_order (Qnil); frames != Qnil;
+       frames = Fcdr (frames))
+    {
+      Lisp_Object frame = Fcar (frames);
+      struct frame *f = XFRAME (frame);
+
+      if (f->left_pos <= x && x < f->left_pos + f->pixel_width &&
+         f->top_pos <= y && y < f->top_pos + f->pixel_height)
+       return frame;
+    }
+
+  return Qnil;
+}
+
+DEFUN ("tty-frame-at", Ftty_frame_at, Stty_frame_at,
+       2, 2, 0,
+       doc: /* Return tty frame containing pixel position X, Y.  */)
+  (Lisp_Object x, Lisp_Object y)
+{
+  if (! FIXNUMP (x) || ! FIXNUMP (y))
+    /* Coordinates this big can not correspond to any frame.  */
+    return Qnil;
+
+  return tty_frame_at (XFIXNUM (x), XFIXNUM (y));
+}
+
 #ifdef HAVE_GPM
 
 void
@@ -2638,7 +2668,12 @@ term_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
                     enum scroll_bar_part *part, Lisp_Object *x,
                     Lisp_Object *y, Time *timeptr)
 {
-  *fp = SELECTED_FRAME ();
+  /* If we've gotten no GPM mouse events yet, last_mouse_frame won't be
+     set.  Perhaps `gpm-mouse-mode' was never active.  */
+  if (! FRAMEP (last_mouse_frame))
+    return;
+
+  *fp = XFRAME (last_mouse_frame);
   (*fp)->mouse_moved = 0;
 
   *bar_window = Qnil;
@@ -2713,9 +2748,14 @@ term_mouse_click (struct input_event *result, Gpm_Event *event,
 }
 
 int
-handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event)
+handle_one_term_event (struct tty_display_info *tty, const Gpm_Event *event_in)
 {
-  struct frame *f = XFRAME (tty->top_frame);
+  Lisp_Object frame = tty_frame_at (event_in->x, event_in->y);
+  struct frame *f = decode_live_frame (frame);
+  Gpm_Event event = *event_in;
+  event.x -= f->left_pos;
+  event.y -= f->top_pos;
+
   struct input_event ie;
   int count = 0;
 
@@ -2723,30 +2763,34 @@ handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event)
   ie.kind = NO_EVENT;
   ie.arg = Qnil;
 
-  if (event->type & (GPM_MOVE | GPM_DRAG))
+  if (event.type & (GPM_MOVE | GPM_DRAG))
     {
-      Gpm_DrawPointer (event->x, event->y, fileno (tty->output));
+      /* The pointer must be drawn using screen coordinates (x,y), not
+        frame coordinates.  Use event_in which has an unmodified event
+        directly from GPM.  */
+      Gpm_DrawPointer (event_in->x, event_in->y, fileno (tty->output));
 
       /* Has the mouse moved off the glyph it was on at the last
          sighting?  */
-      if (event->x != last_mouse_x || event->y != last_mouse_y)
+      if (event.x != last_mouse_x || event.y != last_mouse_y)
         {
-          /* FIXME: These three lines can not be moved into
+          /* FIXME: These four lines can not be moved into
              update_mouse_position unless xterm-mouse gets updated to
              generate mouse events via C code.  See
              https://lists.gnu.org/archive/html/emacs-devel/2020-11/msg00163.html */
-          last_mouse_x = event->x;
-          last_mouse_y = event->y;
+          last_mouse_frame = frame;
+          last_mouse_x = event.x;
+          last_mouse_y = event.y;
           f->mouse_moved = 1;
 
-          count += update_mouse_position (f, event->x, event->y);
+          count += update_mouse_position (f, event.x, event.y);
         }
     }
   else
     {
       f->mouse_moved = 0;
-      term_mouse_click (&ie, event, f);
-      ie.arg = tty_handle_tab_bar_click (f, event->x, event->y,
+      term_mouse_click (&ie, &event, f);
+      ie.arg = tty_handle_tab_bar_click (f, event.x, event.y,
                                         (ie.modifiers & down_modifier) != 0, &ie);
       kbd_buffer_store_event (&ie);
       count++;
@@ -4967,9 +5011,11 @@ trigger redisplay.  */);
   defsubr (&Stty__set_output_buffer_size);
   defsubr (&Stty__output_buffer_size);
 #endif /* !HAVE_ANDROID */
+  defsubr (&Stty_frame_at);
 #ifdef HAVE_GPM
   defsubr (&Sgpm_mouse_start);
   defsubr (&Sgpm_mouse_stop);
+  staticpro (&last_mouse_frame);
 #endif /* HAVE_GPM */
 
   defsubr (&Stty_frame_geometry);
index b32804a57b3fa6fe133061a6c559ed93891c8804..0795148f1af346cae5c259e5ca7c0d2fc946ebf8 100644 (file)
@@ -458,7 +458,7 @@ enum {
 
 #ifdef HAVE_GPM
 #include <gpm.h>
-extern int handle_one_term_event (struct tty_display_info *, Gpm_Event *);
+extern int handle_one_term_event (struct tty_display_info *, const Gpm_Event *);
 extern void term_mouse_moveto (int, int);
 
 /* The device for which we have enabled gpm support.  */