unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: "Jan D." <jan.h.d@swipnet.se>
Cc: emacs-devel@gnu.org
Subject: Re: Patch for Emacs X focus issue
Date: Wed, 26 Jun 2002 15:03:08 +0200 (CEST)	[thread overview]
Message-ID: <200206261258.g5QCwcuM001371@stubby.bodenonline.com> (raw)
In-Reply-To: <E17MznB-0008PH-00@fencepost.gnu.org> "from Richard Stallman at Jun 25, 2002 07:32:13 pm"

> I think that the input-pending-p problem needs a real fix.
> These events should be ignored for the sake of input-pending-p
> even if they are not ignored for some other purposes.
> 
> Perhaps there should be two different functions for asking
> whether there is input, one for low-level Emacs purposes
> and one for high-level purposes.  Can you try fixing it that way?
> 

Here's a modified patch, please comment.

	Jan D.


Index: src/keyboard.c
*** src/keyboard.c.~1.683.~	2002-06-22 16:17:17.000000000 +0200
--- src/keyboard.c	2002-06-26 14:56:12.000000000 +0200
***************
*** 672,678 ****
--- 672,680 ----
  
  static int read_avail_input P_ ((int));
  static void get_input_pending P_ ((int *, int));
+ static void get_filtered_input_pending P_ ((int *, int, int));
  static int readable_events P_ ((int));
+ static int readable_filtered_events P_ ((int, int));
  static Lisp_Object read_char_x_menu_prompt P_ ((int, Lisp_Object *,
  						Lisp_Object, int *));
  static Lisp_Object read_char_x_menu_prompt ();
***************
*** 3253,3283 ****
  /* Return true iff there are any events in the queue that read-char
     would return.  If this returns false, a read-char would block.  */
  static int
! readable_events (do_timers_now)
       int do_timers_now;
  {
    if (do_timers_now)
      timer_check (do_timers_now);
  
    /* If the buffer contains only FOCUS_IN_EVENT events,
!      report it as empty.  */
    if (kbd_fetch_ptr != kbd_store_ptr)
      {
        struct input_event *event;
  
        event = ((kbd_fetch_ptr < kbd_buffer + KBD_BUFFER_SIZE)
  	       ? kbd_fetch_ptr
  	       : kbd_buffer);
  
!       while (event->kind == FOCUS_IN_EVENT)
  	{
  	  event++;
  	  if (event == kbd_buffer + KBD_BUFFER_SIZE)
  	    event = kbd_buffer;
  	  if (event == kbd_store_ptr)
! 	    return 0;
  	}
!       return 1;
      }
  
  #ifdef HAVE_MOUSE
--- 3255,3291 ----
  /* Return true iff there are any events in the queue that read-char
     would return.  If this returns false, a read-char would block.  */
  static int
! readable_filtered_events (do_timers_now, filter_events)
       int do_timers_now;
+      int filter_events;
  {
    if (do_timers_now)
      timer_check (do_timers_now);
  
    /* If the buffer contains only FOCUS_IN_EVENT events,
!      and FILTER_EVENTS is nonzero, report it as empty.  */
    if (kbd_fetch_ptr != kbd_store_ptr)
      {
+       int have_live_event = 1;
+ 
+       if (filter_events)
+         {
            struct input_event *event;
            
            event = ((kbd_fetch_ptr < kbd_buffer + KBD_BUFFER_SIZE)
                     ? kbd_fetch_ptr
                     : kbd_buffer);
  
!           while (have_live_event && event->kind == FOCUS_IN_EVENT)
              {
                event++;
                if (event == kbd_buffer + KBD_BUFFER_SIZE)
                  event = kbd_buffer;
                if (event == kbd_store_ptr)
!                 have_live_event = 0;
              }
!         }
!       if (have_live_event) return 1;
      }
  
  #ifdef HAVE_MOUSE
***************
*** 3299,3304 ****
--- 3307,3321 ----
    return 0;
  }
  
+ /* Return true iff there are any events in the queue that read-char
+    would return.  If this returns false, a read-char would block.  */
+ static int
+ readable_events (do_timers_now)
+      int do_timers_now;
+ {
+   return readable_filtered_events (do_timers_now, 0);
+ }
+ 
  /* Set this for debugging, to have a way to get out */
  int stop_character;
  
***************
*** 6144,6158 ****
     but works even if FIONREAD does not exist.
     (In fact, this may actually read some input.)
  
!    If DO_TIMERS_NOW is nonzero, actually run timer events that are ripe.  */
  
  static void
! get_input_pending (addr, do_timers_now)
       int *addr;
       int do_timers_now;
  {
    /* First of all, have we already counted some input?  */
!   *addr = !NILP (Vquit_flag) || readable_events (do_timers_now);
  
    /* If input is being read as it arrives, and we have none, there is none.  */
    if (*addr > 0 || (interrupt_input && ! interrupts_deferred))
--- 6161,6178 ----
     but works even if FIONREAD does not exist.
     (In fact, this may actually read some input.)
  
!    If DO_TIMERS_NOW is nonzero, actually run timer events that are ripe.
!    If FILTER_EVENTS is nonzero, ignore internal events (FOCUS_IN_EVENT). */
  
  static void
! get_filtered_input_pending (addr, do_timers_now, filter_events)
       int *addr;
       int do_timers_now;
+      int filter_events;
  {
    /* First of all, have we already counted some input?  */
!   *addr = (!NILP (Vquit_flag)
!            || readable_filtered_events (do_timers_now, filter_events));
  
    /* If input is being read as it arrives, and we have none, there is none.  */
    if (*addr > 0 || (interrupt_input && ! interrupts_deferred))
***************
*** 6160,6166 ****
  
    /* Try to read some input and see how much we get.  */
    gobble_input (0);
!   *addr = !NILP (Vquit_flag) || readable_events (do_timers_now);
  }
  
  /* Interface to read_avail_input, blocking SIGIO or SIGALRM if necessary.  */
--- 6180,6202 ----
  
    /* Try to read some input and see how much we get.  */
    gobble_input (0);
!   *addr = (!NILP (Vquit_flag)
!            || readable_filtered_events (do_timers_now, filter_events));
! }
! 
! /* Store into *addr a value nonzero if terminal input chars are available.
!    Serves the purpose of ioctl (0, FIONREAD, addr)
!    but works even if FIONREAD does not exist.
!    (In fact, this may actually read some input.)
! 
!    If DO_TIMERS_NOW is nonzero, actually run timer events that are ripe.  */
! 
! static void
! get_input_pending (addr, do_timers_now)
!      int *addr;
!      int do_timers_now;
! {
!   get_filtered_input_pending (addr, do_timers_now, 0);
  }
  
  /* Interface to read_avail_input, blocking SIGIO or SIGALRM if necessary.  */
***************
*** 9563,9569 ****
    if (!NILP (Vunread_command_events) || unread_command_char != -1)
      return (Qt);
  
!   get_input_pending (&input_pending, 1);
    return input_pending > 0 ? Qt : Qnil;
  }
  
--- 9599,9605 ----
    if (!NILP (Vunread_command_events) || unread_command_char != -1)
      return (Qt);
  
!   get_filtered_input_pending (&input_pending, 1, 1);
    return input_pending > 0 ? Qt : Qnil;
  }
  
Index: src/xterm.c
*** src/xterm.c.~1.736.~	2002-06-15 21:57:57.000000000 +0200
--- src/xterm.c	2002-06-24 23:32:07.000000000 +0200
***************
*** 466,471 ****
--- 466,481 ----
  static void frame_highlight P_ ((struct frame *));
  static void frame_unhighlight P_ ((struct frame *));
  static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
+ static int  x_focus_changed P_ ((int,
+                                  int,
+                                  struct x_display_info *,
+                                  struct frame *,
+                                  struct input_event *,
+                                  int));
+ static int  x_detect_focus_change P_ ((struct x_display_info *,
+                                        XEvent *,
+                                        struct input_event *,
+                                        int));
  static void XTframe_rehighlight P_ ((struct frame *));
  static void x_frame_rehighlight P_ ((struct x_display_info *));
  static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
***************
*** 6291,6296 ****
--- 6301,6421 ----
    x_frame_rehighlight (dpyinfo);
  }
  
+ /* Handle FocusIn and FocusOut state changes for FRAME.
+    If FRAME has focus and there exists more than one frame, puts
+    an FOCUS_IN_EVENT into BUFP.
+    Returns number of events inserted into BUFP. */
+ 
+ static int
+ x_focus_changed (type, state, dpyinfo, frame, bufp, numchars)
+      int type;
+      int state;
+      struct x_display_info *dpyinfo;
+      struct frame *frame;
+      struct input_event *bufp;
+      int numchars;
+ {
+   int nr_events = 0;
+ 
+   if (type == FocusIn)
+     {
+       if (dpyinfo->x_focus_event_frame != frame)
+         {
+           x_new_focus_frame (dpyinfo, frame);
+           dpyinfo->x_focus_event_frame = frame;
+       
+           /* Don't stop displaying the initial startup message
+              for a switch-frame event we don't need.  */
+           if (numchars > 0
+               && GC_NILP (Vterminal_frame)
+               && GC_CONSP (Vframe_list)
+               && !GC_NILP (XCDR (Vframe_list)))
+             {
+               bufp->kind = FOCUS_IN_EVENT;
+               XSETFRAME (bufp->frame_or_window, frame);
+               bufp->arg = Qnil;
+               ++bufp;
+               numchars--;
+               ++nr_events;
+             }
+         }
+ 
+       frame->output_data.x->focus_state |= state;
+ 
+ #ifdef HAVE_X_I18N
+       if (FRAME_XIC (frame))
+         XSetICFocus (FRAME_XIC (frame));
+ #endif
+     }
+   else if (type == FocusOut)
+     {
+       frame->output_data.x->focus_state &= ~state;
+       
+       if (dpyinfo->x_focus_event_frame == frame)
+         {
+           dpyinfo->x_focus_event_frame = 0;
+           x_new_focus_frame (dpyinfo, 0);
+         }
+ 
+ #ifdef HAVE_X_I18N
+       if (FRAME_XIC (frame))
+         XUnsetICFocus (FRAME_XIC (frame));
+ #endif
+     }
+ 
+   return nr_events;
+ }
+ 
+ /* The focus may have changed.  Figure out if it is a real focus change,
+    by checking both FocusIn/Out and Enter/LeaveNotify events.
+ 
+    Returns number of events inserted into BUFP. */
+ 
+ static int
+ x_detect_focus_change (dpyinfo, event, bufp, numchars)
+      struct x_display_info *dpyinfo;
+      XEvent *event;
+      struct input_event *bufp;
+      int numchars;
+ {
+   struct frame *frame;
+   int nr_events = 0;
+   
+   frame = x_top_window_to_frame (dpyinfo, event->xany.window);
+   if (! frame) return nr_events;
+   
+   switch (event->type)
+     {
+     case EnterNotify:
+     case LeaveNotify:
+       if (event->xcrossing.detail != NotifyInferior
+           && event->xcrossing.focus
+           && ! (frame->output_data.x->focus_state & FOCUS_EXPLICIT))
+         nr_events = x_focus_changed ((event->type == EnterNotify
+                                       ? FocusIn : FocusOut),
+                                      FOCUS_IMPLICIT,
+                                      dpyinfo,
+                                      frame,
+                                      bufp,
+                                      numchars);
+       break;
+ 
+     case FocusIn:
+     case FocusOut:
+       nr_events = x_focus_changed (event->type,
+                                    (event->xfocus.detail == NotifyPointer
+                                     ? FOCUS_IMPLICIT : FOCUS_EXPLICIT),
+                                    dpyinfo,
+                                    frame,
+                                    bufp,
+                                    numchars);
+       break;
+     }
+ 
+   return nr_events;
+ }
+ 
+ 
  /* Handle an event saying the mouse has moved out of an Emacs frame.  */
  
  void
***************
*** 10746,10760 ****
  	      goto OTHER;
  #endif
  
- 	      /* Here's a possible interpretation of the whole
- 		 FocusIn-EnterNotify FocusOut-LeaveNotify mess.  If
- 		 you get a FocusIn event, you have to get a FocusOut
- 		 event before you relinquish the focus.  If you
- 		 haven't received a FocusIn event, then a mere
- 		 LeaveNotify is enough to free you.  */
- 
  	    case EnterNotify:
  	      {
  		f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
  
  #if 0
--- 10871,10886 ----
  	      goto OTHER;
  #endif
  
  	    case EnterNotify:
                {
+                 int n;
+ 
+                 n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
+                 if (n > 0)
+                 {
+                   bufp += n, count += n, numchars -= n;
+                 }
+               
                  f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
  
  #if 0
***************
*** 10781,10814 ****
  	      }
  
  	    case FocusIn:
- 	      f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
- 	      if (event.xfocus.detail != NotifyPointer)
- 		dpyinfo->x_focus_event_frame = f;
- 	      if (f)
  		{
! 		  x_new_focus_frame (dpyinfo, f);
  
! 		  /* Don't stop displaying the initial startup message
! 		     for a switch-frame event we don't need.  */
! 		  if (GC_NILP (Vterminal_frame)
! 		      && GC_CONSP (Vframe_list)
! 		      && !GC_NILP (XCDR (Vframe_list)))
  		    {
! 		      bufp->kind = FOCUS_IN_EVENT;
! 		      XSETFRAME (bufp->frame_or_window, f);
! 		      bufp->arg = Qnil;
! 		      ++bufp, ++count, --numchars;
  		    }
  		}
  
- #ifdef HAVE_X_I18N
- 	      if (f && FRAME_XIC (f))
- 		XSetICFocus (FRAME_XIC (f));
- #endif
- 
  	      goto OTHER;
  
  	    case LeaveNotify:
  	      f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
  	      if (f)
  		{
--- 10907,10935 ----
                }
            
  	    case FocusIn:
                {
!                 int n;
  
!                 n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
!                 if (n > 0)
                  {
!                   bufp += n, count += n, numchars -= n;
                  }
                }
  
  	      goto OTHER;
  
  	    case LeaveNotify:
+               {
+                 int n;
+ 
+                 n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
+                 if (n > 0)
+                 {
+                   bufp += n, count += n, numchars -= n;
+                 }
+               }
+ 
  	      f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
  	      if (f)
  		{
***************
*** 10836,10867 ****
  		      bufp += n, count += n, numchars -= n;
  		    }
  
- #if 0
- 		  if (event.xcrossing.focus)
- 		    x_mouse_leave (dpyinfo);
- 		  else
- 		    {
- 		      if (f == dpyinfo->x_focus_event_frame)
- 			dpyinfo->x_focus_event_frame = 0;
- 		      if (f == dpyinfo->x_focus_frame)
- 			x_new_focus_frame (dpyinfo, 0);
- 		    }
- #endif
  		}
  	      goto OTHER;
  
  	    case FocusOut:
! 	      f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
! 	      if (event.xfocus.detail != NotifyPointer
! 		  && f == dpyinfo->x_focus_event_frame)
! 		dpyinfo->x_focus_event_frame = 0;
! 	      if (f && f == dpyinfo->x_focus_frame)
! 		x_new_focus_frame (dpyinfo, 0);
  
! #ifdef HAVE_X_I18N
! 	      if (f && FRAME_XIC (f))
! 		XUnsetICFocus (FRAME_XIC (f));
! #endif
  
  	      goto OTHER;
  
--- 10957,10975 ----
  		      bufp += n, count += n, numchars -= n;
  		    }
  
  		}
  	      goto OTHER;
  
  	    case FocusOut:
!               {
!                 int n;
  
!                 n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
!                 if (n > 0)
!                 {
!                   bufp += n, count += n, numchars -= n;
!                 }
!               }
  
  	      goto OTHER;
  
Index: src/xterm.h
*** src/xterm.h.~1.131.~	2002-06-15 21:57:57.000000000 +0200
--- src/xterm.h	2002-06-24 23:26:28.000000000 +0200
***************
*** 618,623 ****
--- 618,628 ----
       these may differ because this does not take into account possible
       menubar.  y_pixels_diff is with menubar height included */
    int y_pixels_outer_diff;
+ 
+   /* Keep track of focus.  May be EXPLICIT if we received a FocusIn for this
+      frame, or IMPLICIT if we received an EnterNotify.
+      FocusOut and LeaveNotify clears EXPLICIT/IMPLICIT. */
+   int focus_state;
  };
  
  enum
***************
*** 631,636 ****
--- 636,654 ----
    FULLSCREEN_MOVE_WAIT  = 8,
  };
  
+ enum
+ {
+   /* Values for focus_state, used as bit mask.
+      EXPLICIT means if we received a FocusIn for the frame and know it has
+      the focus.  IMPLICIT means we recevied an EnterNotify and the frame
+      may have the focus if no window manager is running.
+      FocusOut and LeaveNotify clears EXPLICIT/IMPLICIT. */
+   FOCUS_NONE     = 0,
+   FOCUS_IMPLICIT = 1,
+   FOCUS_EXPLICIT = 2
+ };
+ 
+ 
  /* Return the X window used for displaying data in frame F.  */
  #define FRAME_X_WINDOW(f) ((f)->output_data.x->window_desc)

  reply	other threads:[~2002-06-26 13:03 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-06-23 19:16 Patch for Emacs X focus issue Jan D.
2002-06-23 19:47 ` Stefan Monnier
2002-06-23 20:08   ` Jan D.
2002-06-24 19:39     ` Richard Stallman
2002-06-24 21:14       ` Jan D.
2002-06-25 19:10         ` David
2002-06-25 23:32         ` Richard Stallman
2002-06-26 13:03           ` Jan D. [this message]
2002-06-28 17:39             ` Richard Stallman
2002-06-28 19:57               ` Jan D.

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

  List information: https://www.gnu.org/software/emacs/

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

  git send-email \
    --in-reply-to=200206261258.g5QCwcuM001371@stubby.bodenonline.com \
    --to=jan.h.d@swipnet.se \
    --cc=emacs-devel@gnu.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 public inbox

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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).