[Top][All Lists]
[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)
- Patch for Emacs X focus issue, Jan D., 2002/06/23
- Re: Patch for Emacs X focus issue, Stefan Monnier, 2002/06/23
- Re: Patch for Emacs X focus issue, Jan D., 2002/06/23
- Re: Patch for Emacs X focus issue, Richard Stallman, 2002/06/24
- Re: Patch for Emacs X focus issue, Jan D., 2002/06/24
- Re: Patch for Emacs X focus issue, David, 2002/06/25
- Re: Patch for Emacs X focus issue, Richard Stallman, 2002/06/25
- Re: Patch for Emacs X focus issue,
Jan D. <=
- Re: Patch for Emacs X focus issue, Richard Stallman, 2002/06/28
- Re: Patch for Emacs X focus issue, Jan D., 2002/06/28