X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=src%2Fevent-Xt.c;h=04b54d3680f74aa815b3d64df5a91aeec0957935;hb=03e80302fb3953f2d09ee4a82d90b38f245a3c2c;hp=d597719395fe22c0fe362c6c6d506336bd1ea9f5;hpb=59eec5f21669e81977b5b1fe9bf717cab49cf7fb;p=chise%2Fxemacs-chise.git- diff --git a/src/event-Xt.c b/src/event-Xt.c index d597719..04b54d3 100644 --- a/src/event-Xt.c +++ b/src/event-Xt.c @@ -92,6 +92,7 @@ int debug_x_events; 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; @@ -687,20 +688,29 @@ x_handle_sticky_modifiers (XEvent *ev, struct device *d) { /* Not a modifier key */ Bool key_event_p = (type == KeyPress || type == KeyRelease); - if (type == KeyPress && !xd->last_downkey) - xd->last_downkey = keycode; - else if (type == ButtonPress || - (type == KeyPress && xd->last_downkey && - (keycode != xd->last_downkey || - ev->xkey.time != xd->release_time))) + if (type == ButtonPress + || (type == KeyPress + && ((xd->last_downkey + && ((keycode != xd->last_downkey + || ev->xkey.time != xd->release_time))) + || (INTP (Vmodifier_keys_sticky_time) + && ev->xkey.time + > (xd->modifier_release_time + + XINT (Vmodifier_keys_sticky_time)))))) { xd->need_to_add_mask = 0; xd->last_downkey = 0; } + else if (type == KeyPress && !xd->last_downkey) + xd->last_downkey = keycode; + if (type == KeyPress) xd->release_time = 0; if (type == KeyPress || type == ButtonPress) - xd->down_mask = 0; + { + xd->down_mask = 0; + xd->modifier_release_time = 0; + } if (key_event_p) ev->xkey.state |= xd->need_to_add_mask; @@ -722,7 +732,8 @@ x_handle_sticky_modifiers (XEvent *ev, struct device *d) So we assume that if the release and the next press occur at the same time, the key was actually auto- repeated. Under Open-Windows, at least, this works. */ - xd->release_time = key_event_p ? ev->xkey.time : ev->xbutton.time; + xd->modifier_release_time = xd->release_time + = key_event_p ? ev->xkey.time : ev->xbutton.time; } else /* Modifier key pressed */ { @@ -742,6 +753,15 @@ x_handle_sticky_modifiers (XEvent *ev, struct device *d) xd->need_to_add_mask = 0; } + if (xd->modifier_release_time + && INTP (Vmodifier_keys_sticky_time) + && (ev->xkey.time + > xd->modifier_release_time + XINT (Vmodifier_keys_sticky_time))) + { + xd->need_to_add_mask = 0; + xd->down_mask = 0; + } + #define FROB(mask) \ do { \ if (type == KeyPress) \ @@ -767,6 +787,7 @@ do { \ xd->need_to_add_mask |= mask; \ } \ } \ + xd->modifier_release_time = ev->xkey.time; \ } while (0) for (i = 0; i < xd->x_keysym_map_keysyms_per_code; i++) @@ -1330,10 +1351,10 @@ x_event_to_emacs_event (XEvent *x_event, Lisp_Event *emacs_event) Lisp_Object l_dndlist = Qnil, l_item = Qnil; struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; - GCPRO4 (l_type, l_data, l_dndlist, l_item); - if (! frame) return 0; /* not for us */ + + GCPRO4 (l_type, l_data, l_dndlist, l_item); XSETFRAME (emacs_event->channel, frame); emacs_event->event_type = misc_user_event; @@ -1516,11 +1537,12 @@ static void handle_focus_event_1 (struct frame *f, int in_p) { #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))); @@ -1544,13 +1566,19 @@ handle_focus_event_1 (struct frame *f, int in_p) click in the frame. Why is this? */ if (in_p #if XtSpecificationRelease > 5 - && FRAME_X_TEXT_WIDGET (f) != focus_widget + && FRAME_X_TEXT_WIDGET (f) != widget_with_focus #endif ) { lw_set_keyboard_focus (FRAME_X_SHELL_WIDGET (f), FRAME_X_TEXT_WIDGET (f)); } + + /* 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; @@ -1567,6 +1595,23 @@ handle_focus_event_1 (struct frame *f, int in_p) } } +/* 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 andthen 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); @@ -1743,6 +1788,41 @@ handle_client_message (struct frame *f, 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) { @@ -1758,8 +1838,8 @@ 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 @@ -2929,7 +3009,11 @@ emacs_Xt_event_pending_p (int user_p) /* 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; @@ -3206,7 +3290,7 @@ vars_of_event_Xt (void) 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.