all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Stefan Monnier <monnier@iro.umontreal.ca>
To: Jared Finder <jared@finder.org>
Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org
Subject: Re: mouse-face and help echo support for xterm mouse
Date: Wed, 04 Nov 2020 13:47:29 -0500	[thread overview]
Message-ID: <jwvk0v1ngcc.fsf-monnier+emacs@gnu.org> (raw)
In-Reply-To: <5928a03c79bcf0afee270de1df4d9fa5@finder.org> (Jared Finder's message of "Wed, 04 Nov 2020 09:54:11 -0800")

>> - done:
>> -  if (ie.kind != NO_EVENT)
>> +  if (ie.kind != NO_EVENT) /* FIXME: We retest the previous if's
>> condition!  */
>>      {
>> +      /* FIXME: `hold_quit` could already hold a previous event,
>> +         so it risks crushing that previous event.
>> +         What am I missing?  */
>>        kbd_buffer_store_event_hold (&ie, hold_quit);
>
> This is the meat of the refactor.
>
> Given the current code hold_quit will never hold a previous
> event. tty_read_avail_input initializes hold_quit right before calling
> handle_one_term_event and and sets kind to NO_EVENT.  This is the first and
> only time in this function hold_quit is passed to any other function.

The way I read it:

      EVENT_INIT (gpm_hold_quit);
      gpm_hold_quit.kind = NO_EVENT;
      [...]
      while (gpm = Gpm_GetEvent (&event), gpm == 1) {
	  nread += handle_one_term_event (tty, &event, &gpm_hold_quit);
      }

`gpm_hold_quit->kind` could hold a different value from `NO_EVENT` on the
second iteration (and subsequent ones) of the loop.

> Because it is the first time passed, we can safely deduce that
>  hold_quit->kind will still be NO_EVENT *unless* a previous loop iteration
> changed it.

That's right.

> Because it is the only time passed, we can safely deduce that
>  hold_quit->kind can only changed in a previous loop iteration by this
>  function storing a quit event.  However, this can not happen.  hold_quit
>  would get set by kbd_buffer_store_buffered_event which
>  kbd_buffer_store_event_hold calls.  To get set, the following must all be
> true:
>
> 1. An event of kind ASCII_KEYSTROKE_EVENT must be processed.
> 2. And that event's character code must be quit_char.
> 3. And that event must be on the current frame's KBOARD (not quite sure what
>   this means).
>
> However, 1 will never be true as the only events that ever reach this point
> are of kind GPM_CLICK_EVENT, as deduced from the above asserts.

Oh, I see, indeed.

So we have the following:

    if (event->type & (GPM_MOVE | GPM_DRAG))
      {
        [...]
        eassert (ie.kind == NO_EVENT);
      }
    else
      {
        [...]
        eassert (ie.kind == GPM_CLICK_EVENT);
      }
    
    if (ie.kind != NO_EVENT) /* FIXME: We retest the previous if's condition!  */
      {
        kbd_buffer_store_event_hold (&ie, hold_quit);
        count++;
      }

where we can move the second `if` into the first (according to the FIXME)

    if (event->type & (GPM_MOVE | GPM_DRAG))
      {
        [...]
        eassert (ie.kind == NO_EVENT);
      }
    else
      {
        [...]
        eassert (ie.kind == GPM_CLICK_EVENT);
        kbd_buffer_store_event_hold (&ie, hold_quit);
        count++;
      }

and then we know that `hold_quit` starts at NO_EVENT and can only be
changed via this call to `kbd_buffer_store_event_hold`, but this call
will never change it because `ie.kind == GPM_CLICK_EVENT` and
kbd_buffer_store_event_hold would only ever touch it if the kind was
ASCII_KEYSTROKE_EVENT, so we know that `hold_quit->kind == NO_EVENT`
always holds and we can drop it.

The code is now (with added context):

    if (event->type & (GPM_MOVE | GPM_DRAG))
      {
        [...]
        eassert (ie.kind == NO_EVENT);
      }
    else
      {
        [...]
        eassert (ie.kind == GPM_CLICK_EVENT);
        kbd_buffer_store_event (&ie);
        count++;
      }
    
    if (do_help
        /* FIXME: `hold_quit` is never NULL?!  */
        && !(hold_quit && hold_quit->kind != NO_EVENT))
      { ... }

and the last if's condition can now be simplified:

    bool do_help = false;
    [...]
    if (event->type & (GPM_MOVE | GPM_DRAG))
      {
        [...]
        if (!NILP (help_echo_string)
            || !NILP (previous_help_echo_string))
          do_help = true;

        eassert (ie.kind == NO_EVENT);
      }
    else
      {
        [...]
        eassert (ie.kind == GPM_CLICK_EVENT);
        kbd_buffer_store_event (&ie);
        count++;
      }
    
    if (do_help)
      { ... }

and now we can again fold the second move into the tail of the first:

    bool do_help = false;
    [...]
    if (event->type & (GPM_MOVE | GPM_DRAG))
      {
        [...]
        if (!NILP (help_echo_string)
            || !NILP (previous_help_echo_string))
          do_help = true;

        eassert (ie.kind == NO_EVENT);
        if (do_help)
          { ... }
      }
    else
      {
        [...]
        eassert (ie.kind == GPM_CLICK_EVENT);
        kbd_buffer_store_event (&ie);
        count++;
      }
    
and get rid of `do_help` altogether.

    [...]
    if (event->type & (GPM_MOVE | GPM_DRAG))
      {
        [...]
        if (!NILP (help_echo_string)
            || !NILP (previous_help_echo_string))
          { ... }
      }
    else
      {
        [...]
        eassert (ie.kind == GPM_CLICK_EVENT);
        kbd_buffer_store_event (&ie);
        count++;
      }
    
So, I installed the patch below.


        Stefan


diff --git a/src/keyboard.c b/src/keyboard.c
index 2e0143379a..49a0a8bd23 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -7005,12 +7005,8 @@ tty_read_avail_input (struct terminal *terminal,
   if (gpm_tty == tty)
   {
       Gpm_Event event;
-      struct input_event gpm_hold_quit;
       int gpm, fd = gpm_fd;
 
-      EVENT_INIT (gpm_hold_quit);
-      gpm_hold_quit.kind = NO_EVENT;
-
       /* gpm==1 if event received.
          gpm==0 if the GPM daemon has closed the connection, in which case
                 Gpm_GetEvent closes gpm_fd and clears it to -1, which is why
@@ -7018,13 +7014,11 @@ tty_read_avail_input (struct terminal *terminal,
 		select masks.
          gpm==-1 if a protocol error or EWOULDBLOCK; the latter is normal.  */
       while (gpm = Gpm_GetEvent (&event), gpm == 1) {
-	  nread += handle_one_term_event (tty, &event, &gpm_hold_quit);
+	  nread += handle_one_term_event (tty, &event);
       }
       if (gpm == 0)
 	/* Presumably the GPM daemon has closed the connection.  */
 	close_gpm (fd);
-      if (gpm_hold_quit.kind != NO_EVENT)
-	  kbd_buffer_store_event (&gpm_hold_quit);
       if (nread)
 	  return nread;
   }
diff --git a/src/term.c b/src/term.c
index ff1aabfed2..3a13da165e 100644
--- a/src/term.c
+++ b/src/term.c
@@ -2550,67 +2550,63 @@ term_mouse_click (struct input_event *result, Gpm_Event *event,
 }
 
 int
-handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event,
-		       struct input_event *hold_quit)
+handle_one_term_event (struct tty_display_info *tty, Gpm_Event *event)
 {
   struct frame *f = XFRAME (tty->top_frame);
   struct input_event ie;
-  bool do_help = 0;
   int count = 0;
 
   EVENT_INIT (ie);
   ie.kind = NO_EVENT;
   ie.arg = Qnil;
 
-  if (event->type & (GPM_MOVE | GPM_DRAG)) {
-    previous_help_echo_string = help_echo_string;
-    help_echo_string = Qnil;
+  if (event->type & (GPM_MOVE | GPM_DRAG))
+    {
+      previous_help_echo_string = help_echo_string;
+      help_echo_string = Qnil;
 
-    Gpm_DrawPointer (event->x, event->y, fileno (tty->output));
+      Gpm_DrawPointer (event->x, event->y, fileno (tty->output));
 
-    if (!term_mouse_movement (f, event))
-      help_echo_string = previous_help_echo_string;
+      if (!term_mouse_movement (f, event))
+        help_echo_string = previous_help_echo_string;
 
-    /* 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;
+      /* 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))
+	{
+	  Lisp_Object frame;
 
-    goto done;
-  }
-  else {
-    f->mouse_moved = 0;
-    term_mouse_click (&ie, event, f);
-    if (tty_handle_tab_bar_click (f, event->x, event->y,
-                                 (ie.modifiers & down_modifier) != 0, &ie))
-      {
-       /* tty_handle_tab_bar_click stores 2 events in the event
-          queue, so we are done here.  */
-       count += 2;
-       return count;
-      }
-  }
+	  if (f)
+	    XSETFRAME (frame, f);
+	  else
+	    frame = Qnil;
 
- done:
-  if (ie.kind != NO_EVENT)
-    {
-      kbd_buffer_store_event_hold (&ie, hold_quit);
-      count++;
+	  gen_help_event (help_echo_string, frame, help_echo_window,
+		          help_echo_object, help_echo_pos);
+	  count++;
+	}
     }
-
-  if (do_help
-      && !(hold_quit && hold_quit->kind != NO_EVENT))
+  else
     {
-      Lisp_Object frame;
-
-      if (f)
-	XSETFRAME (frame, f);
-      else
-	frame = Qnil;
-
-      gen_help_event (help_echo_string, frame, help_echo_window,
-		      help_echo_object, help_echo_pos);
+      f->mouse_moved = 0;
+      term_mouse_click (&ie, event, f);
+      /* eassert (ie.kind == GPM_CLICK_EVENT); */
+      if (tty_handle_tab_bar_click (f, event->x, event->y,
+                                    (ie.modifiers & down_modifier) != 0, &ie))
+        {
+          /* eassert (ie.kind == GPM_CLICK_EVENT
+           *          || ie.kind == TAB_BAR_EVENT); */
+          /* tty_handle_tab_bar_click stores 2 events in the event
+             queue, so we are done here.  */
+          /* FIXME: Actually, `tty_handle_tab_bar_click` returns true
+             without storing any events, when
+             (ie.modifiers & down_modifier) != 0  */
+          count += 2;
+          return count;
+        }
+      /* eassert (ie.kind == GPM_CLICK_EVENT); */
+      kbd_buffer_store_event (&ie);
       count++;
     }
 
diff --git a/src/termhooks.h b/src/termhooks.h
index d18b750c3a..6ab06ceff9 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -370,7 +370,7 @@ #define EVENT_INIT(event) memset (&(event), 0, sizeof (struct input_event))
 
 #ifdef HAVE_GPM
 #include <gpm.h>
-extern int handle_one_term_event (struct tty_display_info *, Gpm_Event *, struct input_event *);
+extern int handle_one_term_event (struct tty_display_info *, Gpm_Event *);
 #ifndef HAVE_WINDOW_SYSTEM
 extern void term_mouse_moveto (int, int);
 #endif




  reply	other threads:[~2020-11-04 18:47 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-01  5:46 mouse-face and help echo support for xterm mouse Jared Finder via Emacs development discussions.
2020-11-01 13:39 ` Stefan Monnier
2020-11-01 15:56   ` Jared Finder via Emacs development discussions.
2020-11-04  6:54     ` Jared Finder via Emacs development discussions.
2020-11-04 14:13       ` Stefan Monnier
2020-11-04 15:46         ` Eli Zaretskii
2020-11-04 15:56           ` Stefan Monnier
2020-11-04 17:54             ` Jared Finder via Emacs development discussions.
2020-11-04 18:47               ` Stefan Monnier [this message]
2020-11-04 18:51                 ` Eli Zaretskii
2020-11-04 19:05                   ` Stefan Monnier
2020-11-04 19:10                     ` Jared Finder via Emacs development discussions.
2020-11-04 15:19       ` Eli Zaretskii
2020-11-05  8:15   ` Jared Finder via Emacs development discussions.
2020-11-05 14:45     ` Stefan Monnier
2020-11-05 19:58       ` Jared Finder via Emacs development discussions.
2020-11-05 20:18         ` Stefan Monnier
2020-11-06  5:23           ` Jared Finder via Emacs development discussions.
2020-11-06  6:00             ` Eli Zaretskii
2020-11-06  6:46               ` Jared Finder via Emacs development discussions.
2020-11-06  7:39                 ` Eli Zaretskii
2020-11-07  1:22                   ` Jared Finder via Emacs development discussions.
2020-11-14 12:38                     ` Eli Zaretskii
2020-11-14 12:35                 ` Eli Zaretskii

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=jwvk0v1ngcc.fsf-monnier+emacs@gnu.org \
    --to=monnier@iro.umontreal.ca \
    --cc=eliz@gnu.org \
    --cc=emacs-devel@gnu.org \
    --cc=jared@finder.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.