#include "events-mod.h"
+void enqueue_focus_event (Widget wants_it, Lisp_Object frame, int in_p);
static void handle_focus_event_1 (struct frame *f, int in_p);
+static void handle_focus_event_2 (Window w, struct frame *f, int in_p);
static struct event_stream *Xt_event_stream;
int x_allow_sendevents;
#ifdef DEBUG_XEMACS
-int debug_x_events;
+Fixnum debug_x_events;
#endif
static int process_events_occurred;
static int tty_events_occurred;
+static Widget widget_with_focus;
/* Mask of bits indicating the descriptors that we wait for input on */
extern SELECT_TYPE input_wait_mask, process_only_mask, tty_only_mask;
{
extern Lisp_Object Vcurrent_global_map;
extern Lisp_Object Qascii_character;
- Fput (symbol, Qascii_character, character);
- if (NILP (Flookup_key (Vcurrent_global_map, symbol, Qnil)))
- Fdefine_key (Vcurrent_global_map, symbol, Qself_insert_command);
+ if (NILP (Flookup_key (Vcurrent_global_map, symbol, Qnil)))
+ {
+ Fput (symbol, Qascii_character, character);
+ Fdefine_key (Vcurrent_global_map, symbol, Qself_insert_command);
+ }
}
}
static void
handle_focus_event_1 (struct frame *f, int in_p)
{
+ handle_focus_event_2 (XtWindow (FRAME_X_TEXT_WIDGET (f)), f, in_p);
+}
+
+static void
+handle_focus_event_2 (Window win, struct frame *f, int in_p)
+{
+ /* Although this treats focus differently for all widgets (including
+ the frame) it seems to work ok. */
+ Widget needs_it = XtWindowToWidget (FRAME_X_DISPLAY (f), win);
+
#if XtSpecificationRelease > 5
- Widget focus_widget = XtGetKeyboardFocusWidget (FRAME_X_TEXT_WIDGET (f));
+ widget_with_focus = XtGetKeyboardFocusWidget (FRAME_X_TEXT_WIDGET (f));
#endif
#ifdef HAVE_XIM
XIM_focus_event (f, in_p);
#endif /* HAVE_XIM */
+
/* On focus change, clear all memory of sticky modifiers
to avoid non-intuitive behavior. */
clear_sticky_modifiers (XDEVICE (FRAME_DEVICE (f)));
click in the frame. Why is this? */
if (in_p
#if XtSpecificationRelease > 5
- && FRAME_X_TEXT_WIDGET (f) != focus_widget
+ && needs_it != widget_with_focus
#endif
)
{
- lw_set_keyboard_focus (FRAME_X_SHELL_WIDGET (f),
- FRAME_X_TEXT_WIDGET (f));
+ lw_set_keyboard_focus (FRAME_X_SHELL_WIDGET (f), needs_it);
}
+
+ /* If we are focusing on a native widget then record and exit. */
+ if (needs_it != FRAME_X_TEXT_WIDGET (f)) {
+ widget_with_focus = needs_it;
+ return;
+ }
+
+ /* We have the focus now. See comment in
+ emacs_Xt_handle_widget_losing_focus (). */
+ if (in_p)
+ widget_with_focus = NULL;
+
/* do the generic event-stream stuff. */
{
Lisp_Object frm;
}
}
+/* Create a synthetic X focus event. */
+void
+enqueue_focus_event (Widget wants_it, Lisp_Object frame, int in_p)
+{
+ Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
+ Lisp_Event *ev = XEVENT (emacs_event);
+ XEvent *x_event = &ev->event.magic.underlying_x_event;
+
+ x_event->type = in_p ? FocusIn : FocusOut;
+ x_event->xfocus.window = XtWindow (wants_it);
+
+ ev->channel = frame;
+ ev->event_type = magic_event;
+
+ enqueue_Xt_dispatch_event (emacs_event);
+}
+
+/* The idea here is that when a widget glyph gets unmapped we don't
+ want the focus to stay with it if it has focus - because it may
+ well just get deleted next and then we have lost the focus until the
+ user does something. So handle_focus_event_1 records the widget
+ with keyboard focus when FocusOut is processed, and then, when a
+ widget gets unmapped, it calls this function to restore focus if
+ appropriate. */
+void emacs_Xt_handle_widget_losing_focus (struct frame* f, Widget losing_widget);
+void
+emacs_Xt_handle_widget_losing_focus (struct frame* f, Widget losing_widget)
+{
+ if (losing_widget == widget_with_focus)
+ {
+ handle_focus_event_1 (f, 1);
+ }
+}
+
/* This is called from the external-widget code */
void emacs_Xt_handle_focus_event (XEvent *event);
}
}
+/* #### I'm struggling to understand how the X event loop really works.
+ Here is the problem:
+
+ When widgets get mapped / changed etc the actual display updates
+ are done asynchronously via X events being processed - this
+ normally happens when XtAppProcessEvent() gets called. However, if
+ we are executing lisp code or even doing redisplay we won't
+ necessarily process X events for a very long time. This has the
+ effect of widgets only getting updated when XEmacs only goes into
+ idle, or some other event causes processing of the X event queue.
+
+ XtAppProcessEvent can get called from the following places:
+
+ emacs_Xt_next_event () - this is normal event processing, almost
+ any non-X event will take precedence and this means that we
+ cannot rely on it to do the right thing at the right time for
+ widget display.
+
+ drain_X_queue () - this happens when SIGIO gets tripped,
+ processing the event queue allows C-g to be checked for. It gets
+ called from emacs_Xt_event_pending_p ().
+
+ In order to solve this I have tried introducing a list primitive -
+ dispatch-non-command-events - which forces processing of X events
+ related to display. Unfortunately this has a number of problems,
+ one is that it is possible for event_stream_event_pending_p to
+ block for ever if there isn't actually an event. I guess this can
+ happen if we drop the synthetic event for reason. It also relies on
+ SIGIO processing which makes things rather fragile.
+
+ People have seen behaviour whereby XEmacs blocks until you move the
+ mouse. This seems to indicate that dispatch-non-command-events is
+ blocking. It may be that in a SIGIO world forcing SIGIO processing
+ does the wrong thing.
+*/
static void
emacs_Xt_force_event_pending (struct frame* f)
{
/* Send the drop message */
XSendEvent(dpy, XtWindow (FRAME_X_SHELL_WIDGET (f)),
True, NoEventMask, &event);
- /* Force event pending to check the X queue. */
- quit_check_signal_tick_count++;
+ /* We rely on SIGIO and friends to realise we have generated an
+ event. */
}
static void
if (FRAME_X_EXTERNAL_WINDOW_P (f))
break;
#endif
- handle_focus_event_1 (f, event->type == FocusIn);
+ handle_focus_event_2 (event->xfocus.window, f, event->type == FocusIn);
break;
case ClientMessage:
static void
drain_X_queue (void)
{
+ Lisp_Object devcons, concons;
+ CONSOLE_LOOP (concons)
+ {
+ struct console *con = XCONSOLE (XCAR (concons));
+ if (!con->input_enabled)
+ continue;
+
+ /* sjt sez: Have you tried the loop over devices with XtAppPending(),
+ not XEventsQueued()?
+ Ben Sigelman sez: No.
+ sjt sez: I'm guessing that the reason that your patch "works" is this:
+
+ + struct device* d;
+ + Display* display;
+ + d = XDEVICE (XCAR (devcons));
+ + if (DEVICE_X_P (d) && DEVICE_X_DISPLAY (d)) {
+
+ Ie, if the device goes down, XEmacs detects that and deletes it.
+ Then the if() fails (DEVICE_X_DISPLAY(d) is NULL), and we don't go
+ into the Xlib-of-no-return. If you know different, I'd like to hear
+ about it. ;-)
+
+ These ideas haven't been tested; the code below works for Ben.
+ */
+ CONSOLE_DEVICE_LOOP (devcons, con)
+ {
+ struct device* d;
+ Display* display;
+ d = XDEVICE (XCAR (devcons));
+ if (DEVICE_X_P (d) && DEVICE_X_DISPLAY (d)) {
+ display = DEVICE_X_DISPLAY (d);
+ while (XEventsQueued (display, QueuedAfterReading))
+ XtAppProcessEvent (Xt_app_con, XtIMXEvent);
+ }
+ }
+ }
+ /* This is the old code, before Ben Sigelman's patch. */
+ /*
while (XtAppPending (Xt_app_con) & XtIMXEvent)
XtAppProcessEvent (Xt_app_con, XtIMXEvent);
+ */
}
static int
/* quit_check_signal_tick_count is volatile so try to avoid race conditions
by using a temporary variable */
tick_count_val = quit_check_signal_tick_count;
- if (last_quit_check_signal_tick_count != tick_count_val)
+ if (last_quit_check_signal_tick_count != tick_count_val
+#if !defined (SIGIO) || defined (CYGWIN)
+ || (XtIMXEvent & XtAppPending (Xt_app_con))
+#endif
+ )
{
last_quit_check_signal_tick_count = tick_count_val;
dispatch_event_queue = Qnil;
staticpro (&dispatch_event_queue);
dispatch_event_queue_tail = Qnil;
- pdump_wire (&dispatch_event_queue_tail);
+ dump_add_root_object (&dispatch_event_queue_tail);
DEFVAR_BOOL ("x-allow-sendevents", &x_allow_sendevents /*
*Non-nil means to allow synthetic events. Nil means they are ignored.