emacs-devel
[Top][All Lists]
Advanced

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

Patch for Emacs X focus issue


From: Jan D.
Subject: Patch for Emacs X focus issue
Date: Sun, 23 Jun 2002 21:16:32 +0200 (CEST)

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)
  



reply via email to

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