emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Patch for Emacs X focus issue


From: Jan D.
Subject: Re: Patch for Emacs X focus issue
Date: Wed, 26 Jun 2002 15:03:08 +0200 (CEST)

> 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 via email to

[Prev in Thread] Current Thread [Next in Thread]