unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Patch for Emacs X focus issue
@ 2002-06-23 19:16 Jan D.
  2002-06-23 19:47 ` Stefan Monnier
  0 siblings, 1 reply; 10+ messages in thread
From: Jan D. @ 2002-06-23 19:16 UTC (permalink / raw)


Hello.

I've made a patch for the issues with focus under X.  For example,
Emacs does not detect focus when no window manager is running, and
it can get out of sync even with a window manager running.

Richard Stallman mailed me a description of how this could be done,
but I could not make it work in all situations.  The situation without
any window manager was not handeled correctly.

So, since xterm always seemed to get things right (I used that as
a reference when testing), I looked in that code instead and adopted
that strategy for Emacs.

Both ways share the same general strategy but differs in details.
I haven't managed to get Emacs out of sync with respect with focus
with the xterm strategy.  However, there are many ways to configure
Emacs and window managers, it is hard to cover all cases.

The patch is attached below.  Please comment, and if it is OK, I will
commit it into CVS.

Thanks,

	Jan D.

Index: src/keyboard.c
*** src/keyboard.c.~1.683.~	2002-06-22 16:17:17.000000000 +0200
--- src/keyboard.c	2002-06-23 19:21:07.000000000 +0200
***************
*** 3259,3285 ****
    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
    if (!NILP (do_mouse_tracking) && some_mouse_moved ())
      return 1;
--- 3259,3266 ----
Index: src/xterm.c
*** src/xterm.c.~1.736.~	2002-06-15 21:57:57.000000000 +0200
--- src/xterm.c	2002-06-23 20:37:58.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_HAVEIT))
+         nr_events = x_focus_changed (event->type == EnterNotify ?
+                                      FocusIn : FocusOut,
+                                      FOCUS_INWINDOW,
+                                      dpyinfo,
+                                      frame,
+                                      bufp,
+                                      numchars);
+       break;
+ 
+     case FocusIn:
+     case FocusOut:
+       nr_events = x_focus_changed (event->type,
+                                    event->xfocus.detail == NotifyPointer ?
+                                    FOCUS_INWINDOW : FOCUS_HAVEIT,
+                                    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,10888 ----
  	      goto OTHER;
  #endif
  
  	    case EnterNotify:
                {
+                 int n;
+ 
+                 if ((n = x_detect_focus_change (dpyinfo,
+                                                 &event,
+                                                 bufp,
+                                                 numchars)) > 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)
  		{
--- 10909,10941 ----
                }
            
  	    case FocusIn:
                {
!                 int n;
  
!                 if ((n = x_detect_focus_change (dpyinfo,
!                                                 &event,
!                                                 bufp,
!                                                 numchars)) > 0)
                  {
!                   bufp += n, count += n, numchars -= n;
                  }
                }
  
  	      goto OTHER;
  
  	    case LeaveNotify:
+               {
+                 int n;
+ 
+                 if ((n = x_detect_focus_change (dpyinfo,
+                                                 &event,
+                                                 bufp,
+                                                 numchars)) > 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;
  
--- 10963,10983 ----
  		      bufp += n, count += n, numchars -= n;
  		    }
  
  		}
  	      goto OTHER;
  
  	    case FocusOut:
!               {
!                 int n;
  
!                 if ((n = x_detect_focus_change (dpyinfo,
!                                                 &event,
!                                                 bufp,
!                                                 numchars)) > 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-23 19:09:21.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 HAVEIT if we received a FocusIn for this
+      frame, or INWINDOW if we received an EnterNotify.
+      FocusOut and LeaveNotify clears HAVEIT/INWINDOW. */
+   int focus_state;
  };
  
  enum
***************
*** 631,636 ****
--- 636,650 ----
    FULLSCREEN_MOVE_WAIT  = 8,
  };
  
+ enum
+ {
+   /* Values for focus_state, used as bit mask. */
+   FOCUS_NONE     = 0,
+   FOCUS_INWINDOW = 1,
+   FOCUS_HAVEIT   = 2
+ };
+ 
+ 
  /* Return the X window used for displaying data in frame F.  */
  #define FRAME_X_WINDOW(f) ((f)->output_data.x->window_desc)

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Patch for Emacs X focus issue
  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.
  0 siblings, 1 reply; 10+ messages in thread
From: Stefan Monnier @ 2002-06-23 19:47 UTC (permalink / raw)
  Cc: emacs-devel

> The patch is attached below.  Please comment, and if it is OK, I will
> commit it into CVS.

I have no idea about the actual focus handling issue in X, but I'm
surprised by the first hunk in your patch (see below), which seems
unrelated.  What is the reason for it ?


	Stefan


> Index: src/keyboard.c
> *** src/keyboard.c.~1.683.~	2002-06-22 16:17:17.000000000 +0200
> --- src/keyboard.c	2002-06-23 19:21:07.000000000 +0200
> ***************
> *** 3259,3285 ****
>     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
>     if (!NILP (do_mouse_tracking) && some_mouse_moved ())
>       return 1;
> --- 3259,3266 ----

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Patch for Emacs X focus issue
  2002-06-23 19:47 ` Stefan Monnier
@ 2002-06-23 20:08   ` Jan D.
  2002-06-24 19:39     ` Richard Stallman
  0 siblings, 1 reply; 10+ messages in thread
From: Jan D. @ 2002-06-23 20:08 UTC (permalink / raw)
  Cc: emacs-devel

> 
> > The patch is attached below.  Please comment, and if it is OK, I will
> > commit it into CVS.
> 
> I have no idea about the actual focus handling issue in X, but I'm
> surprised by the first hunk in your patch (see below), which seems
> unrelated.  What is the reason for it ?
> 

The code in question ignored FOCUS_IN_EVENT when looking for pending
input.  So when a new frame got focus, the modeline face was not
changed immediately to the "active" looking face.  It took another
event or a timeout for this to happen.  You have to have two or
more frames to see this change in the modeline.

I suspect there where too many FOCUS_IN_EVENT:s generated previously and
that this caused problems.  The patch simply restores the code to what
it is in the RC branch.

	Jan D.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Patch for Emacs X focus issue
  2002-06-23 20:08   ` Jan D.
@ 2002-06-24 19:39     ` Richard Stallman
  2002-06-24 21:14       ` Jan D.
  0 siblings, 1 reply; 10+ messages in thread
From: Richard Stallman @ 2002-06-24 19:39 UTC (permalink / raw)
  Cc: monnier+gnu/emacs, emacs-devel

    The code in question ignored FOCUS_IN_EVENT when looking for pending
    input. 

That was the intention.  There was a bug report that input-pending-p
reported that there was input available, even when it was just a focus
change.  I made this change to fix that.

	    So when a new frame got focus, the modeline face was not
    changed immediately to the "active" looking face.

It is right to fix that bug, but simply removing the change is not
correct.  That would reintroduce the other bug.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Patch for Emacs X focus issue
  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
  0 siblings, 2 replies; 10+ messages in thread
From: Jan D. @ 2002-06-24 21:14 UTC (permalink / raw)
  Cc: emacs-devel, dajo

>     The code in question ignored FOCUS_IN_EVENT when looking for pending
>     input. 
> 
> That was the intention.  There was a bug report that input-pending-p
> reported that there was input available, even when it was just a focus
> change.  I made this change to fix that.
> 
> 	    So when a new frame got focus, the modeline face was not
>     changed immediately to the "active" looking face.
> 
> It is right to fix that bug, but simply removing the change is not
> correct.  That would reintroduce the other bug.

I have considerably reduced the number of FOCUS_IN_EVENTs generated with
this patch.  On the configuration used where the input-pending-p problem
occured (Gnome/sawfish), with a simple test case (make two frames,
open up one menu and close it, first on the second frame, then on the first,
kill emacs) generated 30 FOCUS_IN_EVENTs with the old code.
With this focus patch the number is 6.

It would be great if the original poster of the input-pending-p
problem could retest with this patch to see if the problem remains.
Is that possible? (Cc:ing the reporter of that bug).

I initially solved the "modline face" bug by making two events, one
FOCUS_IN_EVENT followed by an empty HELP_EVENT.  Since this triggers
input-pending-p anyway, I guess it is a bad fix.

A way to fix the "modline face" bug (I noticed now that the cursor also
doesn't start blinking) would be to let only Finput_pending_p ignore
FOCUS_IN_EVENTS.  Is that a way to go?

	Jan D.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Patch for Emacs X focus issue
  2002-06-24 21:14       ` Jan D.
@ 2002-06-25 19:10         ` David
  2002-06-25 23:32         ` Richard Stallman
  1 sibling, 0 replies; 10+ messages in thread
From: David @ 2002-06-25 19:10 UTC (permalink / raw)
  Cc: rms, emacs-devel

> It would be great if the original poster of the input-pending-p
> problem could retest with this patch to see if the problem remains.
> Is that possible? (Cc:ing the reporter of that bug).

I am willing to test if that will help.

dajo

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Patch for Emacs X focus issue
  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.
  1 sibling, 1 reply; 10+ messages in thread
From: Richard Stallman @ 2002-06-25 23:32 UTC (permalink / raw)
  Cc: emacs-devel, dajo

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?

    A way to fix the "modline face" bug (I noticed now that the cursor also
    doesn't start blinking) would be to let only Finput_pending_p ignore
    FOCUS_IN_EVENTS.  Is that a way to go?

It looks like we both had the same idea.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Patch for Emacs X focus issue
  2002-06-25 23:32         ` Richard Stallman
@ 2002-06-26 13:03           ` Jan D.
  2002-06-28 17:39             ` Richard Stallman
  0 siblings, 1 reply; 10+ messages in thread
From: Jan D. @ 2002-06-26 13:03 UTC (permalink / raw)
  Cc: emacs-devel

> 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)

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Patch for Emacs X focus issue
  2002-06-26 13:03           ` Jan D.
@ 2002-06-28 17:39             ` Richard Stallman
  2002-06-28 19:57               ` Jan D.
  0 siblings, 1 reply; 10+ messages in thread
From: Richard Stallman @ 2002-06-28 17:39 UTC (permalink / raw)
  Cc: emacs-devel

It looks good now.  If it seems to work, please install it.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Patch for Emacs X focus issue
  2002-06-28 17:39             ` Richard Stallman
@ 2002-06-28 19:57               ` Jan D.
  0 siblings, 0 replies; 10+ messages in thread
From: Jan D. @ 2002-06-28 19:57 UTC (permalink / raw)
  Cc: emacs-devel

> It looks good now.  If it seems to work, please install it.

I have installed this now.  If anybody out there sees a case where Emacs
fails to detect focus changes correctly, please report it, including the
window manager used.

Thanks,

	Jan D.

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2002-06-28 19:57 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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.
2002-06-28 17:39             ` Richard Stallman
2002-06-28 19:57               ` Jan D.

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).